mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-30 23:12:13 +03:00
9994 lines
674 KiB
Handlebars
9994 lines
674 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 rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
|
||
<link keeplink="1" 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.1.js"></script>
|
||
<script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0.js"></script>
|
||
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
|
||
<script type="text/javascript" src="scripts/qrcode.min.js"></script>
|
||
<script keeplink="1" type="text/javascript" src="scripts/u2f-api.js"></script>
|
||
<script keeplink="1" type="text/javascript" src="scripts/charts.js"></script>
|
||
<script keeplink="1" type="text/javascript" src="scripts/filesaver.js"></script>
|
||
</head><body id="body" onload="if (typeof(startup) !== 'undefined') startup();" oncontextmenu="handleContextMenu(event)" style="display:none;min-width:495px">{{{StartGeoLocation}}}
|
||
<script keeplink="1" type="text/javascript" src="scripts/ol.js"></script>
|
||
<script keeplink="1" type="text/javascript" src="scripts/ol3-contextmenu.js"></script>
|
||
{{{EndGeoLocation}}}
|
||
<title>{{{title}}}</title>
|
||
|
||
|
||
<!-- right click menu -->
|
||
<div id="contextMenu" class="contextMenu noselect" style="display:none">
|
||
<div id="cxinfo" class="cmtext" onclick="cmaction(1,event)"><b>情報</b></div>
|
||
<div id="cxdesktop" class="cmtext" onclick="cmaction(3,event)">デスクトップ</div>
|
||
<div id="cxterminal" class="cmtext" onclick="cmaction(2,event)">ターミナル</div>
|
||
<div id="cxfiles" class="cmtext" onclick="cmaction(4,event)">ファイル</div>
|
||
<div id="cxevents" class="cmtext" onclick="cmaction(5,event)">イベント</div>
|
||
<div id="cxconsole" class="cmtext" onclick="cmaction(6,event)">コンソール</div>
|
||
<hr id="cxmgroupsplit">
|
||
<div id="cxmdesktop" class="cmtext" onclick="cmaction(7,event)" style="display:none">マルチデスクトップ</div>
|
||
</div>
|
||
<div id="meshContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||
<div id="cxselectall" class="cmtext" onclick="cmmeshaction(1,event)">すべて選択</div>
|
||
<div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2,event)">なしを選択</div>
|
||
<!--
|
||
<hr id="cxmgroupsplit2" style="display:none" />
|
||
<div id="cxmmdesktop" class="cmtext" style="display:none" onclick="cmmeshaction(3,event)">Multi-Desktop</div>
|
||
-->
|
||
</div>
|
||
<div id="termShellContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)"><b>管理シェル</b></div>
|
||
<div id="cxtermps" class="cmtext" onclick="cmtermaction(6,event)">管理者PowerShell</div>
|
||
<div id="cxtermunorm" class="cmtext" onclick="cmtermaction(8,event)">ユーザーシェル</div>
|
||
<div id="cxtermups" class="cmtext" onclick="cmtermaction(9,event)">ユーザーPowerShell</div>
|
||
</div>
|
||
<div id="termShellContextMenuLinux" class="contextMenu noselect" style="display:none;min-width:0px">
|
||
<div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)"><b>ルートシェル</b></div>
|
||
<div id="cxtermps" class="cmtext" onclick="cmtermaction(8,event)">ユーザーシェル</div>
|
||
</div>
|
||
<!--
|
||
<div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
|
||
<div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
|
||
</div>
|
||
-->
|
||
<!-- main page -->
|
||
<div id="container">
|
||
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
|
||
<div id="masthead" class="noselect">
|
||
<div style="float:left">{{{titlehtml}}}</div>
|
||
<div class="title">{{{title1}}}</div>
|
||
<div class="title2">{{{title2}}}</div>
|
||
<div style="float:right">
|
||
<div id="notificationCount" onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="クリックして現在の通知を表示します">0</div>
|
||
</div>
|
||
<p id="logoutControl"><span id="logoutControlSpan" style="color:white"></span><span id="idleTimeoutNotify" style="color:yellow"></span></p>
|
||
</div>
|
||
<div id="page_leftbar">
|
||
<div style="height:16px"></div>
|
||
<div id="LeftMenuMyDevices" tabindex="0" class="lbbutton lbbuttonsel" title="私のデバイス" onclick="go(1,event)" onkeypress="if (event.key=='Enter') { go(1); }">
|
||
<div class="lb2"></div>
|
||
</div>
|
||
<div id="LeftMenuMyAccount" tabindex="0" class="lbbutton" title="マイアカウント" onclick="go(2,event)" onkeypress="if (event.key=='Enter') { go(2); }">
|
||
<div class="lb1"></div>
|
||
</div>
|
||
<div id="LeftMenuMyEvents" tabindex="0" class="lbbutton" title="私のイベント" onclick="go(3,event)" onkeypress="if (event.key=='Enter') { go(3); }">
|
||
<div class="lb3"></div>
|
||
</div>
|
||
<div id="LeftMenuMyFiles" tabindex="0" class="lbbutton" style="display:none" title="私のファイル" onclick="go(5,event)" onkeypress="if (event.key=='Enter') { go(5); }">
|
||
<div class="lb4"></div>
|
||
</div>
|
||
<div id="LeftMenuMyUsers" tabindex="0" class="lbbutton" style="display:none" title="私のユーザー" onclick="go(4,event)" onkeypress="if (event.key=='Enter') { go(4); }">
|
||
<div class="lb5"></div>
|
||
</div>
|
||
<div id="LeftMenuMyServer" tabindex="0" class="lbbutton" style="display:none" title="私のサーバー" onclick="go(6,event)" onkeypress="if (event.key=='Enter') { go(6); }">
|
||
<div class="lb6"></div>
|
||
</div>
|
||
</div>
|
||
<div id="topbar" class="noselect">
|
||
<div>
|
||
<div style="position:relative">
|
||
<span id="logoutControlSpan2" style="color:white"></span>
|
||
<div tabindex="0" id="uiMenuButton" title="ユーザーインターフェイスの選択" onclick="showUserInterfaceSelectMenu()" onkeypress="if (event.key == 'Enter') showUserInterfaceSelectMenu()">
|
||
♦
|
||
<div id="uiMenu" style="display:none">
|
||
<div tabindex="0" id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="左バーインターフェイス" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(1)"><div class="uiSelector1"></div></div>
|
||
<div tabindex="0" id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="トップバーインターフェース" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(2)"><div class="uiSelector2"></div></div>
|
||
<div tabindex="0" id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="固定幅インターフェイス" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)"><div class="uiSelector3"></div></div>
|
||
<div tabindex="0" id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="ナイトモードを切り替える" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
|
||
</div>
|
||
</div>
|
||
<table id="MainMenuSpan" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr>
|
||
<td tabindex="0" id="MainMenuMyDevices" class="topbar_td style3x" onclick="go(1,event)" onkeypress="if (event.key == 'Enter') go(1)">私のデバイス</td>
|
||
<td tabindex="0" id="MainMenuMyAccount" class="topbar_td style3x" onclick="go(2,event)" onkeypress="if (event.key == 'Enter') go(2)">マイアカウント</td>
|
||
<td tabindex="0" id="MainMenuMyEvents" class="topbar_td style3x" onclick="go(3,event)" onkeypress="if (event.key == 'Enter') go(3)">私のイベント</td>
|
||
<td tabindex="0" id="MainMenuMyFiles" class="topbar_td style3x" onclick="go(5,event)" onkeypress="if (event.key == 'Enter') go(5)">私のファイル</td>
|
||
<td tabindex="0" id="MainMenuMyUsers" class="topbar_td style3x" onclick="go(4,event)" onkeypress="if (event.key == 'Enter') go(4)">私のユーザー</td>
|
||
<td tabindex="0" id="MainMenuMyServer" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">私のサーバー</td>
|
||
<td class="topbar_td_end style3"> </td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="MainSubMenuSpan" style="display:none">
|
||
<table id="MainSubMenu" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr>
|
||
<td tabindex="0" id="MainDev" class="topbar_td style3x" onclick="go(10,event)" onkeypress="if (event.key == 'Enter') go(10)">全般</td>
|
||
<td tabindex="0" id="MainDevDesktop" class="topbar_td style3x" onclick="go(11,event)" onkeypress="if (event.key == 'Enter') go(11)">デスクトップ</td>
|
||
<td tabindex="0" id="MainDevTerminal" class="topbar_td style3x" onclick="go(12,event)" onkeypress="if (event.key == 'Enter') go(12)">ターミナル</td>
|
||
<td tabindex="0" id="MainDevFiles" class="topbar_td style3x" onclick="go(13,event)" onkeypress="if (event.key == 'Enter') go(13)">ファイル</td>
|
||
<td tabindex="0" id="MainDevEvents" class="topbar_td style3x" onclick="go(16,event)" onkeypress="if (event.key == 'Enter') go(16)">イベント</td>
|
||
<td tabindex="0" id="MainDevInfo" class="topbar_td style3x" onclick="go(17,event)" onkeypress="if (event.key == 'Enter') go(17)">詳細</td>
|
||
<td tabindex="0" id="MainDevAmt" class="topbar_td style3x" onclick="go(14,event)" onkeypress="if (event.key == 'Enter') go(14)">Intel® AMT</td>
|
||
<td tabindex="0" id="MainDevConsole" class="topbar_td style3x" onclick="go(15,event)" onkeypress="if (event.key == 'Enter') go(15)">コンソール</td>
|
||
<td tabindex="0" id="MainDevPlugins" class="topbar_td style3x" onclick="go(19,event)" onkeypress="if (event.key == 'Enter') go(19)">プラグイン</td>
|
||
<td class="topbar_td_end style3"> </td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="MeshSubMenuSpan" style="display:none">
|
||
<table id="MeshSubMenu" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr>
|
||
<td tabindex="0" id="MeshGeneral" class="topbar_td style3x" onclick="go(20,event)" onkeypress="if (event.key == 'Enter') go(20)">全般</td>
|
||
<td tabindex="0" id="MeshSummary" class="topbar_td style3x" onclick="go(21,event)" onkeypress="if (event.key == 'Enter') go(21)">Summary</td>
|
||
<td class="topbar_td_end style3"> </td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="UserSubMenuSpan" style="display:none">
|
||
<table id="UserSubMenu" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr>
|
||
<td tabindex="0" id="UserGeneral" class="topbar_td style3x" onclick="go(30,event)" onkeypress="if (event.key == 'Enter') go(30)">全般</td>
|
||
<td tabindex="0" id="UserEvents" class="topbar_td style3x" onclick="go(31,event)" onkeypress="if (event.key == 'Enter') go(31)">イベント</td>
|
||
<td class="topbar_td_end style3"> </td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="ServerSubMenuSpan" style="display:none">
|
||
<table id="ServerSubMenu" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr>
|
||
<td tabindex="0" id="ServerGeneral" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">全般</td>
|
||
<td tabindex="0" id="ServerStats" class="topbar_td style3x" onclick="go(40,event)" onkeypress="if (event.key == 'Enter') go(40)">統計</td>
|
||
<td tabindex="0" id="ServerConsole" class="topbar_td style3x" onclick="go(115,event)" onkeypress="if (event.key == 'Enter') go(115)">コンソール</td>
|
||
<td tabindex="0" id="ServerTrace" class="topbar_td style3x" onclick="go(41,event)" onkeypress="if (event.key == 'Enter') go(41)">トレース</td>
|
||
<td tabindex="0" id="ServerPlugins" class="topbar_td style3x" onclick="go(42,event)" onkeypress="if (event.key == 'Enter') go(42)">プラグイン</td>
|
||
<td class="topbar_td_end style3"> </td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="UserDummyMenuSpan">
|
||
<table id="UserDummyMenu" cellpadding="0" cellspacing="0" class="style1">
|
||
<tbody><tr><td class="style3" style=""> </td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="column_l">
|
||
<div id="p0" style="display:none">
|
||
<div id="p0message"><span id="p0span">サーバーが切断されました</span>、 <href onclick="reload()" style="cursor:pointer"><u>クリックして再接続</u></href>。</div>
|
||
</div>
|
||
<div id="p1" style="display:none">
|
||
<div id="p1title">
|
||
<div style="display:none" id="devListToolbarViewIcons">
|
||
<div tabindex="0" id="devViewButton1" class="viewSelector" onclick="onDeviceViewChange(1)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(1); }" title="列"><div class="viewSelector2"></div></div>
|
||
<div tabindex="0" id="devViewButton2" class="viewSelector" onclick="onDeviceViewChange(2)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(2); }" title="リスト"><div class="viewSelector1"></div></div>
|
||
<div tabindex="0" id="devViewButton3" class="viewSelector" onclick="onDeviceViewChange(3)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(3); }" title="デスクトップ"><div class="viewSelector3"></div></div>
|
||
<div tabindex="0" id="devViewButton4" class="viewSelector" onclick="onDeviceViewChange(4)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(4); }" title="地図" style="display:none"><div class="viewSelector4"></div></div>
|
||
</div><div><h1>私のデバイス</h1></div>
|
||
</div>
|
||
<table id="devListToolbarSpan" class="noselect">
|
||
<tbody><tr>
|
||
<td class="h1"></td>
|
||
<td id="devListToolbar" class="style14" style="display:none">
|
||
<input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="すべて選択">
|
||
<input type="button" id="GroupActionButton" disabled="disabled" value="グループアクション" onclick="groupActionFunction()">
|
||
<input id="SearchInput" type="text" placeholder="フィルタ" onchange="masterUpdate(5)" onkeyup="masterUpdate(5)" autocomplete="off" onfocus="onSearchFocus(1)" onblur="onSearchFocus(0)">
|
||
<label><input type="checkbox" id="RealNameCheckBox" onclick="onRealNameCheckBox()"><span title="デバイスのオペレーティングシステム名を表示する">OS名</span></label>
|
||
</td>
|
||
<td id="kvmListToolbar" class="style14" style="display:none">
|
||
<input type="button" onclick="connectAllKvmFunction()" value="すべて接続">
|
||
<input type="button" onclick="disconnectAllKvmFunction()" value="すべて切断">
|
||
<label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="自動接続">オート </label>
|
||
<input type="button" onclick="showMultiDesktopSettings()" value="設定">
|
||
</td>
|
||
<td id="devMapToolbar" class="style14" style="display:none">
|
||
<input type="text" id="mapSearchLocation" placeholder="場所を検索" onfocus="onMapSearchFocus(1)" onblur="onMapSearchFocus(0)">
|
||
<input type="button" value="サーチ" title="場所を検索" onclick="getSearchLocation()">
|
||
<input type="button" id="refreshmap" title="マップビューをリセット" value="リセットする" onclick="refreshMap(false,true)">
|
||
</td>
|
||
<td class="auto-style1" style="height:100%">
|
||
<div style="display:none" id="devListToolbarView">
|
||
表示する
|
||
<select id="viewselect" onchange="onDeviceViewChange()">
|
||
<option value="1">列</option>
|
||
<option value="2">リスト</option>
|
||
<option value="3">デスクトップ</option>
|
||
<option id="viewselectmapoption" value="4" style="display:none">地図</option>
|
||
</select>
|
||
</div>
|
||
<div style="display:none" id="devListToolbarSort">
|
||
ソート
|
||
<select id="sortselect" onchange="masterUpdate(6)">
|
||
<option>グループ</option>
|
||
<option>力</option>
|
||
<option>デバイス</option>
|
||
<option>タグ</option>
|
||
</select>
|
||
|
||
</div>
|
||
<div style="display:none" id="devListToolbarSize">
|
||
サイズ
|
||
<select id="sizeselect" onchange="onDeviceViewChange()">
|
||
<option value="0">小さい</option>
|
||
<option value="1">中</option>
|
||
<option value="2">大</option>
|
||
</select>
|
||
|
||
</div>
|
||
</td>
|
||
<td class="h2"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="NoMeshesPanel" style="display:none">
|
||
<table>
|
||
<tbody><tr>
|
||
<td valign="top" style="width:50px">
|
||
<img src="images/info.png">
|
||
</td>
|
||
<td>
|
||
<div id="getStarted1">始めるには、 <a href="#" onclick="return account_createMesh()"><strong>ここをクリックしてデバイスグループを作成します</strong></a>。</div>
|
||
<div id="getStarted2">デバイスグループはありません。</div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="xdevices" class="noselect" style="display:none"></div>
|
||
<div id="xdevicesmap" style="display:none">
|
||
<div id="xmapSearchResultsDlg" style="display:none">
|
||
<div id="xmapSearchResultsBck">
|
||
<div id="xmapSearchClose" onclick="mapCloseSearchWindow()"><b>バツ</b></div>
|
||
<div style="padding:5px">ロケーション結果</div>
|
||
<div style="width:100%;margin:6px"></div>
|
||
</div>
|
||
<div id="xmapSearchResults" style="margin:6px"></div>
|
||
</div>
|
||
</div>
|
||
<div id="xmap-info-window"></div>
|
||
</div>
|
||
<div id="p2" style="display:none">
|
||
<div id="p2title"><h1>マイアカウント</h1></div>
|
||
<img id="p2AccountImage" alt="" src="images/clipboard-128.png">
|
||
<div id="p2AccountSecurity" style="display:none">
|
||
<p><strong>アカウントのセキュリティ</strong></p>
|
||
<div style="margin-left:25px">
|
||
<div id="manageAuthApp"><div class="p2AccountActions"><span id="authAppSetupCheck"><strong>✓</strong></span></div><span><a href="#" onclick="return account_manageAuthApp()">認証アプリを管理する</a><br></span></div>
|
||
<div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>✓</strong></span></div><span><a href="#" onclick="return account_manageHardwareOtp(0)">セキュリティキーを管理する</a><br></span></div>
|
||
<div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>✓</strong></span></div><span><a href="#" onclick="return account_manageOtp(0)">バックアップコードを管理する</a><br></span></div>
|
||
</div>
|
||
</div>
|
||
<div id="p2AccountActions">
|
||
<p><strong>アカウントアクション</strong></p>
|
||
<p class="mL">
|
||
<span id="verifyEmailId" style="display:none"><a href="#" onclick="return account_showVerifyEmail()">Eメールを確認します</a><br></span>
|
||
<span id="accountEnableNotificationsSpan" style="display:none"><a href="#" onclick="return account_enableNotifications()">Web通知を有効にする</a><br></span>
|
||
<a href="#" onclick="return account_showLocalizationSettings()">ローカリゼーション設定</a><br>
|
||
<a href="#" onclick="return account_showAccountNotifySettings()">通知設定</a><br>
|
||
<span id="accountChangeEmailAddressSpan" style="display:none"><a href="#" onclick="return account_showChangeEmail()">メールアドレスを変更する</a><br></span>
|
||
<a href="#" onclick="return account_showChangePassword()">パスワードを変更する</a><span id="p2nextPasswordUpdateTime"></span><br>
|
||
<a href="#" onclick="return account_showDeleteAccount()">アカウントを削除する</a><br>
|
||
</p>
|
||
<br style="clear:both">
|
||
</div>
|
||
<strong>デバイスグループ</strong>
|
||
<span id="p2createMeshLink1">( <a href="#" onclick="return account_createMesh()" class="newMeshBtn"> 新しい</a> )</span>
|
||
<br><br>
|
||
<div id="p2meshes"></div>
|
||
<div id="p2noMeshFound" style="display:none">デバイスグループはありません。<span id="p2createMeshLink2"> <a href="#" onclick="return account_createMesh()"><strong>ここから始めましょう!</strong></a></span></div>
|
||
<br style="clear:both">
|
||
</div>
|
||
<div id="p3" style="display:none">
|
||
<div id="p3title"><h1>私のイベント</h1></div>
|
||
<table class="pTable">
|
||
<tbody><tr>
|
||
<td class="h1"></td>
|
||
<td class="auto-style1">
|
||
ショー
|
||
<select id="p3limitdropdown" onchange="refreshEvents()">
|
||
<option value="60">最後の60</option>
|
||
<option value="120">最後の120</option>
|
||
<option value="250">過去250</option>
|
||
<option value="500">最後の500</option>
|
||
<option value="1000">過去1000</option>
|
||
</select>
|
||
<a href="#" onclick="p3showDownloadEventsDialog(2)"><img src="images/link4.png" height="10" width="10" title="イベントをダウンロードする" style="cursor:pointer"></a>
|
||
</td>
|
||
<td class="h2"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p3events" style=""></div>
|
||
</div>
|
||
<div id="p4" style="display:none">
|
||
<div id="p4title"><h1>私のユーザー</h1></div>
|
||
<table class="pTable">
|
||
<tbody><tr>
|
||
<td class="h1"></td>
|
||
<td class="style14">
|
||
<div style="float:right">
|
||
<input type="button" onclick="showUserBroadcastDialog()" style="margin-right:6px" value="放送">
|
||
<a href="#" onclick="p4downloadUserInfo()"><img style="cursor:pointer" title="ユーザー情報をダウンロードする" src="images/link4.png"></a>
|
||
<a href="#" onclick="p4batchAccountCreate()"><img id="p4UserBatchCreate" style="cursor:pointer;display:none" title="多数のユーザーアカウントをバッチ作成する" src="images/link6.png"></a>
|
||
</div>
|
||
<div>
|
||
<input id="UserNewAccountButton" type="button" style="margin-left:6px" onclick="showCreateNewAccountDialog()" value="新しいアカウント...">
|
||
<input id="UserSearchInput" type="text" style="width:120px;margin-left:6px" placeholder="フィルタ" onchange="onUserSearchInputChanged()" onkeyup="onUserSearchInputChanged()" autocomplete="off" onfocus="onUserSearchFocus(1)" onblur="onUserSearchFocus(0)">
|
||
</div>
|
||
</td>
|
||
<td class="h2"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p3users"></div>
|
||
</div>
|
||
<div id="p5" style="display:none">
|
||
<div id="p5title"><h1>私のファイル</h1></div>
|
||
<table id="p5toolbar" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td id="p5filehead" valign="bottom">
|
||
<div id="p5rightOfButtons"></div>
|
||
<div>
|
||
<input type="button" id="p5FolderUp" disabled="disabled" onclick="return p5folderup();" value="アップ">
|
||
<input type="button" id="p5SelectAllButton" disabled="disabled" onclick="p5selectallfile();" value="すべて選択">
|
||
<input type="button" id="p5RenameFileButton" disabled="disabled" value="リネーム" onclick="p5renamefile();">
|
||
<input type="button" id="p5DeleteFileButton" disabled="disabled" value="削除する" onclick="p5deletefile();">
|
||
<!--<input type=button id=p5ViewFileButton disabled="disabled" value="View" onclick="p5viewfile()" /> -->
|
||
<input type="button" id="p5NewFolderButton" disabled="disabled" value="新しいフォルダ" onclick="p5createfolder();">
|
||
<input type="button" id="p5UploadButton" disabled="disabled" value="アップロードする" onclick="p5uploadFile()">
|
||
<input type="button" id="p5CutButton" disabled="disabled" value="カット" onclick="p5copyFile(1)">
|
||
<input type="button" id="p5CopyButton" disabled="disabled" value="コピー" onclick="p5copyFile(0)">
|
||
<input type="button" id="p5PasteButton" disabled="disabled" value="ペースト" onclick="p5pasteFile()">
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td id="p5filesubhead">
|
||
<div style="float:right">
|
||
<select id="p5sortdropdown" onchange="updateFiles()">
|
||
<option value="1" selected="selected">名前順</option>
|
||
<option value="2">サイズで並べ替え</option>
|
||
<option value="3">日付けで並び替え</option>
|
||
<option value="4">名前で降順</option>
|
||
<option value="5">サイズで降順</option>
|
||
<option value="6">日付で降順</option>
|
||
</select>
|
||
</div>
|
||
<div> <span id="p5currentpath"></span></div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p5filetable">
|
||
<!--
|
||
<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=""><div>これらのファイルは一般公開されています。「リンク」をクリックして公開URLを取得してください。</div></div>
|
||
<div id="bigok" style="display:none"><b>✓</b></div>
|
||
<div id="bigfail" style="display:none"><b>✗</b></div>
|
||
<span id="p5files"></span>
|
||
</div>
|
||
<table id="p5toolbarBottom" style="width:100%" cellpadding="0" cellspacing="0">
|
||
<tbody><tr><td class="style6"> <span id="p5bottomstatus"></span></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="p6" style="display:none">
|
||
<div id="p6title">
|
||
<img id="MainMeshImage" src="serverpic.ashx">
|
||
<h1>私のサーバー</h1>
|
||
</div>
|
||
<div id="p2ServerActions">
|
||
<p><strong>サーバーアクション</strong></p>
|
||
<div class="mL">
|
||
<div id="p2ServerActionsBackup"><a href="{{{domainurl}}}backup.zip" rel="noreferrer noopener" target="_blank">サーバーのバックアップをダウンロード</a></div>
|
||
<div id="p2ServerActionsRestore"><a href="#" onclick="return server_showRestoreDlg()">バックアップでサーバーを復元する</a></div>
|
||
<div id="p2ServerActionsVersion"><a href="#" onclick="return server_showVersionDlg()">サーバーのバージョンを確認する</a></div>
|
||
<div id="p2ServerActionsErrors"><a href="#" onclick="return server_showErrorsDlg()">サーバーエラーログを表示</a></div>
|
||
</div>
|
||
</div>
|
||
<br><strong>サーバー統計</strong><br><br>
|
||
<div id="serverStats">
|
||
<div id="serverCpuChartView" style="display:none">
|
||
<div class="chartViewCanvas"><canvas id="serverCpuChart"></canvas></div>
|
||
<div class="chartViewText" id="serverCpuChartText"></div>
|
||
</div>
|
||
<div id="serverMemoryChartView" style="display:none">
|
||
<div class="chartViewCanvas"><canvas id="serverMemoryChart"></canvas></div>
|
||
<div class="chartViewText" id="serverMemoryChartText"></div>
|
||
</div><br><br>
|
||
<div id="serverStatsTable"></div>
|
||
</div>
|
||
<div id="serverWarningsDiv" style="display:none">
|
||
<br><strong>サーバー警告</strong><br><br>
|
||
<div id="serverWarnings"></div>
|
||
</div>
|
||
</div>
|
||
<div id="p10" style="display:none">
|
||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td style="width:auto" valign="top">
|
||
<div id="p10title">
|
||
<div id="p10BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>全般- <span id="p10deviceName"></span></h1>
|
||
</div>
|
||
<div id="p10html"></div>
|
||
</td>
|
||
<td style="width:20px"></td>
|
||
<td style="width:200px">
|
||
<a href="#" onclick="p10showiconselector()"><img id="MainComputerImage"></a>
|
||
<div id="MainComputerState"></div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table><br>
|
||
<div id="p10html2"></div>
|
||
<div id="p10html3"></div>
|
||
</div>
|
||
<div id="p11" class="noselect" style="display:none">
|
||
<div id="p11title">
|
||
<div id="p11deviceNameHeader">
|
||
<div id="p11BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<div id="devListToolbarViewIcons"><div class="viewSelector" onclick="deskToggleFull(event)" title="全画面表示。ブラウザの全画面表示に移行します。"><div class="viewSelector5"></div></div></div>
|
||
<h1>デスクトップ- <span id="p11deviceName"></span></h1>
|
||
</div>
|
||
</div>
|
||
<div id="p11warning" onclick="showFeaturesDlg()">
|
||
<div class="icon2"></div>
|
||
<div class="warningbox">Intel® AMTリダイレクトポートまたはKVM機能が無効になっています<span id="p11warninga">、ここをクリックして有効にします。</span></div>
|
||
</div>
|
||
<div id="p11warning2" onclick="showPowerActionDlg()">
|
||
<div class="icon2"></div>
|
||
<div class="warningbox">リモートコンピューターの電源が入っていません。ここをクリックして電源コマンドを発行してください。</div>
|
||
</div>
|
||
<div id="deskarea0" cellpadding="0" cellspacing="0">
|
||
<div id="deskarea1" class="areaHead">
|
||
<div class="toright2">
|
||
<span id="p11power"></span>
|
||
<div class="deskareaicon" title="表示モードの切り替え" onclick="toggleAspectRatio(1)">⇲</div>
|
||
<div class="deskareaicon" title="左に回転" onclick="drotate(-1)">↺</div>
|
||
<div class="deskareaicon" title="右に回る" onclick="drotate(1)">↻</div>
|
||
<div id="deskRecordIcon" class="deskareaicon" title="サーバーはこのセッションを記録しています" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px"></div>
|
||
<input id="deskFocusBtn" type="button" title="フォーカスモードを切り替えます。アクティブな場合、マウス周辺の領域のみが更新されます。" onkeypress="return false" onkeydown="return false" value="すべてにフォーカス" onclick="deskToggleFocus()" style="margin-right:3px;display:none">
|
||
<input id="deskSaveBtn" type="button" title="リモートデスクトップのスクリーンショットを保存する" onkeypress="return false" onkeydown="return false" value="セーブ..." onclick="deskSaveImage()" class="mR">
|
||
<input id="deskActionsBtn" type="button" title="デバイスの電源操作を実行します" onkeypress="return false" onkeydown="return false" value="行動" onclick="deviceActionFunction()" class="mR">
|
||
<input id="deskActionsSettings" type="button" value="設定..." title="リモートデスクトップ設定を編集する" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR">
|
||
<input type="button" title="リモートマシンの電源状態を変更する" onkeypress="return false" onkeydown="return false" value="電源アクション..." onclick="showPowerActionDlg()" style="display:none">
|
||
</div>
|
||
<div>
|
||
<div id="idx_deskFullBtn2" onclick="deskToggleFull(event)"> ✖</div>
|
||
<input type="button" id="autoconnectbutton1" value="自動接続" onclick="autoConnectDesktop(event)" onkeypress="return false" onkeydown="return false" style="display:none">
|
||
<span id="connectbutton1span"><input type="button" id="connectbutton1" value="つなぐ" onclick="connectDesktop(event,3)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||
<span id="connectbutton1hspan"> <input type="button" id="connectbutton1h" value="HW Connect" title="Intel AMTハードウェアKVMを使用して接続する" onclick="connectDesktop(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||
<span id="disconnectbutton1span"> <input type="button" id="disconnectbutton1" value="切断する" onclick="connectDesktop(event,0)" onkeypress="return false" onkeydown="return false"></span>
|
||
<span id="deskstatus">切断されました</span>
|
||
</div>
|
||
</div>
|
||
<div id="deskarea2" style="">
|
||
<div class="areaProgress"><div id="progressbar" style=""></div></div>
|
||
</div>
|
||
<div id="deskarea3x">
|
||
<div id="DeskFocus" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
|
||
<div id="DeskParent">
|
||
<canvas id="Desk" width="640" height="480" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onmousewheel="dmousewheel(event)"></canvas>
|
||
</div>
|
||
<div id="DeskTools">
|
||
<div id="deskToolsAreaTop">
|
||
<a id="DeskToolsRefreshButton" style="right:2px" onclick="refreshDeskTools()">リフレッシュ</a>
|
||
<div id="deskToolsTopTabProcess" class="deskToolsTopTab" onclick="changeDeskToolTab(0)" style="left:0px;bottom:0px">プロセス</div>
|
||
<div id="deskToolsTopTabService" class="deskToolsTopTab" onclick="changeDeskToolTab(1)" style="display:none;left:90px;color:gray">サービス</div>
|
||
</div>
|
||
<div id="deskToolsArea">
|
||
<div id="DeskToolsProcessTab">
|
||
<div id="deskToolsHeader">
|
||
<a class="colmn1" title="プロセスIDで並べ替え" onclick="sortProcess(0)">PID</a>
|
||
<a class="colmn2" title="名前順" onclick="sortProcess(1)">名</a>
|
||
</div>
|
||
<div id="DeskToolsProcesses" style=""></div>
|
||
</div>
|
||
<div id="DeskToolsServiceTab" style="display:none">
|
||
<div id="deskToolsServiceHeader">
|
||
<a class="colmn1" style="width:70px" title="状態で並べ替え" onclick="sortService(0)">状態</a>
|
||
<a class="colmn2" title="名前順" onclick="sortService(1)">名</a>
|
||
</div>
|
||
<div id="DeskToolsServices" style=""></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="p11DeskConsoleMsg" style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick="p11clearConsoleMsg()"></div>
|
||
<div id="p11DeskSessionSelector" style="display:none;position:absolute;left:30px;top:17px;right:30px"></div>
|
||
</div>
|
||
<div id="deskarea4" class="areaFoot">
|
||
<div class="toright2">
|
||
<span id="DeskTimer" title="セッション時間"></span>
|
||
<select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onkeypress="return false" onkeydown="return false"></select>
|
||
<input id="DeskToolsButton" type="button" value="道具" title="ツールビューの切り替え" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">
|
||
<span id="DeskChatButton" class="deskarea" title="このコンピューターへのチャットウィンドウを開く"><img src="images/icon-chat.png" onclick="deviceChat(event)" height="16" width="16" style="padding-top:2px"></span>
|
||
<span id="DeskNotifyButton" title="リモートコンピューターに通知を表示する"><img src="images/icon-notify.png" onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span>
|
||
<span id="DeskOpenWebButton" title="リモートコンピューターでWebアドレスを開く"><img src="images/icon-url2.png" onclick="deviceUrlFunction()" height="16" width="16" style="padding-top:2px"></span>
|
||
<span id="DeskBackgroundButton" title="リモートデスクトップの背景を切り替える"><img src="images/icon-background.png" onclick="deviceToggleBackground(event)" height="16" width="16" style="padding-top:2px"></span>
|
||
</div>
|
||
<div>
|
||
<select id="deskkeys">
|
||
<option value="10">Ctrl + Alt + Del</option>
|
||
<option value="5">勝つ</option>
|
||
<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>
|
||
<option value="6">Win + R</option>
|
||
<option value="7">Alt-F4</option>
|
||
<option value="8">Ctrl-W</option>
|
||
<option value="9">Alt-Tab</option>
|
||
<option value="11">Win +左</option>
|
||
<option value="12">勝ち+右</option>
|
||
</select>
|
||
<input id="DeskWD" type="button" value="送る" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
|
||
<input id="DeskClip" style="" type="button" value="クリップボード" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()">
|
||
<input id="DeskType" style="" type="button" value="タイプ" onkeypress="return false" onkeydown="return false" onclick="showDeskType()">
|
||
<label><span id="DeskControlSpan" title="マウスとキーボードの入力を切り替える"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">入力</span></label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="p12" style="display:none">
|
||
<div id="p12title">
|
||
<div id="p12BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>ターミナル - <span id="p12deviceName"></span></h1>
|
||
</div>
|
||
<div id="p12warning" onclick="showFeaturesDlg()">
|
||
<div class="icon2"></div>
|
||
<div class="warningbox">Intel® AMTリダイレクトポートまたはKVM機能が無効になっています<span id="p12warninga">、ここをクリックして有効にします。</span></div>
|
||
</div>
|
||
<div id="p12warning2" onclick="showPowerActionDlg()">
|
||
<div class="icon2"></div>
|
||
<div class="warningbox">リモートコンピューターの電源が入っていません。ここをクリックして電源コマンドを発行してください。</div>
|
||
</div>
|
||
<div id="termTable" style="position:relative">
|
||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td class="areaHead">
|
||
<div class="toright2">
|
||
<div id="termRecordIcon" class="deskareaicon" title="サーバーはこのセッションを記録しています" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
|
||
<input id="termActionsBtn" type="button" title="デバイスの電源操作を実行します" onkeypress="return false" onkeydown="return false" value="行動" onclick="deviceActionFunction()">
|
||
</div>
|
||
<div>
|
||
<input type="button" id="autoconnectbutton2" value="自動接続" onclick="autoConnectTerminal(event)" onkeypress="return false" onkeydown="return false" style="display:none">
|
||
<span id="connectbutton2span"><input type="button" id="connectbutton2" value="つなぐ" onclick="connectTerminal(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||
<span id="connectbutton2hspan"> <input type="button" id="connectbutton2h" value="HW Connect" title="Intel AMTハードウェアKVMを使用して接続する" onclick="connectTerminal(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
|
||
<span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="切断する" onclick="connectTerminal(event,0)" onkeypress="return false" onkeydown="return false"></span>
|
||
<span id="termstatus">切断されました</span><span id="termtitle"></span>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
<div class="areaProgress"><div id="termprogressbar" style=""></div></div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td id="termarea3x">
|
||
<pre id="Term"></pre>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="areaFoot">
|
||
<div class="toright2">
|
||
<span id="TermTimer" title="セッション時間"></span>
|
||
<span id="terminalSettingsButtons" style="display:none">
|
||
<input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR + LF" title="リターンキーが送信するものを切り替える" onclick="termToggleCr()">
|
||
<input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel(F10 = ESC + [OM)" title="F1からF10キーのエミュレーションタイプを切り替えます" onclick="termToggleFx()">
|
||
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="拡張アスキー" title="ターミナルエミュレーションタイプの切り替え" onclick="termToggleType()">
|
||
</span>
|
||
<span id="terminalSizeDropDown">
|
||
<select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option><option value="3" selected="">オート</option></select>
|
||
</span>
|
||
<select id="specialkeylist" onkeypress="return false"></select>
|
||
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="送る" title="選択した特殊キーを送信します" onclick="sendSpecialKey()">
|
||
</div>
|
||
<div>
|
||
|
||
<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="バックスペース" onclick="termSendKey(8,'bsbutton')">
|
||
<input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="ペースト" title="端末にテキストを貼り付けます" onclick="showTermPasteDialog()">
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p12TermConsoleMsg" style="display:none;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick="p12clearConsoleMsg()"></div>
|
||
</div>
|
||
</div>
|
||
<div id="p13" style="display:none">
|
||
<div id="p13title">
|
||
<div id="p13BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>ファイル- <span id="p13deviceName"></span></h1>
|
||
</div>
|
||
<table id="p13toolbar" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td class="areaHead">
|
||
<div class="toright2">
|
||
<input id="filesActionsBtn" type="button" title="デバイスの電源操作を実行します" value="行動" onclick="deviceActionFunction()">
|
||
<div id="filesRecordIcon" class="deskareaicon" title="サーバーはこのセッションを記録しています" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
|
||
</div>
|
||
<div>
|
||
<input id="p13AutoConnect" value="自動接続" onclick="autoConnectFiles(event)" type="button" style="display:none">
|
||
<input id="p13Connect" value="つなぐ" onclick="connectFiles(event)" type="button">
|
||
<span id="p13Status">切断されました</span>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="areaHead2" valign="bottom">
|
||
<div id="p13rightOfButtons" class="toright2"></div>
|
||
<div>
|
||
<input type="button" id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="アップ">
|
||
<input type="button" id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="すべて選択">
|
||
<input type="button" id="p13RenameFileButton" disabled="disabled" value="リネーム" onclick="p13renamefile()">
|
||
<input type="button" id="p13DeleteFileButton" disabled="disabled" value="削除する" onclick="p13deletefile()">
|
||
<input type="button" id="p13ViewFileButton" disabled="disabled" value="編集" onclick="p13viewfile()">
|
||
<input type="button" id="p13NewFolderButton" disabled="disabled" value="新しいフォルダ" onclick="p13createfolder()">
|
||
<input type="button" id="p13UploadButton" disabled="disabled" value="アップロードする" onclick="p13uploadFile()">
|
||
<input type="button" id="p13CutButton" disabled="disabled" value="カット" onclick="p13copyFile(1)">
|
||
<input type="button" id="p13CopyButton" disabled="disabled" value="コピー" onclick="p13copyFile(0)">
|
||
<input type="button" id="p13PasteButton" disabled="disabled" value="ペースト" onclick="p13pasteFile()">
|
||
<input type="button" id="p13RefreshButton" disabled="disabled" value="リフレッシュ" onclick="p13folderup(9999)">
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="areaHead3">
|
||
<div class="toright2">
|
||
<select id="p13sortdropdown" onchange="p13updateFiles()">
|
||
<option value="1" selected="selected">名前順</option>
|
||
<option value="2">サイズで並べ替え</option>
|
||
<option value="3">日付けで並び替え</option>
|
||
<option value="4">名前で降順</option>
|
||
<option value="5">サイズで降順</option>
|
||
<option value="6">日付で降順</option>
|
||
</select>
|
||
</div>
|
||
<div> <span id="p13currentpath"></span></div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p13FilesConsoleMsg" style="display:none;cursor:pointer;position:absolute;left:30px;top:165px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick="p13clearConsoleMsg()"></div>
|
||
<div id="p13filetable" style="">
|
||
<div id="p13bigok" style="display:none"><b>✓</b></div>
|
||
<div id="p13bigfail" style="display:none"><b>✗</b></div>
|
||
<span id="p13files"></span>
|
||
</div>
|
||
<table id="p13toolbarBottom" cellpadding="0" cellspacing="0">
|
||
<tbody><tr><td class="style6"> <span id="p13bottomstatus"></span></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="p14" style="display:none">
|
||
<div id="p14title">
|
||
<div id="p14BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<div id="devListToolbarViewIcons"><div class="viewSelector" onclick="deskToggleFull(event)" title="全画面表示。ブラウザの全画面表示に移行します。"><div class="viewSelector5"></div></div></div>
|
||
<h1>Intel® AMT - <span id="p14deviceName"></span></h1>
|
||
</div>
|
||
<iframe id="p14iframe" src="{{{domainurl}}}commander.htm"></iframe>
|
||
</div>
|
||
<div id="p15" style="display:none">
|
||
<div id="p15title">
|
||
<div id="p15BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1><span id="p15deviceName"></span></h1>
|
||
</div>
|
||
<table id="consoleTable" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td class="areaHead">
|
||
<div class="toright2">
|
||
<div id="p15coreName" title="このエージェントで実行されている現在のコアに関する情報"></div>
|
||
<input type="button" id="p15uploadCore" value="エージェントアクション" onclick="p15uploadCore(event)" title="エージェントのJava Scriptコードモジュールを変更する">
|
||
<img onclick="p15downloadConsoleText()" style="cursor:pointer;margin-top:6px" title="コンソールテキストをダウンロードする" src="images/link4.png">
|
||
</div>
|
||
<div id="p15statetext"></div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
<div class="areaProgress"><div id="consoleprogressbar" style=""></div></div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td id="p15agentConsole">
|
||
<pre id="p15agentConsoleText"></pre>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="areaFoot">
|
||
<table style="width:100%">
|
||
<tbody><tr>
|
||
<td style="width:99%">
|
||
<input id="p15consoleText" style="width:100%" onkeyup="p15consoleSend(event)" onfocus="onConsoleFocus(1)" onblur="onConsoleFocus(0)">
|
||
</td>
|
||
<td> </td>
|
||
<td id="p15outputselecttd">
|
||
<select id="p15outputselect">
|
||
<option value="1">エージェント</option>
|
||
<option value="2">MQTT</option>
|
||
</select>
|
||
</td>
|
||
<td style="width:1%"><input id="id_p15consoleClear" type="button" class="bottombutton" value="クリア" onclick="p15consoleClear()"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
</td>
|
||
</tr>
|
||
</tbody></table>
|
||
</div>
|
||
<div id="p16" style="display:none">
|
||
<div id="p16title">
|
||
<div id="p16BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>イベント- <span id="p16deviceName"></span></h1>
|
||
</div>
|
||
<table class="pTable">
|
||
<tbody><tr>
|
||
<td class="h1"></td>
|
||
<!--<td> <input type=button onclick=refreshDeviceEvents() value="Refresh" /></td>-->
|
||
<td class="auto-style1">
|
||
ショー
|
||
<select id="p16limitdropdown" onchange="refreshDeviceEvents()">
|
||
<option value="60">最後の60</option>
|
||
<option value="120">最後の120</option>
|
||
<option value="250">過去250</option>
|
||
<option value="500">最後の500</option>
|
||
<option value="1000">過去1000</option>
|
||
</select>
|
||
<a href="#" onclick="p3showDownloadEventsDialog(1)"><img src="images/link4.png" height="10" width="10" title="イベントをダウンロードする" style="cursor:pointer"></a>
|
||
</td>
|
||
<td class="h2"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p16events"></div>
|
||
</div>
|
||
<div id="p17" style="display:none">
|
||
<div id="p17title">
|
||
<div id="p17BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>詳細- <span id="p17deviceName"></span></h1>
|
||
</div>
|
||
<div id="p17info"></div>
|
||
</div>
|
||
<div id="p20" style="display:none">
|
||
<div id="p20title">
|
||
<picture id="MainMeshImage" style="border-width:0px;height:200px;width:200px;float:right">
|
||
<source type="image/webp" width="200" height="200" srcset="images/webp/mesh-256.webp">
|
||
<img alt="" width="200" height="200" src="images/mesh-256.png">
|
||
</picture>
|
||
<div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>全般- <span id="p20meshName"></span></h1>
|
||
</div>
|
||
<p id="p20info"></p>
|
||
</div>
|
||
<div id="p21" style="display:none">
|
||
<div id="p21title">
|
||
<div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>Summary - <span id="p21meshName"></span></h1>
|
||
</div>
|
||
<div style="width:100%">
|
||
<div style="display:table;width:93%">
|
||
<div id="meshPowerChartDiv" style="width:31%;display:inline-block;text-align:center;max-width:250px">
|
||
<div style="margin:10px;font-size:16px">Power States</div>
|
||
<canvas id="meshPowerChart" style="width:250px;height:250px"></canvas>
|
||
</div>
|
||
<div id="meshOsChartDiv" style="width:31%;display:inline-block;text-align:center;max-width:250px">
|
||
<div style="margin:10px;font-size:16px">Agent Types</div>
|
||
<canvas id="meshOsChart" style="width:250px;height:250px"></canvas>
|
||
</div>
|
||
<div id="meshConnChartDiv" style="width:31%;display:inline-block;text-align:center;max-width:250px">
|
||
<div style="margin:10px;font-size:16px">接続性</div>
|
||
<canvas id="meshConnChart" style="width:250px;height:250px"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p id="p21info"></p>
|
||
</div>
|
||
<div id="p30" style="display:none">
|
||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||
<tbody><tr>
|
||
<td style="width:auto" valign="top">
|
||
<div id="p30title">
|
||
<div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>全般- <span id="p30userName"></span></h1>
|
||
</div>
|
||
<div id="p30html"></div>
|
||
</td>
|
||
<td style="width:20px"></td>
|
||
<td style="width:200px">
|
||
<picture id="MainUserImage" style="border-width:0px;height:200px;width:200px;float:right">
|
||
<source type="image/webp" width="200" height="200" srcset="images/webp/user-256.webp">
|
||
<img alt="" width="200" height="200" src="images/user-256.png">
|
||
</picture>
|
||
<div style="width:100%;text-align:center"><strong><span id="MainUserState"></span></strong></div>
|
||
</td>
|
||
</tr>
|
||
</tbody></table><br>
|
||
<div id="p30html2"></div>
|
||
<div id="p30html3"></div>
|
||
</div>
|
||
<div id="p31" style="display:none">
|
||
<div id="p31title">
|
||
<div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="バック" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
|
||
<h1>イベント- <span id="p31userName"></span></h1>
|
||
</div>
|
||
<table class="pTable">
|
||
<tbody><tr>
|
||
<td class="h1"></td>
|
||
<!--<td> <input type=button onclick=refreshUsersEvents() value="Refresh" /></td>-->
|
||
<td class="auto-style1">
|
||
ショー
|
||
<select id="p31limitdropdown" onchange="refreshUsersEvents()">
|
||
<option value="60">最後の60</option>
|
||
<option value="120">最後の120</option>
|
||
<option value="250">過去250</option>
|
||
<option value="500">最後の500</option>
|
||
<option value="1000">過去1000</option>
|
||
</select>
|
||
<a href="#" onclick="p3showDownloadEventsDialog(3)"><img src="images/link4.png" height="10" width="10" title="イベントをダウンロードする" style="cursor:pointer"></a>
|
||
</td>
|
||
<td class="h2"></td>
|
||
</tr>
|
||
</tbody></table>
|
||
<div id="p31events" style=""></div>
|
||
</div>
|
||
<div id="p40" style="display:none">
|
||
<div id="p40title"><h1>私のサーバー統計</h1></div>
|
||
<div class="areaHead">
|
||
<div class="toright2">
|
||
<select id="p40type" onchange="updateServerTimelineStats()">
|
||
<option value="0">接続</option>
|
||
<option value="1">記憶</option>
|
||
</select>
|
||
<select id="p40time" onchange="updateServerTimelineHours()">
|
||
<option value="3">過去3時間</option>
|
||
<option value="8">過去8時間</option>
|
||
<option value="24">最終日</option>
|
||
<option value="168">先週</option>
|
||
<option value="720">過去30日間</option>
|
||
</select>
|
||
<img src="images/link4.png" height="10" width="10" title="データポイント(.csv)をダウンロードする" style="cursor:pointer" onclick="p40downloadEvents()">
|
||
</div>
|
||
<div>
|
||
<input value="リフレッシュ" type="button" onclick="refreshServerTimelineStats()">
|
||
<label><input id="p40log" type="checkbox" onclick="updateServerTimelineHours()">Log-X</label>
|
||
</div>
|
||
</div>
|
||
<canvas id="serverMainStats" style=""></canvas>
|
||
</div>
|
||
<div id="p41" style="display:none">
|
||
<div id="p41title"><h1>私のサーバートレース</h1></div>
|
||
<div class="areaHead">
|
||
<div class="toright2">
|
||
ショー
|
||
<select id="p41limitdropdown" onchange="displayServerTrace()">
|
||
<option value="100">最後の100</option>
|
||
<option value="250">過去250</option>
|
||
<option value="500">最後の500</option>
|
||
<option value="1000">過去1000</option>
|
||
</select>
|
||
<input value="クリア" type="button" onclick="clearServerTracing()">
|
||
<img src="images/link4.png" height="10" width="10" title="トレースのダウンロード(.csv)" style="cursor:pointer" onclick="p41downloadServerTrace()">
|
||
</div>
|
||
<div>
|
||
<input value="トレース" type="button" onclick="setServerTracing()">
|
||
<span id="p41traceStatus">なし</span>
|
||
</div>
|
||
</div>
|
||
<div id="p41events" style=""></div>
|
||
</div>
|
||
<div id="p42" style="display:none">
|
||
<h1>私のサーバープラグイン</h1>
|
||
<div class="areaHead">
|
||
<div class="toright2">
|
||
</div>
|
||
<div>
|
||
<input value="プラグインをダウンロード" type="button" onclick="return pluginHandler.addPluginDlg();">
|
||
</div>
|
||
</div>
|
||
<div id="pluginRestartNotice" class="areaHead" style="background-color:gold;display:none">
|
||
<div class="toright2">
|
||
<input value="エージェントコアの更新" type="button" onclick="distributeCore();return false">
|
||
</div>
|
||
<div style="padding:2px">
|
||
<div style="padding:2px"><b>通知:</b> プラグインが変更されたため、エージェントコアの更新が必要になる場合があります。</div>
|
||
</div>
|
||
</div>
|
||
<table id="p42tbl">
|
||
<tbody><tr class="DevSt"><th style="width:26px"></th><th style="width:10px"></th><th class="chName">名</th><th class="chDescription">説明</th><th class="chSite" style="text-align:center">リンク</th><th class="chVersion" style="text-align:center">バージョン</th><th class="chUpgradeAvail" style="text-align:center">最新</th><th class="chStatus" style="text-align:center">状態</th><th class="chAction" style="text-align:center">アクション</th><th style="width:10px"></th></tr>
|
||
</tbody></table>
|
||
<div id="pluginNoneNotice" style="width:100%;text-align:center;padding-top:10px;display:none"><i>サーバーにプラグインはありません。</i></div>
|
||
</div>
|
||
<div id="p43" style="display:none">
|
||
<div id="p43BackButton"><div class="backButton" tabindex="0" onclick="go(42)" title="バック" onkeypress="if (event.key == 'Enter') go(42)"><div class="backButtonEx"></div></div></div>
|
||
<h1>私のサーバープラグイン- <span id="p43title"></span></h1>
|
||
<iframe id="p43iframe" frameborder="0" style="width:100%;height:calc(100vh - 245px);max-height:calc(100vh - 245px)"></iframe>
|
||
</div>
|
||
<div id="p19" style="display:none">
|
||
<h1>プラグイン- <span id="p19deviceName"></span></h1>
|
||
<div id="p19headers"></div>
|
||
<div id="p19pages"></div>
|
||
</div>
|
||
<br id="column_l_bottomgap">
|
||
</div>
|
||
<div id="footer">
|
||
<div class="footer1">{{{footer}}}</div>
|
||
<div class="footer2">
|
||
<a id="verifyEmailId2" style="display:none" href="#" onclick="account_showVerifyEmail()">Eメールを確認します</a>
|
||
<a href="terms">利用規約とプライバシー</a>
|
||
</div>
|
||
</div>
|
||
<div id="dialog" class="noselect" style="display:none">
|
||
<div id="dialogHeader">
|
||
<div tabindex="0" id="id_dialogclose" onclick="setDialogMode()" onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
|
||
<div id="id_dialogtitle"></div>
|
||
</div>
|
||
<div id="dialogBody">
|
||
<div id="dialog1">
|
||
<div id="id_dialogMessage" style=""></div>
|
||
</div>
|
||
<div id="dialog2" style="">
|
||
<div id="id_dialogOptions"></div>
|
||
</div>
|
||
<div id="dialog3" style="">
|
||
<div id="d3upload">
|
||
<div>ファイル選択</div>
|
||
<select id="d3uploadMode" onchange="d3modechange()">
|
||
<option value="1">ローカルファイルのアップロード</option>
|
||
<option value="2">サーバーファイルの選択</option>
|
||
</select>
|
||
</div>
|
||
<div id="d3localmode" style="display:none">
|
||
<div>ファイルをアップロードする</div>
|
||
<form id="d3localmodeform" method="post" enctype="multipart/form-data" action="uploadfile.ashx" target="fileUploadFrame">
|
||
<input type="text" id="d3auth" name="auth" style="display:none">
|
||
<input type="text" id="d3attrib" name="attrib" style="display:none">
|
||
<input type="file" id="d3localFile" name="files" onchange="d3setActions()">
|
||
<input type="submit" id="d3submit" style="display:none">
|
||
</form>
|
||
</div>
|
||
<div id="d3servermode">
|
||
<div id="d3serveraction" valign="bottom">
|
||
<input type="button" id="p3FolderUp" disabled="disabled" onclick="d3folderup()" value="アップ">
|
||
</div>
|
||
<div id="d3serverfiles"></div>
|
||
</div>
|
||
</div>
|
||
<div id="dialog4" style="">
|
||
<input id="d4WrapButton" type="button" value="Wrap On" onclick="d4ToggleWrap()">
|
||
<input id="d4SizeButton" type="button" value="小さい" onclick="d4ToggleSize()">
|
||
<textarea id="d4editorarea" style="height:calc(100vh - 286px);width:100%;overflow:scroll;resize:none;white-space:pre"></textarea>
|
||
</div>
|
||
<div id="dialog7" style="">
|
||
<div id="d7meshkvm">
|
||
<h4>エージェントリモートデスクトップ</h4>
|
||
<div>
|
||
<div>品質</div>
|
||
<select id="d7bitmapquality" dir="rtl"></select>
|
||
</div>
|
||
<div>
|
||
<div>スケーリング</div>
|
||
<select id="d7bitmapscaling" style="" 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>
|
||
<div>
|
||
<div>フレームレート</div>
|
||
<select id="d7framelimiter" dir="rtl">
|
||
<option selected="selected" value="50">速い</option>
|
||
<option value="100">中</option>
|
||
<option value="400">スロー</option>
|
||
<option value="1000">非常に遅い</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div id="d7amtkvm">
|
||
<h4>Intel® AMTハードウェアKVM</h4>
|
||
<div>
|
||
<div>画像エンコーディング</div>
|
||
<select id="d7desktopmode">
|
||
<option value="1">RLE8、最速</option>
|
||
<option value="2">RLE16、推奨</option>
|
||
<option value="3">RAW8、遅い</option>
|
||
<option value="4">RAW16、非常に遅い</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<div>その他の設定</div>
|
||
<div id="d7otherset" style="display:block">
|
||
<label style="display:block"><input type="checkbox" id="d7showfocus">フォーカスツールを表示</label>
|
||
<label style="display:block"><input type="checkbox" id="d7showcursor">ローカルマウスカーソルを表示</label>
|
||
<label style="display:block"><input type="checkbox" id="d7localKeyMap">ローカルキーボードマップ</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="idx_dlgButtonBar">
|
||
<input id="idx_dlgCancelButton" type="button" value="キャンセル" style="" onclick="dialogclose(0)">
|
||
<input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
|
||
<div><input id="idx_dlgDeleteButton" type="button" value="削除する" style="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="p5fileDragAuthCookie" name="auth"><input id="p5fileDragSize" name="size"><input id="p5fileDragType" name="type"><input id="p5fileDragData" name="data"><input id="p5fileDragLink" name="link"><input type="submit" id="p5loginSubmit2" style="display:none"></form>
|
||
<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>
|
||
<script type="text/javascript">
|
||
'use strict';
|
||
|
||
// Process server-side web state
|
||
var webState = '{{{webstate}}}';
|
||
if (webState != '') { webState = JSON.parse(decodeURIComponent(webState)); }
|
||
for (var i in webState) { localStorage.setItem(i, webState[i]); }
|
||
if (!webState.loctag) { delete localStorage.removeItem('loctag'); }
|
||
|
||
var args;
|
||
var autoReconnect = true;
|
||
var powerStatetable = ['', "パワード", "睡眠", "睡眠", "睡眠", "冬眠", "電源を切る", "プレゼント"];
|
||
var StatusStrs = ["切断されました", "接続しています...", "セットアップ...", "接続済み", "Intel®接続されたAMT"];
|
||
var agentsStr = ["未知の", "Windows 32ビットコンソール", "Windows 64ビットコンソール", "Windows 32ビットサービス", "Windows 64ビットサービス", "Linux 32ビット", "Linux 64ビット", "MIPS", "XENx86", "Android ARM", "Linux ARM", "MacOS 32ビット", "Android x86", "PogoPlug ARM", "Android APK", "Linux Poky x86-32bit", "MacOS 64ビット", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64ビット", "Windows MinCoreコンソール", "Windows MinCoreサービス", "NodeJS", "ARM-リナロ", "ARMv6l / ARMv7l", "ARMv8 64ビット", "ARMv6l / ARMv7l / NoKVM", "未知の", "未知の", "FreeBSD x86-64"];
|
||
var sort = 0;
|
||
var searchFocus = 0;
|
||
var mapSearchFocus = 0;
|
||
var userSearchFocus = 0;
|
||
var consoleFocus = 0;
|
||
var showRealNames = false;
|
||
var meshserver = null;
|
||
var meshes = {};
|
||
var meshcount = 0;
|
||
var nodes = null;
|
||
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, localkeymap: false };
|
||
var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
|
||
var terminal;
|
||
var files;
|
||
var debugLevel = parseInt('{{{debuglevel}}}');
|
||
var features = parseInt('{{{features}}}');
|
||
var sessionTime = parseInt('{{{sessiontime}}}');
|
||
var domain = '{{{domain}}}';
|
||
var domainUrl = '{{{domainurl}}}';
|
||
var authCookie = '{{{authCookie}}}';
|
||
var authRelayCookie = '{{{authRelayCookie}}}';
|
||
var logoutControls = {{{logoutControls}}};
|
||
var authCookieRenewTimer = null;
|
||
var multiDesktop = {};
|
||
var multiDesktopFilter = null;
|
||
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
||
var amtScanResults = null;
|
||
var debugmode = 0;
|
||
var clickOnce = (((features & 256) != 0) && detectClickOnce());
|
||
var attemptWebRTC = ((features & 128) != 0);
|
||
var passRequirements = '{{{passRequirements}}}';
|
||
if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||
var deskAspectRatio = 0;
|
||
try { deskAspectRatio = parseInt(getstore('deskAspectRatio', '0')); } catch (ex) { }
|
||
var uiMode = parseInt(getstore('uiMode', 1));
|
||
var webPageStackMenu = false;
|
||
var webPageFullScreen = true;
|
||
var nightMode = (getstore('_nightMode', '0') == '1');
|
||
var sessionActivity = Date.now();
|
||
var updateSessionTimer = null;
|
||
var pluginHandlerBuilder = {{{pluginHandler}}};
|
||
var pluginHandler = null;
|
||
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
||
var installedPluginList = null;
|
||
var goBackStack = [];
|
||
|
||
// Console Message Display Timers
|
||
var p11DeskConsoleMsgTimer = null;
|
||
var p12TermConsoleMsgTimer = null;
|
||
var p13FilesConsoleMsgTimer = null;
|
||
|
||
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; }
|
||
}
|
||
|
||
// Check if we are in debug mode
|
||
args = parseUriArgs();
|
||
if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
|
||
debugmode = args.debug;
|
||
if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
|
||
QV('p13AutoConnect', debugmode); // Files
|
||
QV('autoconnectbutton2', debugmode); // Terminal
|
||
QV('autoconnectbutton1', debugmode); // Desktop
|
||
//QV('DeskClip', debugmode); // Clipboard feature, not completed so show in in debug mode only.
|
||
|
||
if (nightMode) { QC('body').add('night'); }
|
||
toggleFullScreen();
|
||
|
||
// Setup page visuals
|
||
var hide = 0;
|
||
var globalHide = parseInt('{{{hide}}}');
|
||
if (globalHide || args.hide) {
|
||
if (args.hide) { hide = parseInt(args.hide); }
|
||
if (globalHide) { hide = (hide | globalHide); }
|
||
}
|
||
args.hide = hide;
|
||
adjustPanels();
|
||
|
||
// Setup logout control
|
||
var logoutControl = '';
|
||
if (logoutControls.name != null) { logoutControl = format("{0}へようこそ。", logoutControls.name); }
|
||
if (logoutControls.logoutUrl != null) { logoutControl += format(' <a href=\"' + logoutControls.logoutUrl + '\" style="color:white">' + "ログアウト" + '</a>'); }
|
||
if (args.hide & 1) { QH('logoutControlSpan2', logoutControl); } else { QH('logoutControlSpan', logoutControl); }
|
||
|
||
// Setup the context menu
|
||
document.onclick = function (e) { hideContextMenu(); }
|
||
document.onkeypress = ondockeypress;
|
||
document.onkeydown = ondockeydown;
|
||
document.onkeyup = ondockeyup;
|
||
//window.addEventListener('focus', ondocfocus, false);
|
||
window.addEventListener('blur', ondocblur, false);
|
||
window.onresize = function () { masterUpdate(512); }
|
||
setTimeout(function() { masterUpdate(512); }, 200);
|
||
|
||
// Connect to the mesh server
|
||
meshserver = MeshServerCreateControl(domainUrl, authCookie);
|
||
meshserver.onStateChanged = onStateChanged;
|
||
meshserver.onMessage = onMessage;
|
||
meshserver.trace = (args.trace == 1);
|
||
meshserver.Start();
|
||
|
||
// Setup page controls
|
||
Q('sortselect').selectedIndex = sort = getstore('sort', 0);
|
||
Q('sizeselect').selectedIndex = getstore('_viewsize', 1);
|
||
Q('SearchInput').value = getstore('_search', '');
|
||
showRealNames = (getstore('showRealNames', 0) == 1);
|
||
Q('RealNameCheckBox').checked = showRealNames;
|
||
Q('viewselect').value = getstore('_deviceView', 1);
|
||
Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
|
||
QV('accountChangeEmailAddressSpan', (features & 0x200000) == 0);
|
||
|
||
// Display the page devices
|
||
masterUpdate(3)
|
||
for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
|
||
Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
|
||
|
||
// 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);
|
||
|
||
// Setup server stats panels
|
||
setupGeneralServerStats();
|
||
setupServerTimelineStats();
|
||
|
||
// Setup the user interface in the right mode
|
||
userInterfaceSelectMenu();
|
||
|
||
// Setup Mesh summary panel
|
||
setupMeshSummaryStats();
|
||
|
||
// If SSPI or LDAP authentication not used, allow batch account creation.
|
||
QV('p4UserBatchCreate', (features & 0x00080000) == 0);
|
||
|
||
// Set the file editor
|
||
d4EditWrapVal = getstore('editorWrap', 0);
|
||
d4EditSizeVal = getstore('editorSize', 0);
|
||
d4ToggleWrap(true);
|
||
d4ToggleSize(true);
|
||
}
|
||
|
||
function adjustPanels() {
|
||
var hide = args.hide;
|
||
QV('masthead', !(hide & 1));
|
||
QV('topbar', !(hide & 2));
|
||
QV('footer', !(hide & 4));
|
||
QV('p1title', !(hide & 8));
|
||
QV('p2title', !(hide & 8));
|
||
QV('p3title', !(hide & 8));
|
||
QV('p4title', !(hide & 8));
|
||
QV('p5title', !(hide & 8));
|
||
QV('p6title', !(hide & 8));
|
||
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));
|
||
QV('p17title', !(hide & 8));
|
||
QV('p20title', !(hide & 8));
|
||
QV('p21title', !(hide & 8));
|
||
QV('p30title', !(hide & 8));
|
||
QV('p31title', !(hide & 8));
|
||
QV('p40title', !(hide & 8));
|
||
QV('p41title', !(hide & 8));
|
||
//if (hide & 16) { QV('page_leftbar', false); QS('page_content').left = '0px'; }
|
||
|
||
if (hide != 0) {
|
||
// Fix the main grid to zero-height elements we want to hide.
|
||
if (uiMode == 2) {
|
||
QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px fit-content(48px) auto ' + ((hide & 4) ? '0' : '45') + 'px';
|
||
QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px fit-content(48px) auto ' + ((hide & 4) ? '0' : '45') + 'px';
|
||
} else {
|
||
QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
|
||
QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
|
||
}
|
||
}
|
||
|
||
// Adjust height of remote desktop, files and Intel AMT
|
||
// 1 = Top bar, 2 = Tool Bar, 4 = Bottom Bar, 8 = Tab Title
|
||
var xh = (((args.hide & 1) ? 0 : 66) + ((args.hide & 2) ? 0 : 24) + ((args.hide & 4) ? 0 : 45) + ((args.hide & 8) ? 0 : 60)); // 0 to 195
|
||
var xh2 = (uiMode > 1)?24:0;
|
||
QS('p3users')['max-height'] = 'calc(100vh - ' + (50 + xh) + 'px)'; // 124
|
||
QS('p3events')['height'] = 'calc(100vh - ' + (50 + xh) + 'px)'; // 124
|
||
QS('deskarea3x')['height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
|
||
QS('deskarea3x')['max-height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
|
||
QS('p5filetable')['height'] = 'calc(100vh - ' + (99 + xh) + 'px)'; // 160
|
||
QS('p13filetable')['height'] = 'calc(100vh - ' + (127 + xh + xh2) + 'px)'; // 124
|
||
QS('serverMainStats')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)'; // 110
|
||
QS('serverMainStats')['max-height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)'; // 110
|
||
QS('xdevices')['max-height'] = 'calc(100vh - ' + (46 + xh) + 'px)'; // 124
|
||
QS('xdevicesmap')['max-height'] = 'calc(100vh - ' + (46 + xh) + 'px)'; // 124
|
||
QS('p15agentConsole')['height'] = 'calc(100vh - ' + (84 + xh + xh2) + 'px)';
|
||
QS('p15agentConsole')['max-height'] = 'calc(100vh - ' + (84 + xh + xh2) + 'px)';
|
||
QS('p15agentConsoleText')['height'] = 'calc(100vh - ' + (81 + xh + xh2) + 'px)';
|
||
QS('p15agentConsoleText')['max-height'] = 'calc(100vh - ' + (81 + xh + xh2) + 'px)';
|
||
QS('p14iframe')['height'] = 'calc(100vh - ' + (23 + xh + xh2) + 'px)';
|
||
QS('p14iframe')['max-height'] = 'calc(100vh - ' + (23 + xh + xh2) + 'px)';
|
||
QS('p43iframe')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
|
||
QS('p43iframe')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
|
||
QS('p16events')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
|
||
QS('p16events')['max-height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
|
||
QS('p41events')['height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
|
||
QS('p41events')['max-height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
|
||
|
||
// We are looking at a single device, remove all the back buttons
|
||
if ('{{currentNode}}' != '') {
|
||
QV('p10BackButton', false);
|
||
QV('p11BackButton', false);
|
||
QV('p12BackButton', false);
|
||
QV('p13BackButton', false);
|
||
QV('p14BackButton', false);
|
||
QV('p15BackButton', false);
|
||
QV('p16BackButton', false);
|
||
}
|
||
p1updateInfo();
|
||
}
|
||
|
||
// Toggle the web page to full screen
|
||
function toggleAspectRatio(toggle) {
|
||
if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); putstore('deskAspectRatio', deskAspectRatio); }
|
||
deskAdjust();
|
||
}
|
||
|
||
// If FullScreen, toggle menu to be horizontal or vertical
|
||
function toggleStackMenu(toggle) {
|
||
if (webPageFullScreen == true) {
|
||
if (toggle === 1) {
|
||
webPageStackMenu = !webPageStackMenu;
|
||
putstore('webPageStackMenu', webPageStackMenu);
|
||
}
|
||
if (webPageStackMenu == false) {
|
||
QC('body').remove('menu_stack');
|
||
} else {
|
||
QC('body').add('menu_stack');
|
||
if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
|
||
}
|
||
deskAdjust();
|
||
}
|
||
}
|
||
|
||
// Toggle user interface menu
|
||
function showUserInterfaceSelectMenu() {
|
||
Q('uiViewButton1').classList.remove('uiSelectorSel');
|
||
Q('uiViewButton2').classList.remove('uiSelectorSel');
|
||
Q('uiViewButton3').classList.remove('uiSelectorSel');
|
||
Q('uiViewButton4').classList.remove('uiSelectorSel');
|
||
try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
|
||
QV('uiMenu', (QS('uiMenu').display == 'none'));
|
||
//Q('uiViewButton1').focus();
|
||
if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
|
||
}
|
||
|
||
function userInterfaceSelectMenu(s) {
|
||
if (s) { uiMode = s; putstore('uiMode', uiMode); }
|
||
webPageFullScreen = (uiMode < 3);
|
||
webPageStackMenu = (uiMode > 1);
|
||
toggleFullScreen(0);
|
||
toggleStackMenu(0);
|
||
if (webPageStackMenu && (xxcurrentView >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||
adjustPanels();
|
||
}
|
||
|
||
function toggleNightMode() {
|
||
nightMode = !nightMode;
|
||
if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
|
||
putstore('_nightMode', nightMode?'1':'0');
|
||
}
|
||
|
||
// Toggle the web page to full screen
|
||
function toggleFullScreen(toggle) {
|
||
if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
|
||
if (webPageFullScreen == false) {
|
||
QC('body').remove('menu_stack');
|
||
QC('body').remove('fullscreen');
|
||
QC('body').remove('arg_hide');
|
||
if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
|
||
QV('UserDummyMenuSpan', false);
|
||
//QV('page_leftbar', false);
|
||
} else {
|
||
QC('body').add('fullscreen');
|
||
if (args.hide & 16) QC('body').add('arg_hide'); // This is replacement for QV('page_leftbar', !(args.hide & 16));
|
||
QV('page_leftbar', !(args.hide & 16));
|
||
QV('MainMenuSpan', !(args.hide & 16));
|
||
if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
|
||
QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
|
||
}
|
||
masterUpdate(512);
|
||
QV('body', true);
|
||
}
|
||
|
||
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
||
function reload() {
|
||
var x = window.location.href;
|
||
if (x.endsWith('/#')) { x = x.substring(0, x.length - 2); }
|
||
window.location.href = x;
|
||
}
|
||
|
||
function onStateChanged(server, state, prevState, errorCode) {
|
||
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);
|
||
if (errorCode == 'noauth') { QH('p0span', "認証を実行できません"); return; }
|
||
if (prevState == 2) { if (autoReconnect) { setTimeout(serverPoll, 5000); } } else { QH('p0span', "Webソケットに接続できません"); }
|
||
if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
|
||
} else if (state == 2) {
|
||
// Fetch list of meshes, nodes, files
|
||
meshserver.send({ action: 'meshes' });
|
||
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
||
if (pluginHandler != null) { meshserver.send({ action: 'plugins' }); }
|
||
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
||
if ('{{viewmode}}' == '') { go(1); }
|
||
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
||
}
|
||
}
|
||
|
||
// Poll the server, if it responds, refresh the page.
|
||
function serverPoll() {
|
||
var 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('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0)); // Hide Account Security if in single user mode, domain authentication to 2 factor auth not supported.
|
||
QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
|
||
QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
|
||
QV('p2ServerActions', siteRights & 21);
|
||
QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
|
||
QV('MainMenuMyServer', siteRights & 21);
|
||
QV('p2ServerActionsBackup', siteRights & 1);
|
||
QV('p2ServerActionsRestore', siteRights & 4);
|
||
QV('p2ServerActionsVersion', siteRights & 16);
|
||
QV('MainMenuMyFiles', siteRights & 8);
|
||
QV('LeftMenuMyFiles', 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('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
|
||
QV('ServerTrace', userinfo.siteadmin === 0xFFFFFFFF);
|
||
if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
|
||
if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
|
||
|
||
// If we are site administrator, register to get server statistics
|
||
if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
|
||
}
|
||
|
||
// To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
|
||
var updateNaggleTimer = null;
|
||
var updateNaggleFlags = 0;
|
||
function masterUpdate(flags) {
|
||
updateNaggleFlags |= flags;
|
||
if (updateNaggleTimer == null) {
|
||
updateNaggleTimer = setTimeout(function () {
|
||
if (updateNaggleFlags & 512) { center(); }
|
||
if (updateNaggleFlags & 1) { onSearchInputChanged(); }
|
||
if (updateNaggleFlags & 2) { onSortSelectChange(false); }
|
||
if (updateNaggleFlags & 128) { updateMeshes(); }
|
||
if (updateNaggleFlags & 4) { updateDevices(); if (xxcurrentView == 21) { p21updateMesh(); } }
|
||
if (updateNaggleFlags & 8) { drawNotifications(); }
|
||
{{{StartGeoLocationJS}}}if (updateNaggleFlags & 16) { updateMapMarkers(); }{{{EndGeoLocationJS}}}
|
||
if (updateNaggleFlags & 32) { eventsUpdate(); }
|
||
{{{StartGeoLocationJS}}}if (updateNaggleFlags & 64) { refreshMap(false, true); }{{{EndGeoLocationJS}}}
|
||
if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
|
||
if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
|
||
if (updateNaggleFlags & 2048) { userEventsUpdate(); }
|
||
if (updateNaggleFlags & 4096) { p20updateMesh(); }
|
||
updateNaggleTimer = null;
|
||
updateNaggleFlags = 0;
|
||
}, 150);
|
||
}
|
||
}
|
||
|
||
var backupCodesWarningDone = false;
|
||
function updateSelf() {
|
||
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||
QV('manageOtp', (userinfo.otpsecret == 1) || (userinfo.otphkeys > 0));
|
||
QV('authAppSetupCheck', userinfo.otpsecret == 1);
|
||
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
||
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
||
masterUpdate(4 + 128 + 4096);
|
||
|
||
// Check if backup codes should really be enabled
|
||
if ((backupCodesWarningDone == false) && !(userinfo.otpkeys > 0) && (((userinfo.otpsecret == 1) && !(userinfo.otphkeys > 0)) || ((userinfo.otpsecret != 1) && (userinfo.otphkeys == 1)))) {
|
||
var n = { text: "二要素バックアップコードを追加してください。現在の要因が失われた場合、このアカウントを回復する方法はありません。", title: "二要素認証" };
|
||
addNotification(n);
|
||
backupCodesWarningDone = true;
|
||
}
|
||
|
||
// If we can't create new groups, hide all links that can do that.
|
||
var newGroupsAllowed = ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0));
|
||
QV('p2createMeshLink1', newGroupsAllowed);
|
||
QV('p2createMeshLink2', newGroupsAllowed);
|
||
QV('getStarted1', newGroupsAllowed);
|
||
QV('getStarted2', !newGroupsAllowed);
|
||
|
||
if (typeof userinfo.passchange == 'number') {
|
||
if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', " - 次回ログイン時にリセット。"); }
|
||
else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
|
||
var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
|
||
if (seconds < 0) { QH('p2nextPasswordUpdateTime', " - 次回ログイン時にリセット。"); }
|
||
else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', format(" - {0}分でリセット{1}。", Math.floor(seconds / 60), addLetterS(Math.floor(seconds / 60)))); }
|
||
else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', format(" - {0}時間でリセット{1}。", Math.floor(seconds / 3600), addLetterS(Math.floor(seconds / 3600)))); }
|
||
else { QH('p2nextPasswordUpdateTime', format(" - {0}日でリセット{1}。"), Math.floor(seconds / 86400), addLetterS(Math.floor(seconds / 86400))); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function addLetterS(x) { return (x > 1) ? 's' : ''; }
|
||
function setSessionActivity() { sessionActivity = Date.now(); QH('idleTimeoutNotify', ''); }
|
||
function checkIdleSessionTimeout() {
|
||
var delta = (Date.now() - sessionActivity);
|
||
if (delta > serverinfo.timeout) { window.location.href = 'logout'; } else {
|
||
var ds = Math.round((serverinfo.timeout - delta) / 1000);
|
||
if (ds <= 60) {
|
||
QH('idleTimeoutNotify', '<br />' + format("切断するまで{0}秒{1}", ds, addLetterS(ds)));
|
||
} else {
|
||
ds = Math.round(ds / 60);
|
||
if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + format("切断するまで{0}分{1}", ds, addLetterS(ds))); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function onMessage(server, message) {
|
||
switch (message.action) {
|
||
case 'trace': {
|
||
serverTrace.unshift(message);
|
||
displayServerTrace();
|
||
break;
|
||
}
|
||
case 'traceinfo': {
|
||
if (typeof message.traceSources == 'object') {
|
||
if ((message.traceSources != null) && (message.traceSources.length > 0)) {
|
||
serverTraceSources = message.traceSources;
|
||
QH('p41traceStatus', EscapeHtml(message.traceSources.join(', ')));
|
||
} else {
|
||
serverTraceSources = [];
|
||
QH('p41traceStatus', "なし");
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'serverstats': {
|
||
updateGeneralServerStats(message);
|
||
break;
|
||
}
|
||
case 'serverwarnings': {
|
||
if ((message.warnings != null) && (message.warnings.length > 0)) {
|
||
var x = '';
|
||
for (var i in message.warnings) { x += '<div style=color:red;padding-bottom:6px><b>' + "警告:" + message.warnings[i] + '</b></div>'; }
|
||
QH('serverWarnings', x);
|
||
QV('serverWarningsDiv', true);
|
||
}
|
||
break;
|
||
}
|
||
case 'servertimelinestats': {
|
||
setServerTimelineStats(message.events);
|
||
break;
|
||
}
|
||
case 'authcookie': {
|
||
// Got an authentication cookie refresh
|
||
authCookie = message.cookie;
|
||
authRelayCookie = message.rcookie;
|
||
break;
|
||
}
|
||
case 'serverinfo': {
|
||
serverinfo = message.serverinfo;
|
||
if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
|
||
if (debugmode == 1) { console.log('Server time: ', printDateTime(new Date(serverinfo.serverTime))); }
|
||
break;
|
||
}
|
||
case 'userinfo': {
|
||
userinfo = message.userinfo;
|
||
updateSiteAdmin();
|
||
updateSelf();
|
||
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]; }
|
||
masterUpdate(4 + 128);
|
||
break;
|
||
}
|
||
case 'files': {
|
||
filetree = setupBackPointers(message.filetree);
|
||
updateFiles();
|
||
d3updatefiles();
|
||
break;
|
||
}
|
||
case 'nodes': {
|
||
nodes = [];
|
||
for (var m in message.nodes) {
|
||
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
|
||
for (var n in message.nodes[m]) {
|
||
if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
|
||
message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
|
||
if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
|
||
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;
|
||
message.nodes[m][n].ip = message.nodes[m][n].ip;
|
||
if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
|
||
message.nodes[m][n].ident = ++nodeShortIdent;
|
||
nodes.push(message.nodes[m][n]);
|
||
}
|
||
}
|
||
masterUpdate(1 | 2 | 4 | 64);
|
||
|
||
if (xxcurrentView == -1) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } }
|
||
if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',parseInt('{{viewmode}}'));}
|
||
break;
|
||
}
|
||
case 'powertimeline': {
|
||
if (message.nodeid != powerTimelineReq) break;
|
||
powerTimelineNode = message.nodeid;
|
||
powerTimeline = message.timeline;
|
||
powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
|
||
for (var i in powerTimeline) { if (i % 2 == 1) { powerTimeline[i] = powerTimeline[i] * 1000; } } // Decompress time
|
||
if (currentNode._id == message.nodeid) { masterUpdate(256); }
|
||
break;
|
||
}
|
||
case 'getsysinfo': {
|
||
if (message.nodeid != powerTimelineReq) break;
|
||
//console.log('getsysinfo', message); // ***********************
|
||
if (message.noinfo === true) {
|
||
QH('p17info', "このデバイスに関する情報はありません。");
|
||
} else {
|
||
var x = '', s = {};
|
||
if (message.hardware) {
|
||
if (message.hardware.identifiers) {
|
||
var ident = message.hardware.identifiers;
|
||
// BIOS
|
||
x += '<div class=DevSt style=margin-bottom:3px><b>' + "BIOS" + '</b></div>';
|
||
if (ident.bios_vendor) { x += addDetailItem("ベンダー", ident.bios_vendor, s); }
|
||
if (ident.bios_version) { x += addDetailItem("バージョン", ident.bios_version, s); }
|
||
x += '<br />';
|
||
|
||
// Motherboard
|
||
x += '<div class=DevSt style=margin-bottom:3px><b>' + "マザーボード" + '</b></div>';
|
||
if (ident.board_vendor) { x += addDetailItem("ベンダー", ident.board_vendor, s); }
|
||
if (ident.board_name) { x += addDetailItem("名", ident.board_name, s); }
|
||
if (ident.board_serial && (ident.board_serial != '')) { x += addDetailItem("シリアル", ident.board_serial, s); }
|
||
if (ident.board_version) { x += addDetailItem("バージョン", ident.board_version, s); }
|
||
if (ident.product_uuid) { x += addDetailItem("識別子", ident.product_uuid, s); }
|
||
x += '<br />';
|
||
}
|
||
|
||
if (message.hardware.windows) {
|
||
if (message.hardware.windows.memory) {
|
||
// Memory
|
||
x += '<div class=DevSt style=margin-bottom:3px><b>' + "記憶" + '</b></div>';
|
||
|
||
// Sort Memory
|
||
function memorySort(a, b) { if (a.BankLabel > b.BankLabel) return 1; if (a.BankLabel < b.BankLabel) return -1; return 0; }
|
||
message.hardware.windows.memory.sort(memorySort);
|
||
|
||
x += '<table style=width:100%>';
|
||
for (var i in message.hardware.windows.memory) {
|
||
var m = message.hardware.windows.memory[i];
|
||
x += '<tr><td VALIGN=Top style=width:38px><img src="images/ram2.png" />'
|
||
x += '<td><div style=background-color:lightgray;border-radius:5px;padding:8px>';
|
||
x += '<div><b>' + m.BankLabel + '</b></div>';
|
||
if (m.Capacity) { x += addDetailItem("容量/速度", format("{0} Mb、{1} Mhz", (m.Capacity / 1024 / 1024), m.Speed), s); }
|
||
if (m.PartNumber) { x += addDetailItem("品番", ((m.Manufacturer && m.Manufacturer != 'Undefined')?(m.Manufacturer + ', '):'') + m.PartNumber, s); }
|
||
x += '</div>';
|
||
}
|
||
x += '</table><br />';
|
||
}
|
||
|
||
if (message.hardware.windows.osinfo) {
|
||
// Operating System
|
||
var m = message.hardware.windows.osinfo;
|
||
x += '<div class=DevSt style=margin-bottom:3px><b>' + "オペレーティング・システム" + '</b></div>';
|
||
if (m.Caption) { x += addDetailItem("名", m.Caption, s); }
|
||
if (m.Version) { x += addDetailItem("バージョン", m.Version, s); }
|
||
if (m.OSArchitecture) { x += addDetailItem("建築", m.OSArchitecture, s); }
|
||
x += '<br />';
|
||
}
|
||
|
||
// Disks
|
||
//x += '<div class=DevSt style=margin-bottom:3px><b>Disks</b></div>';
|
||
//x += '<br />';
|
||
}
|
||
}
|
||
|
||
QH('p17info', x);
|
||
}
|
||
break;
|
||
}
|
||
case 'lastconnect': {
|
||
var node = getNodeFromId(message.nodeid);
|
||
if (node != null) {
|
||
node.lastconnect = message.time;
|
||
node.lastaddr = message.addr;
|
||
if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
|
||
QH('MainComputerState', '<span>' + "最後に見たのは:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>');
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'msg': {
|
||
// Check if this is a message from a node
|
||
if (message.nodeid != null) {
|
||
var index = -1;
|
||
if (nodes != null) { 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, message.source); } // This is a console message.
|
||
else if (message.type == 'notify') { // This is a notification message.
|
||
var n = getstore('notifications', 0);
|
||
if (((n & 8) == 0) && (message.amtMessage != null)) { break; } // Intel AMT desktop & terminal messages should be ignored.
|
||
var n = { text: message.value, title: message.title, icon: message.icon };
|
||
if (message.nodeid != null) { n.nodeid = message.nodeid; }
|
||
if (message.tag != null) { n.tag = message.tag; }
|
||
if (message.username != null) { n.username = message.username; }
|
||
addNotification(n);
|
||
} else if (message.type == 'ps') {
|
||
showDeskToolsProcesses(message);
|
||
} else if (message.type == 'services') {
|
||
showDeskToolsServices(message);
|
||
} else if ((message.type == 'getclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
|
||
Q('d2clipText').value = message.data;
|
||
} else if ((message.type == 'setclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
|
||
// Display success/fail on the clipboard dialog box.
|
||
QH('dlgClipStatus', message.success ? '<span style=color:green>' + "成功" + '</span>' : '<span style=color:red>' + "失敗しました" + '</span>')
|
||
setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
|
||
} else if ((message.type == 'userSessions') && (currentNode != null) && (currentNode._id == message.nodeid) && (desktop == null)) {
|
||
// Got list of user sessions
|
||
var userSessions = [];
|
||
if (message.data != null) { for (var i in message.data) { if ((message.data[i].State == 'Active') || (message.data[i].StationName == 'Console') || (debugmode == 3)) { userSessions.push(message.data[i]); } } }
|
||
if (userSessions.length == 0) { connectDesktop(null, 1); } // No active sessions, do a normal connection.
|
||
else if (userSessions.length == 1) { connectDesktop(null, 1, userSessions[0].SessionId); } // One active session, connect to it
|
||
else {
|
||
var x = '';
|
||
for (var i in userSessions) {
|
||
x += '<div style="text-align:left;cursor:pointer;background-color:gray;margin:5px;padding:5px;border-radius:5px" onclick=connectDesktop(event,1,' + userSessions[i].SessionId + ')>' + userSessions[i].State + ', ' + userSessions[i].StationName;
|
||
if (userSessions[i].Username) { if (userSessions[i].Domain) { x += ' - ' + userSessions[i].Domain + '/' + userSessions[i].Username; } else { x += ' - ' + userSessions[i].Username; } }
|
||
x += '</div>';
|
||
}
|
||
QH('p11DeskSessionSelector', x);
|
||
QV('p11DeskSessionSelector', true);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if (message.type == 'notify') { // This is a notification message.
|
||
var n = { text: message.value, title: message.title, icon: message.icon };
|
||
if (message.tag != null) { n.tag = message.tag; }
|
||
if (message.username != null) { n.username = message.username; }
|
||
addNotification(n);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'getnetworkinfo': {
|
||
if ((currentNode._id == message.nodeid) && (xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
|
||
if (message.netif == null) {
|
||
QH('d2netinfo', "このデバイスで利用可能なネットワークインターフェイス情報はありません。");
|
||
} else {
|
||
var x = '<div class=dialogText>';
|
||
|
||
if (currentNode.lastconnect) { x += addHtmlValue2("最後のエージェント接続", printDateTime(new Date(currentNode.lastconnect))); }
|
||
if (currentNode.lastaddr) {
|
||
var splitip = currentNode.lastaddr.split(':');
|
||
if (splitip.length > 2) {
|
||
// IPv6
|
||
x += addHtmlValue2("最後のエージェントのアドレス", currentNode.lastaddr + ' <img src="images/link4.png" title="Copy address to clipboard" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(currentNode.lastaddr) + '\") width=10 height=10>');
|
||
} else {
|
||
// IPv4
|
||
if (isPrivateIP(currentNode.lastaddr)) {
|
||
x += addHtmlValue2("最後のエージェントのアドレス", splitip[0] + ' <img src="images/link4.png" title="' + "クリップボードにアドレスをコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(splitip[0]) + '\") width=10 height=10>');
|
||
} else {
|
||
x += addHtmlValue2("最後のエージェントのアドレス", '<a href="https://iplocation.com/?ip=' + splitip[0] + '" rel="noreferrer noopener" target="MeshIPLoopup">' + splitip[0] + '</a> <img src="images/link4.png" title="' + "クリップボードにアドレスをコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(splitip[0]) + '\") width=10 height=10>');
|
||
}
|
||
}
|
||
}
|
||
|
||
x += addHtmlValue2("最後のインターフェイスの更新", printDateTime(new Date(message.updateTime)));
|
||
for (var i in message.netif) {
|
||
var net = message.netif[i];
|
||
x += '<hr />'
|
||
if (net.name) { x += addHtmlValue2("名", '<b>' + EscapeHtml(net.name) + '</b>'); }
|
||
if (net.desc) { x += addHtmlValue2("説明", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
||
if (net.dnssuffix) { x += addHtmlValue2("DNSサフィックス", EscapeHtml(net.dnssuffix) + ' <img src="images/link4.png" title="' + "名前をクリップボードにコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.dnssuffix) + '\") width=10 height=10>'); }
|
||
if (net.mac) { x += addHtmlValue2("Macアドレス", '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "MACアドレスをクリップボードにコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.mac.toLowerCase()) + '\") width=10 height=10>'); }
|
||
if (net.v4addr) { x += addHtmlValue2("IPv4アドレス", EscapeHtml(net.v4addr) + ' <img src="images/link4.png" title="' + "クリップボードにアドレスをコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4addr) + '\") width=10 height=10>'); }
|
||
if (net.v4mask) { x += addHtmlValue2("IPv4マスク", EscapeHtml(net.v4mask) + ' <img src="images/link4.png" title="' + "クリップボードにアドレスをコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4mask) + '\") width=10 height=10>'); }
|
||
if (net.v4gateway) { x += addHtmlValue2("IPv4ゲートウェイ", EscapeHtml(net.v4gateway) + ' <img src="images/link4.png" title="' + "クリップボードにアドレスをコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4gateway) + '\") width=10 height=10>'); }
|
||
if (net.gatewaymac) { x += addHtmlValue2("ゲートウェイMAC", '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "MACアドレスをクリップボードにコピー" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.gatewaymac.toLowerCase()) + '\") width=10 height=10>'); }
|
||
}
|
||
x += '</div>';
|
||
QH('d2netinfo', x);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'serverversion': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
|
||
var x = '<div class=dialogText>';
|
||
if (!message.current) { message.current = "未知の"; }
|
||
if (!message.latest) { message.latest = "未知の"; }
|
||
x += addHtmlValue2("現行版", '<b>' + EscapeHtml(message.current) + '</b>');
|
||
x += addHtmlValue2("最新バージョン", '<b>' + EscapeHtml(message.latest) + '</b>');
|
||
x += '</div>';
|
||
if ((message.latest.indexOf('.') == -1) || (message.current == message.latest) || ((features & 2048) == 0)) {
|
||
setDialogMode(2, "MeshCentralバージョン", 1, null, x);
|
||
} else {
|
||
setDialogMode(2, "MeshCentralバージョン", 3, server_showVersionDlgEx, x + '<br /><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> ' + "チェックして[OK]をクリックし、サーバーの自己更新を開始します。" + '</label>');
|
||
server_showVersionDlgUpdate();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'servererrors': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
|
||
if (message.data == null) {
|
||
setDialogMode(2, "MeshCentralサーバーエラー", 1, null, "サーバーにはエラーログがありません。");
|
||
} else {
|
||
var x = '<div class="dialogText dialogTextLog"><pre id=d2ServerErrorsLogPre>' + message.data + '<pre></div>';
|
||
setDialogMode(2, "MeshCentralサーバーエラー", 3, server_showErrorsDlgEx, x + '<br /><div style=float:right><img src=images/link4.png height=10 width=10 title="' + "エラーログをダウンロードする" + '" style=cursor:pointer onclick=d2CopyServerErrorsToClip()></div><div><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> ' + "チェックして[OK]をクリックし、エラーログをクリアします。" + '</label></div>');
|
||
server_showVersionDlgUpdate();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'serverconsole': {
|
||
p15consoleReceive('serverconsole', message.value);
|
||
break;
|
||
}
|
||
case 'events': {
|
||
if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
|
||
currentDeviceEvents = message.events;
|
||
masterUpdate(1024);
|
||
} else if ((message.user != null) && (message.user == currentUser.name)) {
|
||
currentUserEvents = message.events;
|
||
masterUpdate(2048);
|
||
} else {
|
||
events = message.events;
|
||
masterUpdate(32);
|
||
}
|
||
break;
|
||
}
|
||
case 'getcookie': {
|
||
if (message.tag == 'clickonce') {
|
||
var basicPort = '{{{serverRedirPort}}}' == '' ? '{{{serverPublicPort}}}' : '{{{serverRedirPort}}}';
|
||
var rdpurl = 'http://' + window.location.hostname + ':' + basicPort + '/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F' + window.location.hostname + '%2Fmeshrelay.ashx%3Fauth=' + message.cookie + '&CH={{{webcerthash}}}&AP=' + message.protocol + ((debugmode == 1) ? '' : '&HOL=1');
|
||
var newWindow = window.open(rdpurl, '_blank');
|
||
newWindow.opener = null;
|
||
}
|
||
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 'otpauth-request': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
|
||
var secret = message.secret;
|
||
if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
|
||
else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
|
||
QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>' + "インストール<a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank> Google Authenticator </a>または互換性のあるアプリケーションでバーコードをスキャンするには、<a href=\"' + message.url +'\" rel=\"noreferrer noopener\" target=_blank>このリンク</a>を使用するか、秘密。次に、現在の6桁のトークンを入力して、2段階ログインを有効にします。" + '<br /><br />Secret<br /><tt id=d2optsecret secret=\"' + message.secret + '\" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />' + "2段階ログインのトークンをここに入力します。" + ' <input type=text onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
|
||
new QRCode(Q('qrcode'), { text: message.url, width: 128, height: 128, colorDark: '#000000', colorLight: '#EEE', correctLevel: QRCode.CorrectLevel.H });
|
||
QV('idx_dlgOkButton', true);
|
||
QE('idx_dlgOkButton', false);
|
||
Q('d2otpauthinput').focus();
|
||
}
|
||
break;
|
||
}
|
||
case 'otpauth-setup': {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "認証アプリ", 1, null, message.success ? ('<b style=color:green>' + "認証アプリのアクティベーションが成功しました。" + '</b> ' + "再度ログインするには、有効なトークンが必要になります。") : ('<b style=color:red>' + "2段階ログインのアクティベーションに失敗しました。" + '</b> ' + "アプリケーションから秘密をクリアして、再試行してください。適切なコードを入力するのに数分しかかかりません。"));
|
||
break;
|
||
}
|
||
case 'otpauth-clear': {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "認証アプリ", 1, null, message.success ? ('<b>' + "認証アプリケーションが削除されました。" + '</b> ' + "この機能はいつでも再アクティブ化できます。") : ('<b style=color:red>' + "2段階ログインアクティベーションの削除に失敗しました。" + '</b> ' + "再試行する。"));
|
||
break;
|
||
}
|
||
case 'otpauth-getpasswords': {
|
||
if (xxdialogMode) return;
|
||
var x = "ワンタイムトークンは、セカンダリ認証として使用できます。セットを生成して印刷し、安全な場所に保管してください。";
|
||
x += '<div style="border-radius:6px;border: 2px dashed #888;width:100%;margin-top:8px"><div style="padding:8px;font-family:Arial, Helvetica, sans-serif;font-size:20px;font-weight:bold"><table class=selecttext style=width:100%;text-align:center>';
|
||
if (message.passwords) {
|
||
var j = 0, clipb = '';
|
||
for (var i in message.passwords) {
|
||
if (++j % 2) { x += '<tr>'; }
|
||
var p = '' + message.passwords[i].p;
|
||
while (p.length < 8) { p = '0' + p; }
|
||
if (message.passwords[i].u === true) {
|
||
x += '<td>' + p.substring(0, 4) + ' ' + p.substring(4);
|
||
if (clipb != '') { clipb += ' '; }
|
||
clipb += p;
|
||
} else {
|
||
x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + ' ' + p.substring(4); + '</strike>';
|
||
}
|
||
}
|
||
} else {
|
||
x += '<tr><td>' + "アクティブなトークンがありません";
|
||
}
|
||
x += '</table></div></div><br />';
|
||
x += '<div><input type=button value=' + "閉じる" + ' onclick=setDialogMode(0) style=float:right></input>';
|
||
x += '<input type=button value="' + "新しいトークンを生成する" + '" onclick="account_manageOtp(1);"></input>';
|
||
if (message.passwords != null) {
|
||
x += '<input type=button value="' + "クリアトークン" + '" onclick="account_manageOtp(2);"></input>';
|
||
x += ' <img src=images/link4.png height=10 width=10 title="' + "有効なコードをクリップボードにコピー" + '" style=cursor:pointer onclick=copyTextToClip2("' + encodeURIComponent(clipb) + '")>';
|
||
}
|
||
x += '</div><br />';
|
||
setDialogMode(2, "バックアップコードの管理", 8, null, x, 'otpauth-manage');
|
||
break;
|
||
}
|
||
case 'otp-hkey-get': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
var start = '<div style="border-radius:6px;border:2px solid #CCC;background-color:#BBB;width:100%;box-sizing:border-box;margin-bottom:6px"><div style="margin:3px;font-family:Arial, Helvetica, sans-serif;font-size:16px;font-weight:bold"><table style=width:100%;text-align:left>';
|
||
var end = '</table></div></div>';
|
||
var x = "<a href=\"https://www.yubico.com/\" rel=\"noreferrer noopener\" target=\"_blank\">ハードウェアキー</a>は、セカンダリログイン認証として使用されます。";
|
||
x += '<div style="max-height:150px;overflow-y:auto;overflow-x:hidden;margin-top:6px;margin-bottom:6px">';
|
||
if (message.keys && message.keys.length > 0) {
|
||
for (var i in message.keys) {
|
||
var key = message.keys[i], type = (key.type == 2)?'OTP':'WebAuthn';
|
||
x += start + '<tr style=margin:5px><td style=width:30px><img width=24 height=18 src="images/hardware-key-' + type + '-24.png" style=margin-top:4px><td style=width:250px>' + key.name + '<td><input type=button value="' + "削除する" + '" onclick=account_removehkey(' + key.i + ')></input>' + end;
|
||
}
|
||
} else {
|
||
x += start + '<tr style=text-align:center><td>' + "キーが設定されていません" + end;
|
||
}
|
||
x += '</div>';
|
||
x += '<div><input type=button value="' + "閉じる" + '" onclick=setDialogMode(0) style=float:right></input>';
|
||
if ((features & 0x00020000) != 0) { x += '<input id=d2addkey3 type=button value="' + "キーを追加" + '" onclick="account_addhkey(3);"></input>'; }
|
||
if ((features & 0x00004000) != 0) { x += '<input id=d2addkey2 type=button value="' + "YubiKey®を追加OTP" + '" onclick="account_addhkey(2);"></input>'; }
|
||
x += '</div><br />';
|
||
setDialogMode(2, "セキュリティキーを管理する", 8, null, x, 'otpauth-hardware-manage');
|
||
if (u2fSupported() == false) { QE('d2addkey1', false); }
|
||
break;
|
||
}
|
||
case 'otp-hkey-yubikey-add': {
|
||
if (message.result) {
|
||
meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
|
||
} else {
|
||
setDialogMode(2, "セキュリティキーを追加", 1, null, '<br />' + "エラー、キーを追加できません。" + '<br /><br />');
|
||
}
|
||
break;
|
||
}
|
||
case 'otp-hkey-setup-response': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
if (message.result == true) {
|
||
meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
|
||
} else {
|
||
setDialogMode(2, "セキュリティキーを追加", 1, null, '<br />' + "エラー:キーを追加できません。" + '<br /><br />', 'otpauth-hardware-manage');
|
||
}
|
||
break;
|
||
}
|
||
case 'webauthn-startregister': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
var x = "ここでキーボタンを押します。" + '<br /><br /><div style=width:100%;text-align:center><img width=120 height=117 src="images/hardware-keypress-120.png" /></div><input id=dp1keyname style=display:none value=' + message.name + ' />';
|
||
setDialogMode(2, "セキュリティキーを追加", 2, null, x);
|
||
|
||
var publicKey = message.request;
|
||
message.request.challenge = Uint8Array.from(atob(message.request.challenge), function (c) { return c.charCodeAt(0) })
|
||
message.request.user.id = Uint8Array.from(atob(message.request.user.id), function (c) { return c.charCodeAt(0) })
|
||
navigator.credentials.create({ publicKey: publicKey })
|
||
.then(function(newCredentialInfo) {
|
||
// Public key credential
|
||
var r = { rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.rawId))), response: { attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.attestationObject))), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.clientDataJSON))) }, type: newCredentialInfo.type };
|
||
meshserver.send({ action: 'webauthn-endregister', response: r });
|
||
setDialogMode(0);
|
||
}, function(error) {
|
||
// Error
|
||
setDialogMode(2, "セキュリティキーを追加", 1, null, "エラー:" + error);
|
||
});
|
||
break;
|
||
}
|
||
case 'event': {
|
||
if (!message.event.nolog) {
|
||
if (currentNode && (message.event.nodeid == currentNode._id)) {
|
||
// If this event has a nodeid and we are looking at this node, update the log in real time.
|
||
currentDeviceEvents.unshift(message.event);
|
||
var eventLimit = parseInt(p16limitdropdown.value);
|
||
while (currentDeviceEvents.length > eventLimit) { currentDeviceEvents.pop(); } // Remove element(s) at the end
|
||
masterUpdate(1024);
|
||
}
|
||
|
||
if (currentUser && (message.event.userid == currentUser._id)) {
|
||
// If this event has a userid and we are looking at this user, update the log in real time.
|
||
currentUserEvents.unshift(message.event);
|
||
var eventLimit = parseInt(p31limitdropdown.value);
|
||
while (currentUserEvents.length > eventLimit) { currentUserEvents.pop(); } // Remove element(s) at the end
|
||
masterUpdate(2048);
|
||
}
|
||
|
||
// Add this event to the master events log.
|
||
events.unshift(message.event);
|
||
var eventLimit = parseInt(p3limitdropdown.value);
|
||
while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
|
||
masterUpdate(32);
|
||
}
|
||
if (message.event.noact) break; // Take no action on this event
|
||
switch (message.event.action) {
|
||
case 'userWebState': {
|
||
// New user web state, update the web page as needed
|
||
if (localStorage != null) {
|
||
var oldShowRealNames = localStorage.getItem('showRealNames');
|
||
var oldUiMode = localStorage.getItem('uiMode');
|
||
var oldSort = localStorage.getItem('sort');
|
||
var oldLoctag = localStorage.getItem('loctag');
|
||
|
||
var webstate = JSON.parse(message.event.state);
|
||
for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
|
||
|
||
// Update the web page
|
||
if ((webstate.deskAspectRatio != null) && (webstate.deskAspectRatio != deskAspectRatio)) { deskAspectRatio = webstate.deskAspectRatio; deskAdjust(); }
|
||
if ((webstate.showRealNames != null) && (webstate.showRealNames != oldShowRealNames)) { showRealNames = Q('RealNameCheckBox').checked = (webstate.showRealNames == '1'); masterUpdate(6); }
|
||
if ((webstate.uiMode != null) && (webstate.uiMode != oldUiMode)) { userInterfaceSelectMenu(parseInt(webstate.uiMode)); }
|
||
if ((webstate.sort != null) && (webstate.sort != oldSort)) { document.getElementById('sortselect').selectedIndex = sort = parseInt(webstate.sort); masterUpdate(6); }
|
||
if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) { if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; } masterUpdate(0xFFFFFFFF); }
|
||
}
|
||
break;
|
||
}
|
||
case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
|
||
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' }); }
|
||
var oldgroups = userinfo.groups;
|
||
userinfo = message.event.account;
|
||
if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
|
||
updateSelf();
|
||
|
||
if ((userinfo.siteadmin & 2) != 0) {
|
||
// Compare our groups
|
||
var og = oldgroups ? oldgroups : [];
|
||
var ng = userinfo.groups ? userinfo.groups : [];
|
||
if (og.join(',') != ng.join(',')) {
|
||
// Our groups have changed, re-ask for a list of users.
|
||
users = wssessions = null;
|
||
meshserver.send({ action: 'users' });
|
||
meshserver.send({ action: 'wssessioncount' });
|
||
}
|
||
}
|
||
}
|
||
if (users == null) break;
|
||
|
||
// Check if the account is part of our user group
|
||
if ((userinfo.groups == null) || (userinfo.groups.length == 0) || (findOne(message.event.account.groups, userinfo.groups) == true)) {
|
||
users[message.event.account._id] = message.event.account; // Part of our groups, update this user.
|
||
} else {
|
||
delete users[message.event.account._id]; // No longer part of our groups, remove this user.
|
||
}
|
||
|
||
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 ((meshes[message.event.meshid] == null) && (message.event.links[userinfo._id] != null)) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
|
||
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
|
||
masterUpdate(4 + 128);
|
||
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
|
||
if (message.event.name != null) {
|
||
meshes[message.event.meshid].name = message.event.name;
|
||
for (var i in nodes) { if (nodes[i].meshid == message.event.meshid) { nodes[i].meshnamel = message.event.name.toLowerCase(); } }
|
||
}
|
||
if (message.event.desc != null) { meshes[message.event.meshid].desc = message.event.desc; }
|
||
if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
|
||
if (message.event.consent != null) { meshes[message.event.meshid].consent = message.event.consent; }
|
||
if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
|
||
if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; }
|
||
|
||
// Check if we lost rights to this mesh in this change.
|
||
if (meshes[message.event.meshid].links[userinfo._id] == 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); }
|
||
}
|
||
}
|
||
masterUpdate(4 + 128);
|
||
if (currentNode && (currentNode.meshid == message.event.meshid)) { currentNode = null; if ((xxcurrentView >= 10) && (xxcurrentView < 20)) { go(1); } }
|
||
//meshserver.send({ action: 'files' }); // TODO: Why do we need to do this??
|
||
|
||
// If we are looking at a mesh that is now deleted, move back to "My Account"
|
||
if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { masterUpdate(4096); }
|
||
break;
|
||
}
|
||
case 'deletemesh': {
|
||
// Delete the mesh
|
||
if (meshes[message.event.meshid]) {
|
||
delete meshes[message.event.meshid];
|
||
masterUpdate(128);
|
||
meshserver.send({ action: 'files' });
|
||
}
|
||
|
||
// Delete all nodes in that mesh
|
||
var newnodes = [];
|
||
if (nodes != null) { for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } } }
|
||
nodes = newnodes;
|
||
masterUpdate(4);
|
||
|
||
// 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.
|
||
if (getNodeFromId(node._id) != null) break; // This node is already known.
|
||
node.namel = node.name.toLowerCase();
|
||
if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
node.meshnamel = meshes[node.meshid].name.toLowerCase();
|
||
node.state = 0;
|
||
if (!node.icon) node.icon = 1;
|
||
node.ident = ++nodeShortIdent;
|
||
if (nodes == null) { }
|
||
nodes.push(node);
|
||
|
||
// Web page update
|
||
masterUpdate(1 | 2 | 4 | 16);
|
||
|
||
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); }
|
||
currentNode = null;
|
||
// TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
|
||
}
|
||
nodes.splice(index, 1);
|
||
|
||
// Web page update
|
||
masterUpdate(4 | 16);
|
||
}
|
||
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.rname = message.event.node.rname;
|
||
node.users = message.event.node.users;
|
||
node.host = message.event.node.host;
|
||
node.desc = message.event.node.desc;
|
||
node.ip = message.event.node.ip;
|
||
node.osdesc = message.event.node.osdesc;
|
||
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.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
|
||
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.tag != null) { node.intelamt.tag = message.event.node.intelamt.tag; }
|
||
if (message.event.node.intelamt.uuid != null) { node.intelamt.uuid = message.event.node.intelamt.uuid; }
|
||
if (message.event.node.intelamt.realm != null) { node.intelamt.realm = message.event.node.intelamt.realm; }
|
||
}
|
||
if (message.event.node.av != null) { node.av = message.event.node.av; }
|
||
node.namel = node.name.toLowerCase();
|
||
if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
if (message.event.node.icon) { node.icon = message.event.node.icon; }
|
||
|
||
// Web page update
|
||
masterUpdate(2 | 4 | 8 | 16);
|
||
refreshDevice(node._id);
|
||
|
||
if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
|
||
}
|
||
break;
|
||
}
|
||
case 'nodemeshchange': {
|
||
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 (meshes[message.event.newMeshId] == null) {
|
||
// We don't see the new mesh, remove this device
|
||
|
||
// TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
|
||
if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } currentNode = null; }
|
||
nodes.splice(index, 1);
|
||
masterUpdate(4 | 16);
|
||
} else {
|
||
// We see the new mesh, move this device
|
||
node.meshid = message.event.newMeshId;
|
||
node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
|
||
masterUpdate(1 | 2 | 4);
|
||
}
|
||
refreshDevice(message.event.nodeid);
|
||
} else {
|
||
// This is a new device, add it.
|
||
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.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
node.meshnamel = meshes[node.meshid].name.toLowerCase();
|
||
node.state = 0;
|
||
if (!node.icon) node.icon = 1;
|
||
node.ident = ++nodeShortIdent;
|
||
if (nodes == null) { }
|
||
nodes.push(node);
|
||
|
||
// Web page update
|
||
masterUpdate(1 | 2 | 4 | 16);
|
||
}
|
||
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];
|
||
|
||
// Event the connection change if needed
|
||
var n = getstore('notifications', 0); // Account notification settings
|
||
|
||
// Per-group notification settings
|
||
if (message.event.meshid && userinfo.links && userinfo.links[message.event.meshid] && userinfo.links[message.event.meshid].notify) {
|
||
n &= userinfo.links[message.event.meshid].notify;
|
||
} else {
|
||
n = 0;
|
||
}
|
||
|
||
// Show the notification
|
||
if (n & 2) {
|
||
if (((node.conn & 1) == 0) && ((message.event.conn & 1) != 0)) { addNotification({ text: "接続されたエージェント", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 2) == 0) && ((message.event.conn & 2) != 0)) { addNotification({ text: "Intel AMTが検出されました", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 4) == 0) && ((message.event.conn & 4) != 0)) { addNotification({ text: "Intel AMT CIRAが接続されました", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 16) == 0) && ((message.event.conn & 16) != 0)) { addNotification({ text: "MQTT接続済み", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
}
|
||
if (n & 4) {
|
||
if (((node.conn & 1) != 0) && ((message.event.conn & 1) == 0)) { addNotification({ text: "エージェントが切断されました", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 2) != 0) && ((message.event.conn & 2) == 0)) { addNotification({ text: "Intel AMTが検出されません", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 4) != 0) && ((message.event.conn & 4) == 0)) { addNotification({ text: "Intel AMT CIRAが切断されました", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
if (((node.conn & 16) != 0) && ((message.event.conn & 16) == 0)) { addNotification({ text: "MQTTが切断されました", title: node.name, icon: node.icon, nodeid: node._id }); }
|
||
}
|
||
|
||
// Change the node connection state
|
||
node.conn = message.event.conn;
|
||
node.pwr = message.event.pwr;
|
||
|
||
// Web page update
|
||
masterUpdate(4 | 16);
|
||
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 'login': {
|
||
// Update the last login time
|
||
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
|
||
users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
|
||
}
|
||
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>' + "このアドレス範囲をスキャンできません。" + '</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>' + "サンプルIP範囲値<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 += " TLSを使用。"; } else { str += " 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, title: message.event.title, icon: message.event.icon };
|
||
if (message.event.tag != null) { n.tag = message.event.tag; }
|
||
addNotification(n);
|
||
break;
|
||
}
|
||
case 'traceinfo': {
|
||
if (typeof message.event.traceSources == 'object') {
|
||
if ((message.event.traceSources != null) && (message.event.traceSources.length > 0)) {
|
||
serverTraceSources = message.event.traceSources;
|
||
QH('p41traceStatus', EscapeHtml(message.event.traceSources.join(', ')));
|
||
} else {
|
||
serverTraceSources = [];
|
||
QH('p41traceStatus', "なし");
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'sysinfohash': {
|
||
// If the sysinfo document has changed and we are looking at it, request an update.
|
||
if ((currentNode != null) && (message.event.nodeid == powerTimelineReq)) {
|
||
meshserver.send({ action: 'getsysinfo', nodeid: message.event.nodeid });
|
||
}
|
||
break;
|
||
}
|
||
case 'stopped': { // Server is stopping.
|
||
// Disconnect
|
||
//console.log(message.msg);
|
||
break;
|
||
}
|
||
case 'updatePluginList': {
|
||
installedPluginList = message.event.list;
|
||
updatePluginList();
|
||
break;
|
||
}
|
||
case 'pluginStateChange': {
|
||
if (pluginHandler == null) break;
|
||
pluginHandler.refreshPluginHandler();
|
||
break;
|
||
}
|
||
case 'plugin': {
|
||
if (pluginHandler == null) break;
|
||
try { pluginHandler[message.event.plugin][message.event.pluginaction](message); } catch (e) { console.log("PluginHandler could not event message: ", e); }
|
||
break;
|
||
}
|
||
default:
|
||
//console.log('Unknown message.event.action', message.event.action);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case 'createInviteLink': { // Agent installation invitation link
|
||
if (xxdialogTag != message.meshid) break;
|
||
var servername = serverinfo.name;
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||
var url;
|
||
if (serverinfo.https == true) {
|
||
var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
|
||
url = 'https://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie;
|
||
} else {
|
||
var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
|
||
url = 'http://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie;
|
||
}
|
||
Q('agentInvitationLink').href = url;
|
||
var t = format("{0}時間{1}", message.expire, addLetterS(message.expire));
|
||
if (message.expire == 24) { t = "1日"; }
|
||
if (message.expire == 168) { t = "1週間"; }
|
||
if (message.expire == 5040) { t = "1ヶ月"; }
|
||
if (message.expire == 0) { t = "無制限"; }
|
||
QH('agentInvitationLink', format("招待リンク({0})", t));
|
||
QV('agentInvitationLinkDiv', true);
|
||
break;
|
||
}
|
||
case 'getmqttlogin': {
|
||
if ((currentNode == null) || (currentNode._id != message.nodeid) || (xxdialogMode != null)) return;
|
||
var x = "これらの設定を使用して、このデバイスのMQTTを接続できます。" + '<br /><br />';
|
||
delete message.action;
|
||
delete message.nodeid;
|
||
x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>' + JSON.stringify(message) + '</textarea>';
|
||
/*
|
||
x += addHtmlValue('Username', '<input style=width:230px readonly value="' + message.user + '" />');
|
||
x += addHtmlValue('Password', '<input style=width:230px readonly value="' + message.pass + '" />');
|
||
x += addHtmlValue('WS URL', '<input style=width:230px readonly value="' + message.wsUrl + '" />');
|
||
if (message.mpsUrl && message.mpsCertHash) {
|
||
x += addHtmlValue('MPS URL', '<input style=width:230px readonly value="' + message.mpsUrl + '" />');
|
||
x += addHtmlValue('MPS Cert Hash', '<input style=width:230px readonly value="' + message.mpsCertHash + '" />');
|
||
}
|
||
*/
|
||
setDialogMode(2, "MQTT資格情報", 1, null, x);
|
||
break;
|
||
}
|
||
case 'stopped': { // Server is stopping.
|
||
// Disconnect
|
||
autoReconnect = false;
|
||
QH('p0span', message.msg);
|
||
break;
|
||
}
|
||
case 'updatePluginList': {
|
||
installedPluginList = message.list;
|
||
updatePluginList();
|
||
break;
|
||
}
|
||
case 'pluginVersionsAvailable': {
|
||
if (pluginHandler == null) break;
|
||
updatePluginList(message.list);
|
||
break;
|
||
}
|
||
case 'downgradePluginVersions': {
|
||
var vSelect = '<select id="lastPluginVersion">';
|
||
message.info.versionList.forEach(function(v) { vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>'; });
|
||
vSelect += '</select>';
|
||
setDialogMode(2, "プラグインアクション", 3, pluginActionEx, format('Select the version to downgrade the plugin: {0}', message.info.name) + '<hr />' + vSelect + '<hr />' + "ダウングレードは推奨されないことに注意してください。最近のアップグレードで何かが壊れた場合にのみ行ってください。" + + '<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
|
||
break;
|
||
}
|
||
case 'pluginError': {
|
||
setDialogMode(2, "プラグインエラー", 1, null, message.msg);
|
||
break;
|
||
}
|
||
case 'plugin': {
|
||
if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
|
||
try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
|
||
break;
|
||
}
|
||
default:
|
||
//console.log('Unknown message.action', message.action);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// MY DEVICES
|
||
//
|
||
|
||
function onRealNameCheckBox() {
|
||
showRealNames = Q('RealNameCheckBox').checked;
|
||
putstore('showRealNames', showRealNames ? 1 : 0);
|
||
masterUpdate(6);
|
||
return;
|
||
}
|
||
|
||
function onDeviceViewChange(i) {
|
||
if (i != null) { Q('viewselect').value = i; }
|
||
for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
|
||
Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
|
||
putstore('_deviceView', Q('viewselect').value);
|
||
putstore('_viewsize', Q('sizeselect').value);
|
||
masterUpdate(4);
|
||
setTimeout(function () { masterUpdate(512); }, 200);
|
||
}
|
||
|
||
function ondockeypress(e) {
|
||
setSessionActivity();
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
|
||
if (inputAllowed == false) return false;
|
||
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
|
||
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
|
||
}
|
||
return desktop.m.handleKeys(e);
|
||
}
|
||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeys(e); }
|
||
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
|
||
if (!xxdialogMode && xxcurrentView == 4) {
|
||
if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||
var processed = 0;
|
||
if (e.key) {
|
||
if (e.key.length === 1 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + e.key)); processed = 1; }
|
||
if (e.keyCode == 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = x.substring(0, x.length - 1); processed = 1; }
|
||
if (e.keyCode == 27) { Q('UserSearchInput').value = ''; processed = 1; }
|
||
} else {
|
||
if (e.charCode != 0 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
|
||
}
|
||
if (processed > 0) { if (processed == 1) { onUserSearchInputChanged(); } return haltEvent(e); }
|
||
}
|
||
if (xxdialogMode || xxcurrentView != 1) return;
|
||
if (e.ctrlKey == true && e.charCode == 96) {
|
||
showRealNames = !showRealNames;
|
||
Q('RealNameCheckBox').value = showRealNames;
|
||
putstore('showRealNames', showRealNames ? 1 : 0);
|
||
masterUpdate(6)
|
||
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) { masterUpdate(5); } 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) {
|
||
setSessionActivity();
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
|
||
if (inputAllowed == false) return false;
|
||
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
|
||
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
|
||
}
|
||
return desktop.m.handleKeyDown(e);
|
||
}
|
||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { terminal.m.TermHandleKeyDown(e); if ((e.keyCode >= 37) && (e.keyCode <= 40)) { haltEvent(e); } }
|
||
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
|
||
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
|
||
if (!xxdialogMode && xxcurrentView == 4) {
|
||
if (e.keyCode === 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
|
||
if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
|
||
if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(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) { masterUpdate(5); } 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) {
|
||
setSessionActivity();
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
|
||
if (inputAllowed == false) return false;
|
||
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
|
||
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
|
||
}
|
||
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 && xxcurrentView == 4) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
|
||
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); } }
|
||
}
|
||
|
||
//function ondocfocus() { }
|
||
// TODO: Add handleReleaseKeys() for Intel AMT.
|
||
function ondocblur() { if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked && desktop.m.handleReleaseKeys) { return desktop.m.handleReleaseKeys(); } }
|
||
|
||
// Highlights the device being hovered
|
||
function devMouseHover(element, over) {
|
||
setSessionActivity();
|
||
var view = Q('viewselect').value;
|
||
if (view == 1) {
|
||
var e = element.children[1].children[1];
|
||
e.children[0].classList.remove('g1s');
|
||
e.children[1].classList.remove('e2s');
|
||
e.children[2].classList.remove('g2s');
|
||
if (over == 1) {
|
||
e.children[0].classList.add('g1s');
|
||
e.children[1].classList.add('e2s');
|
||
e.children[2].classList.add('g2s');
|
||
}
|
||
} else if (view == 2) {
|
||
var e = element;
|
||
e.children[2].classList.remove('g1s');
|
||
e.children[4].classList.remove('e2s');
|
||
e.children[3].classList.remove('g2s');
|
||
if (over == 1) {
|
||
e.children[2].classList.add('g1s');
|
||
e.children[4].classList.add('e2s');
|
||
e.children[3].classList.add('g2s');
|
||
}
|
||
}
|
||
}
|
||
|
||
var deviceHeaderId = 0;
|
||
var deviceHeaderTotal = 0;
|
||
var deviceHeadersTitles = {};
|
||
var deviceHeaderCount;
|
||
var deviceHeaders = {};
|
||
var oldviewmode = 0;
|
||
function updateDevices() {
|
||
if (nodes == null) { return; }
|
||
var r = '', c = 0, current = null, count = 0, scount = 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('devListToolbarViewIcons', (meshcount != 0) && (nodes.length > 0));
|
||
QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
|
||
if ((meshcount == 0) || (nodes.length == 0)) { view = 1; sort = 0; }
|
||
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 = [];
|
||
|
||
// Perform node sort
|
||
if (sort == 0) { nodes.sort(meshSort); }
|
||
else if (sort == 1) { nodes.sort(powerSort); }
|
||
else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
|
||
|
||
// Save the list of currently checked nodeid's
|
||
var checkedNodeids = [], elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
|
||
if ((oldviewmode < 3) && (view == 3)) { multiDesktopFilter = checkedNodeids; }
|
||
else if ((oldviewmode == 3) && (view < 3)) { checkedNodeids = multiDesktopFilter; }
|
||
|
||
// Compute the width of the device view.
|
||
var totalDeviceViewWidth = Q('column_l').clientWidth - 60;
|
||
var deviceBoxWidth = Math.floor(totalDeviceViewWidth / 301);
|
||
deviceBoxWidth = 301 + Math.floor((totalDeviceViewWidth - (deviceBoxWidth * 301)) / deviceBoxWidth);
|
||
|
||
// Go thru the list of nodes and display them
|
||
for (var i in nodes) {
|
||
var node = nodes[i];
|
||
if (node.v == false) continue;
|
||
var mesh2 = meshes[node.meshid], meshlinks = mesh2.links[userinfo._id];
|
||
if (meshlinks == null) continue;
|
||
var meshrights = meshlinks.rights;
|
||
if ((view == 3) && (mesh2.mtype == 1)) continue;
|
||
if (sort == 0) {
|
||
// Mesh header
|
||
if (node.meshid != current) {
|
||
deviceHeaderSet();
|
||
var extra = '';
|
||
if (view == 2) { r += '<tr><td colspan=5>'; }
|
||
if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>' + "、Intel® AMTのみ" + '</span>'; }
|
||
if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
|
||
if (view == 2) { r += '<div>'; }
|
||
r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
|
||
r += '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span>' + extra;
|
||
r += '</span><span id=MxMESH tabindex=0 style=cursor:pointer onclick=gotoMesh("' + node.meshid + '") onkeypress="if (event.key==\'Enter\') gotoMesh(\'' + node.meshid + '\')">' + EscapeHtml(meshes[node.meshid].name) + '</span>' + getMeshActions(mesh2, meshrights) + '</div>';
|
||
if (view == 2) { r += '</div>'; }
|
||
current = node.meshid;
|
||
displayedMeshes[current] = 1;
|
||
c = 0;
|
||
}
|
||
} else if (sort == 1) {
|
||
// Power header
|
||
var pwr = node.pwr?node.pwr:0;
|
||
if (pwr !== current) {
|
||
deviceHeaderSet();
|
||
if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
|
||
|
||
if (view == 2) { r += '<tr><td>'; }
|
||
r += '<div class=DevSt style=width:100%;padding-top:4px><span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx style=float:right></span><span>' + PowerStateStr2(node.pwr) + '</span></div>';
|
||
|
||
current = pwr;
|
||
c = 0;
|
||
}
|
||
} else if (sort == 2) {
|
||
// Device header
|
||
if (current == null) { current = '1'; }
|
||
}
|
||
|
||
count++;
|
||
var title = EscapeHtml(node.name);
|
||
if (title.length == 0) { title = '<i>' + "なし" + '</i>'; }
|
||
if ((node.rname != null) && (node.rname.length > 0)) { title += ' / ' + EscapeHtml(node.rname); }
|
||
var name = EscapeHtml(node.name);
|
||
if (showRealNames == true && node.rname != null) name = EscapeHtml(node.rname);
|
||
if (name.length == 0) { name = '<i>' + "なし" + '</i>'; }
|
||
|
||
// Node
|
||
var icon = node.icon;
|
||
if ((!node.conn) || (node.conn == 0)) { icon += ' gray'; }
|
||
if (view == 1) {
|
||
r += '<div id=devs onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div><div style=height:100%;cursor:pointer tabindex=0 onclick=gotoDevice(\'' + node._id + '\',null,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)"><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 style=width:' + (deviceBoxWidth - 100) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></div><div class=g2></div></div></div></div>';
|
||
} else if (view == 2) {
|
||
var states = [];
|
||
if (node.conn) {
|
||
if ((node.conn & 1) != 0) { states.push('<span title=\"' + "メッシュエージェントが接続され、使用できる状態になりました。" + '\">' + "エージェント" + '</span>'); }
|
||
if ((node.conn & 2) != 0) { states.push('<span title=\"' + "Intel® AMT CIRAが接続され、使用できる状態になりました。" + '\">' + "CIRA" + '</span>'); }
|
||
else if ((node.conn & 4) != 0) { states.push('<span title=\"' + "Intel® AMTはルーティング可能です。" + '\">' + "AMT" + '</span>'); }
|
||
if ((node.conn & 8) != 0) { states.push('<span title=\"' + "メッシュエージェントは、別のエージェントをリレーとして使用して到達可能です。" + '\">' + "リレー" + '</span>'); }
|
||
if ((node.conn & 16) != 0) { states.push('<span title=\"' + "デバイスへのMQTT接続がアクティブです。" + '\">' + "MQTT" + '</span>'); }
|
||
}
|
||
r += '<tr><td><div id=devs class=bar18 tabindex=0 onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=height:18px;width:100%;font-size:medium onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)">';
|
||
r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div>';
|
||
r += '<div class=deviceBarIcon onclick=gotoDevice(\'' + node._id + '\',null,null,event)><div class=\"j' + icon + '\" style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
|
||
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(\'' + node._id + '\',null,null,event)><span style=width:300px>' + name + '</span></div></div></td>';
|
||
r += '<td style=text-align:center>' + getUserShortStr(node);
|
||
r += '<td style=text-align:center>' + (node.ip != null ? node.ip : '');
|
||
r += '<td style=text-align:center>' + states.join(' + ');
|
||
//r += '<td style=text-align:center>' + (node.pwr != null ? powerStateStrings[node.pwr] : '');
|
||
r += '</tr>';
|
||
} else if ((view == 3) && (node.conn & 1) && (((meshrights & 8) || (meshrights & 256)) != 0) && ((node.agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
|
||
if ((multiDesktopFilter) && ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + node._id) >= 0))) {
|
||
r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div tabindex=0 style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + node._id + '\',11,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',11,null,event)">';
|
||
//r += '<input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox style=float:left>';
|
||
r += '<div class="j' + icon + '" style=width:16px;float:left></div> ' + name + '</div>';
|
||
r += '<span onclick=gotoDevice(\'' + node._id + '\',null,null,event)></span><div id=xkvmid_' + node._id.split('/')[2] + '><div id=skvmid_' + node._id.split('/')[2] + ' tabindex=0 style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:1000;cursor:default" onclick=toggleKvmDevice(\'' + node._id + '\') onkeypress="if (event.key==\'Enter\') toggleKvmDevice(\'' + node._id + '\')">' + "切断されました" + '</div></div>';
|
||
r += '</div>';
|
||
kvmDivs.push(node._id);
|
||
}
|
||
}
|
||
|
||
// If we are displaying devices by group, put the device in the right group.
|
||
if ((sort == 3) && (r != '')) {
|
||
if (node.tags) {
|
||
for (var j in node.tags) {
|
||
var tag = node.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[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
|
||
}
|
||
|
||
// Above 32 devices, gray out the auto connect feature.
|
||
if (kvmDivs.length >= 32) { Q('autoConnectDesktopCheckbox').checked = false; }
|
||
QE('autoConnectDesktopCheckbox', kvmDivs.length < 32);
|
||
|
||
// 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];
|
||
if (view == 2) {
|
||
r += '<tr><td colspan=4><div class=DevSt style=width:100%;padding-top:4px><span class=devHeaderx style=float:right>' + groupCount[i] + ' node' + ((groupCount[i] > 1) ? 's' : '') + '</span><span>' + i + '</span></div>' + groups[i];
|
||
} else {
|
||
r += '<div class=DevSt style=width:100%;padding-top:4px><span class=devHeaderx style=float:right>' + groupCount[i] + ' node' + ((groupCount[i] > 1) ? 's' : '') + '</span><span>' + i + '</span></div>' + groups[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
// If there is nothing to display, explain the problem
|
||
if ((r == '') && (meshcount > 0) && (Q('SearchInput').value != '')) {
|
||
if (sort == 3) {
|
||
r = '<div style="margin:30px">' + "どのグループにもデバイスは含まれていません。デバイスの\"グループ\"をクリックしてグループに追加してください。" + '</div>';
|
||
} else {
|
||
r = '<div style="margin:30px">' + "この検索に一致するデバイスはありません。" + '</div>';
|
||
}
|
||
}
|
||
|
||
if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
|
||
|
||
// Display all empty device groups, 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[userinfo._id];
|
||
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 id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span><span>';
|
||
r += getMeshActions(mesh, meshrights);
|
||
r += '</span></td></tr><tr>';
|
||
if (mesh.mtype == 1) {
|
||
r += '<td><div style=padding:10px><i>' + "Intel®なしこのメッシュのAMTデバイス";
|
||
if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "ひとつ追加" + '</a>'; }
|
||
}
|
||
if (mesh.mtype == 2) {
|
||
r += '<td><div style=padding:10px><i>' + "このグループにデバイスはありません";
|
||
if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>' + "ひとつ追加" + '</a>'; }
|
||
}
|
||
r += '.</i></div></td>';
|
||
current = mesh._id;
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (r != '') {
|
||
if (view == 2) {
|
||
// This height of 1 div at the end to fix a problem in Linux firefox browsers
|
||
r = '<table style=width:100%;margin-top:4px cellpadding=0 cellspacing=0><th style=color:gray><th style=color:gray;width:120px>' + "ユーザー" + '<th style=color:gray;width:120px>' + "住所" + '<th style=color:gray;width:100px>' + "接続性" + r + '</tr></table><div style=height:1px></div>'; //<th style=color:gray;width:100px>State';
|
||
}
|
||
} else {
|
||
if (sort == 3) { r = '<div style="margin:10px"><i>' + "No devices with tags found." + '</i></div>'; }
|
||
}
|
||
|
||
// Add a "Add Device Group" 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) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0))) {
|
||
r += '<a href=# onclick="return account_createMesh()" title=\"' + "デバイスの新しいグループを作成します。" + '\" style=cursor:pointer>' + "デバイスグループを追加" + '</a> ';
|
||
}
|
||
if ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 128) == 0)) {
|
||
r += '<a href=# onclick=\'return p10showMeshCmdDialog(0)\' style=cursor:pointer title=\"' + "多くの機能を実行するコマンドラインツール、MeshCmdをダウンロードします。" + '\">' + "MeshCmd" + '</a> ';
|
||
if (navigator.platform.toLowerCase() == 'win32') { r += '<a href=# onclick=\'return p10showMeshRouterDialog()\' style=cursor:pointer title=\"' + "TCPポートマッピングツールであるMeshCentralルーターをダウンロードします。" + '\">' + "ルーター" + '</a> '; }
|
||
}
|
||
r += '</div><br/>';
|
||
|
||
QH('xdevices', r);
|
||
deviceHeaderSet();
|
||
|
||
// Re-check nodeid's
|
||
var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
|
||
if (checkedNodeids) { for (var i=0;i<elements.length;i++) { 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) {
|
||
// Figure out and adjust the size to fill the width of the div
|
||
var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
|
||
//var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
|
||
var realw = vsize.x + 2, tw = totalDeviceViewWidth - 5, xw = Math.floor(tw / realw);
|
||
xw = realw + Math.floor((tw - (xw * realw)) / xw);
|
||
vsize.y = vsize.y * (xw / vsize.x);
|
||
vsize.x = xw;
|
||
|
||
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, ["切断されました", "接続しています...", "セットアップ...", '', ''][((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, ["切断されました", "接続しています...", "セットアップ...", '', ''][((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" 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', 480);
|
||
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 if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
|
||
mdeskAdjust(multiDesktop[i].m, multiDesktop[i].m.ScreenWidth, multiDesktop[i].m.ScreenHeight, multiDesktop[i].m.CanvasId); // Adjust screen size change
|
||
}
|
||
}
|
||
deskAdjust();
|
||
} else {
|
||
disconnectAllKvmFunction();
|
||
Q('autoConnectDesktopCheckbox').checked = false;
|
||
}
|
||
}
|
||
oldviewmode = view;
|
||
}
|
||
|
||
function toggleKvmDevice(node) {
|
||
if (typeof node == 'string') { node = getNodeFromId(node); } // Convert nodeid to node if needed
|
||
var mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
|
||
if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only 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 getUserShortStr(node) {
|
||
if (node == null || node.users == null || node.users.length == 0) return '';
|
||
if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + nobreak(format("{0}ユーザー", node.users.length)) + '</span>'; }
|
||
var u = node.users[0], su = u, i = u.indexOf('\\');
|
||
if (i > 0) { su = u.substring(i + 1); }
|
||
su = EscapeHtml(su);
|
||
if (su.length > 15) { su = su.substring(0, 14) + '…'; }
|
||
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
|
||
}
|
||
|
||
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
|
||
function connectAllKvmFunction(force) {
|
||
if (xxdialogMode) return false;
|
||
if (force !== true) { // We need to count how many devices will need to be connected, if it's a lot, prompt first.
|
||
var count = 0;
|
||
for (var i in nodes) {
|
||
var node = nodes[i], nodeid = nodes[i]._id;
|
||
if (multiDesktop[nodeid] == null) {
|
||
var mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
|
||
if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only 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) { count++; }
|
||
}
|
||
}
|
||
}
|
||
if (count > 8) { setDialogMode(2, "すべて接続", 3, function() { connectAllKvmFunction(true); }, format("{0}台のデバイスに接続してもよろしいですか?", count)); return; }
|
||
}
|
||
|
||
// Perform connect all
|
||
for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } }
|
||
}
|
||
function disconnectAllKvmFunction() { if (xxdialogMode) return false; for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
|
||
function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ["切断されました", "接続しています...", "セットアップ...", '', ''][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, "リモートデスクトップ設定", 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), authCookie);
|
||
desk.shortid = shortid;
|
||
//desk.debugmode = debugmode;
|
||
desk.onStateChanged = onMultiDesktopStateChange;
|
||
desk.m.bpp = 1;
|
||
desk.m.useZRLE = true;
|
||
desk.m.showmouse = true;
|
||
desk.m.onKvmData = function (data) { console.log('KVM Data received in multi-desktop mode, this is not supported.'); }; // KVM Data Channel not supported in multi-desktop right now.
|
||
//desk.m.onScreenSizeChange = deskAdjust;
|
||
if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
|
||
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, authCookie, authRelayCookie, domainUrl);
|
||
desk.shortid = shortid;
|
||
desk.attemptWebRTC = attemptWebRTC;
|
||
desk.onStateChanged = onMultiDesktopStateChange;
|
||
//desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
|
||
desk.m.CompressionLevel = multidesktopsettings.quality;
|
||
desk.m.ScalingLevel = multidesktopsettings.scaling;
|
||
desk.m.FrameRateTimer = multidesktopsettings.framerate;
|
||
//desk.m.onDisplayinfo = deskDisplayInfo;
|
||
//desk.m.onScreenSizeChange = deskAdjust;
|
||
if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
|
||
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 & 1024) == 0) { // If CIRA is allowed
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "新しいIntel®を追加しますインターネット上にあるAMTコンピューター。" + '\" onclick=\'return addCiraDeviceToMesh(\"' + mesh._id + '\")\'>' + "CIRAを追加" + '</a>';
|
||
}
|
||
if (mesh.mtype == 1) {
|
||
if ((features & 1) == 0) { // If not WAN-Only
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "新しいIntel®を追加しますローカルネットワーク上にあるAMTコンピューター。" + '\" onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "ローカルを追加" + '</a>';
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "新しいIntel®を追加しますローカルネットワークをスキャンしてAMTコンピューター。" + '\" onclick=\'return addAmtScanToMesh(\"' + mesh._id + '\")\'>' + "スキャンネットワーク" + '</a>';
|
||
}
|
||
if (mesh.amt && (mesh.amt.type == 2)) { // CCM activation
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "Intel AMTクライアント制御モード(CCM)アクティベーションを実行します。" + '\" onclick=\'return showCcmActivation(\"' + mesh._id + '\")\'>' + "アクティベーション" + '</a>';
|
||
} else if (mesh.amt && (mesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "Intel AMT管理制御モード(ACM)アクティベーションを実行します。" + '\" onclick=\'return showAcmActivation(\"' + mesh._id + '\")\'>' + "アクティベーション" + '</a>';
|
||
}
|
||
}
|
||
if (mesh.mtype == 2) {
|
||
r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "メッシュエージェントをインストールして、このメッシュに新しいコンピューターを追加します。" + '\" onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>' + "エージェントを追加" + '</a>';
|
||
if ((features & 2) == 0) { r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "このメッシュにメッシュエージェントをインストールするように招待します。" + '\" onclick=\'return inviteAgentToMesh(\"' + mesh._id + '\")\'>' + "招待する" + '</a>'; }
|
||
}
|
||
return r;
|
||
}
|
||
|
||
function addDeviceToMesh(meshid) {
|
||
if (xxdialogMode) return false;
|
||
var mesh = meshes[meshid];
|
||
var x = format("新しいIntel®を追加しますAMTデバイスからデバイスグループ\"{0}\"へ。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("装置名", '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue("ホスト名", '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder=\"' + "デバイス名と同じ" + '\" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue("ユーザー名", '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder=\"' + "管理者" + '\" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue("パスワード", '<input id=dp1password type=password style=width:230px autocomplete=off maxlength=32 onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue("セキュリティ", '<select id=dp1tls style=width:236px><option value=0>' + "TLSセキュリティなし" + '</option><option value=1>' + "TLSセキュリティが必要" + '</option></select>');
|
||
setDialogMode(2, "Intel®を追加AMTデバイス", 3, addDeviceToMeshEx, x, meshid);
|
||
validateDeviceToMesh();
|
||
Q('dp1devicename').focus();
|
||
return false;
|
||
}
|
||
|
||
// Intel AMT CCM Activation
|
||
function showCcmActivation(meshid) {
|
||
if (xxdialogMode) return false;
|
||
var servername = serverinfo.name, mesh = meshes[meshid];
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||
if (serverinfo.https == true) {
|
||
var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
|
||
url = 'wss://' + servername + portStr + domainUrl;
|
||
} else {
|
||
var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
|
||
url = 'ws://' + servername + portStr + domainUrl;
|
||
}
|
||
var x = format("MeshCMDツールをダウンロードして次のように実行することにより、グループ\"{0}\"にIntel AMTクライアントコントロールモード(CCM)アクティベーションを実行します。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>meshcmd amtccm --url ' + url + 'amtactivate?id=' + meshid.split('/')[2] + ' --serverhttpshash ' + serverinfo.tlshash + '</textarea>';
|
||
setDialogMode(2, "Intel® AMTアクティベーション", 9, null, x);
|
||
Q('idx_dlgOkButton').focus();
|
||
return false;
|
||
}
|
||
|
||
// Intel AMT ACM Activation
|
||
function showAcmActivation(meshid) {
|
||
if (xxdialogMode) return false;
|
||
var servername = serverinfo.name, mesh = meshes[meshid];
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||
if (serverinfo.https == true) {
|
||
var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
|
||
url = 'wss://' + servername + portStr + domainUrl;
|
||
} else {
|
||
var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
|
||
url = 'ws://' + servername + portStr + domainUrl;
|
||
}
|
||
var x = format("MeshCMDツールをダウンロードして次のように実行することにより、グループ\"{0}\"にIntel AMT管理制御モード(ACM)アクティベーションを実行します。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>meshcmd amtacm --url ' + url + 'amtactivate?id=' + meshid.split('/')[2] + ' --serverhttpshash ' + serverinfo.tlshash + '</textarea>';
|
||
if (serverinfo.amtAcmFqdn != null) {
|
||
x += ('<div style=margin-top:8px>' + "Intel AMTは、MEBxで信頼できるFQDNを使用して設定するか、ネットワーク上に有線LANが必要です。" + ' <b>' + serverinfo.amtAcmFqdn.join(', ') + '</b></div>');
|
||
}
|
||
setDialogMode(2, "Intel® AMTアクティベーション", 9, null, x);
|
||
Q('idx_dlgOkButton').focus();
|
||
return false;
|
||
}
|
||
|
||
// Display the Intel AMT scanning dialog box
|
||
function addAmtScanToMesh(meshid) {
|
||
if (xxdialogMode) return false;
|
||
var x = "IPアドレスの範囲を入力して、Intel AMTデバイスをスキャンします。" + '<br /><br />';
|
||
x += addHtmlValue("IP範囲", '<input id=dp1range style=width:184px value="192.168.1.0/24" onkeyup=addAmtScanToMeshKeyUp(event) /><input id=dp1rangebutton type=button value=\"' + "スキャン" + '\" 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, "Intelをスキャン® AMTデバイス", 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');
|
||
return false;
|
||
}
|
||
|
||
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=0;i<elements.length;i++) {
|
||
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>' + "走査..." + '</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=0;i<elements.length;i++) { if (elements[i].checked) checkcount++; }
|
||
QE('idx_dlgOkButton', checkcount > 0);
|
||
}
|
||
|
||
function addCiraDeviceToMesh(meshid) {
|
||
if (xxdialogMode) return false;
|
||
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スクリプト" + '</option><option value=1>' + "手動ユーザー名/パスワード" + '</option>';
|
||
if ((features & 16) == 0) { y += ('<option value=2>' + "手動証明書" + '</option></select>'); } // Only display this option if Intel AMT CIRA with Mutual-Auth is allowed.
|
||
|
||
var x = '';
|
||
x += addHtmlValue("設定方法", y);
|
||
x += '<hr>';
|
||
|
||
// Setup CIRA using a MeshCommander script (Pretty Simple)
|
||
x += '<div id=dlgAddCira0>' + format("新しいIntel®を追加するにはCIRAを使用してAMTデバイスからデバイスグループ\"{0}\"に移動し、次のスクリプトファイルをダウンロードして、<a href='http://meshcommander.com' rel='noreferrer noopener' target='_blank'> MeshCommander </を使用しますa>スクリプトを実行してコンピューターを構成します。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
//x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" download>cira_setup.mescript</a>');
|
||
x += addHtmlValue("CIRAのセットアップ", '<a href="mescript.ashx?type=1&meshid=' + meshid + '" download>cira_setup.mescript</a>');
|
||
x += addHtmlValue("CIRAのクリーンアップ", '<a href="mescript.ashx?type=2" download>cira_clean.mescript</a>');
|
||
x += '</div>';
|
||
|
||
// Setup CIRA with user/pass authentication (Somewhat difficult)
|
||
x += '<div id=dlgAddCira1 style=display:none>' + format("新しいIntel®を追加するにはAMTデバイスからCIRAを使用したデバイスグループ\"{0}\"に、Intel AMT内で信頼されたルートとして次の証明書をロード", EscapeHtml(mesh.name));
|
||
if (serverinfo.mpspass) { x += (" このユーザー名とパスワードを使用してサーバーに対して認証します。" + '<br /><br />'); } else { x += (" このユーザー名とパスワードを使用してサーバーに対して認証します。" + '<br /><br />'); }
|
||
x += addHtmlValue("ルート証明書", '<a href=\"' + "MeshServerRootCert.cer" + '\" download>' + "ルート証明書ファイル" + '</a>');
|
||
x += addHtmlValue("ユーザー名", '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
|
||
if (serverinfo.mpspass) { x += addHtmlValue("パスワード", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
|
||
if (serverinfo != null) { x += addHtmlValue("MPSサーバー", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
|
||
x += '</div>';
|
||
|
||
// Setup CIRA with certificate authentication (Really difficult, only if TLS offload is not used)
|
||
if ((features & 16) == 0) {
|
||
x += '<div id=dlgAddCira2 style=display:none>' + format("新しいIntel®を追加するにはCIRAを使用してデバイスグループ\"{0}\"へのAMTデバイス、Intel AMT内の信頼されたルートとして次の証明書を読み込み、次の共通名を持つクライアント証明書を使用して認証し、次のサーバーに接続します。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("ルート証明書", '<a href="MeshServerRootCert.cer" download>' + "ルート証明書ファイル" + '</a>');
|
||
x += addHtmlValue("組織", '<input style=width:230px readonly value="' + meshidx + '" />');
|
||
if (serverinfo != null) { x += addHtmlValue("MPSサーバー", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
|
||
x += '</div>';
|
||
}
|
||
|
||
setDialogMode(2, "Intel®を追加AMT CIRAデバイス", 2, null, x, 'fileDownload');
|
||
Q('dlgAddCiraSel').focus();
|
||
return false;
|
||
}
|
||
|
||
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 false;
|
||
var x = '', mesh = meshes[meshid];
|
||
if (features & 64) {
|
||
x += addHtmlValue("招待タイプ", '<select id=d2InviteType onchange=d2ChangedInviteType() style=width:236px><option value=0>Link invitation</option><option value=1>Email invitation</option></select>') + '<hr />';
|
||
x += '<div id=emailInviteDiv style=display:none>' + format("メッシュエージェントをインストールする人を招待します。 \"{0}\"デバイスグループのメッシュエージェントインストールへのリンクが記載されたメール。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("名前(オプション)", '<input id=agentInviteName value="" style=width:230px maxlength=64 />');
|
||
x += addHtmlValue("Eメール", '<input id=agentInviteEmail style=width:230px placeholder=\"' + "example@email.com" + '\" onkeyup=validateAgentInvite()></input>');
|
||
x += addHtmlValue("オペレーティング・システム", '<select id=agentInviteNameOs onchange=d2ChangedInviteType() style=width:236px><option value=4>' + "インストールリンクを送信" + '</option><option value=0 selected>' + "サポートされているもの" + '</option><option value=1>' + "Windowsのみ" + '</option><option value=3>' + "Apple MacOSのみ" + '</option><option value=2>' + "Linuxのみ" + '</option></select>');
|
||
x += '<div id=d2agentexpirediv>';
|
||
x += addHtmlValue("リンクの有効期限", '<select id=agentInviteExpire style=width:236px><option value=1>' + "1時間" + '</option><option value=8>' + "8時間" + '</option><option value=24>' + "1日" + '</option><option value=168>' + "1週間" + '</option><option value=5040>' + "1ヶ月" + '</option><option value=0>' + "無制限" + '</option></select>');
|
||
x += '</div>';
|
||
x += addHtmlValue("設置タイプ", '<select id=agentInviteType style=width:236px><option value=0>' + "背景とインタラクティブ" + '</option><option value=2>' + "背景のみ" + '</option><option value=1>' + "インタラクティブのみ" + '</option></select>');
|
||
x += addHtmlValue("メッセージ" + '<br />' + "(オプション)", '<textarea id=agentInviteMessage value="" style=width:230px;height:100px;resize:none maxlength=1024 /></textarea>');
|
||
x += '</div>';
|
||
}
|
||
x += '<div id=urlInviteDiv>' + format("招待リンクを共有して、メッシュエージェントをインストールする人を招待します。このリンクは、ユーザーに\"{0}\"デバイスグループのインストール手順を示します。リンクは公開されており、このサーバーのアカウントは必要ありません。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("リンクの有効期限", '<select id=d2inviteExpire style=width:236px onchange=d2RequestInvitationLink()><option value=1>' + "1時間" + '</option><option value=8>' + "8時間" + '</option><option value=24>' + "1日" + '</option><option value=168>' + "1週間" + '</option><option value=5040>' + "1ヶ月" + '</option><option value=0>' + "無制限" + '</option></select>');
|
||
x += '<div id=agentInvitationLinkDiv style="text-align:center;font-size:large;margin:16px;display:none"><a href=# id=agentInvitationLink target="_blank" style=cursor:pointer></a> <img src=images/link4.png height=10 width=10 title=\"' + "リンクをクリップボードにコピー" + '\" style=cursor:pointer onclick=d2CopyInviteToClip()></div></div>';
|
||
setDialogMode(2, "招待する", 3, performAgentInvite, x, meshid);
|
||
if (features & 64) { Q('d2InviteType').focus(); d2ChangedInviteType(); } else { Q('d2inviteExpire').focus(); validateAgentInvite(); }
|
||
d2RequestInvitationLink();
|
||
return false;
|
||
}
|
||
|
||
function d2RequestInvitationLink() {
|
||
meshserver.send({ action: 'createInviteLink', meshid: xxdialogTag, expire: parseInt(Q('d2inviteExpire').value), flags: 0 });
|
||
}
|
||
|
||
function d2ChangedInviteType() {
|
||
QV('urlInviteDiv', Q('d2InviteType').value == 0);
|
||
QV('d2agentexpirediv', Q('agentInviteNameOs').value == 4);
|
||
QV('emailInviteDiv', Q('d2InviteType').value == 1);
|
||
validateAgentInvite();
|
||
}
|
||
|
||
function d2CopyInviteToClip() { copyTextToClip(Q('agentInvitationLink').href); }
|
||
|
||
function validateAgentInvite() {
|
||
if ((features & 64) && (Q('d2InviteType').value == 1)) {
|
||
QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
|
||
QV('idx_dlgCancelButton', true);
|
||
} else {
|
||
QE('idx_dlgOkButton', true);
|
||
QV('idx_dlgCancelButton', false);
|
||
}
|
||
}
|
||
|
||
function performAgentInvite(button, meshid) {
|
||
if ((features & 64) && (Q('d2InviteType').value == 1)) {
|
||
meshserver.send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value, name: Q('agentInviteName').value, os: Q('agentInviteNameOs').value, flags: Q('agentInviteType').value, msg: Q('agentInviteMessage').value, expire: parseInt(Q('agentInviteExpire').value) });
|
||
}
|
||
}
|
||
|
||
function addAgentToMesh(meshid) {
|
||
if (xxdialogMode) return false;
|
||
var mesh = meshes[meshid], x = '', installType = 0;
|
||
x += addHtmlValue("オペレーティング・システム", '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>' + "窓" + '</option><option value=1>' + "Linux / BSD" + '</option><option value=2>' + "Apple MacOS" + '</option><option value=3>' + "Windows(アンインストール)" + '</option><option value=4>' + "Linux / BSD(アンインストール)" + '</option></select>');
|
||
x += '<div id=aginsTypeDiv>';
|
||
x += addHtmlValue("設置タイプ", '<select id=aginsType onchange=addAgentToMeshClick() style=width:236px><option value=0>' + "背景とインタラクティブ" + '</option><option value=2>' + "背景のみ" + '</option><option value=1>' + "インタラクティブのみ" + '</option></select>');
|
||
x += '</div><hr>';
|
||
|
||
// \/:*?"<>|
|
||
var meshfilename = mesh.name
|
||
meshfilename = meshfilename.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join('');
|
||
|
||
// Windows agent install
|
||
//x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
|
||
x += '<div id=agins_windows>' + format("デバイスグループ\"{0}\"に新しいコンピューターを追加するには、メッシュエージェントをダウンロードし、管理するコンピューターにインストールします。このエージェントには、サーバーとデバイスグループの情報が埋め込まれています。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("メッシュエージェント", '<a id=aginsw32lnk href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=0" download onclick="setDialogMode(0)" title=\"' + "MeshAgentの32ビットバージョン" + '\">' + "Windows(.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="Copy Windows 32bit agent URL to clipboard" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
|
||
x += addHtmlValue("メッシュエージェント", '<a id=aginsw64lnk href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=0" download onclick="setDialogMode(0)" title=\"' + "MeshAgentの64ビットバージョン" + '\">' + "Windows x64(.exe)" + '</a> <img src=images/link4.png height=10 width=10 title="Copy Windows 64bit agent URL to clipboard" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
|
||
if (debugmode > 0) { x += addHtmlValue("設定ファイル", '<a id=aginswmshlnk href="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank">' + format("{0}設定(.msh)", EscapeHtml(mesh.name)) + '</a>'); }
|
||
x += '</div>';
|
||
|
||
// Linux agent install
|
||
x += '<div id=agins_linux style=display:none>' + format("{0}にコンピューターを追加するには、次のコマンドを実行します。ルート資格情報が必要になります。", EscapeHtml(mesh.name)) + '<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 style=\'font-size:x-small\'>' + "* BSDの場合、最初に\"pkg install wget sudo bash\"を実行します。" + '</div></div>';
|
||
|
||
// MacOS agent install
|
||
x += '<div id=agins_osx style=display:none>' + format("デバイスグループ\"{0}\"に新しいコンピューターを追加するには、メッシュエージェントをダウンロードし、管理するコンピューターにインストールします。このエージェントインストーラーには、サーバーとデバイスグループの情報が埋め込まれています。", EscapeHtml(mesh.name)) + '<br /><br />';
|
||
x += addHtmlValue("メッシュエージェント", '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" rel="noreferrer noopener" target="_blank" title="64bit version of MacOS Mesh Agent">MacOS Agent (64bit)</a> <img src=images/link4.png height=10 width=10 title="' + "MacOSエージェントのURLをクリップボードにコピーします" + '" style=cursor:pointer onclick=copyAgentUrl("meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '",0)>');
|
||
x += '</div>';
|
||
|
||
// Windows agent uninstall
|
||
x += '<div id=agins_windows_un style=display:none>' + "メッシュエージェントを削除するには、以下のファイルをダウンロードして実行し、「アンインストール」をクリックします。" + '<br /><br />';
|
||
x += addHtmlValue("メッシュエージェント", '<a href="meshagents?id=3" download onclick="setDialogMode(0)" title="' + "MeshAgentの32ビットバージョン" + '">' + "Windows(.exe)" + '</a>');
|
||
x += addHtmlValue("メッシュエージェント", '<a href="meshagents?id=4" download onclick="setDialogMode(0)" title="' + "MeshAgentの64ビットバージョン" + '">' + "Windows x64(.exe)" + '</a>');
|
||
x += '</div>';
|
||
|
||
// Linux agent uninstall
|
||
x += '<div id=agins_linux_un style=display:none>' + "メッシュエージェントを削除するには、次のコマンドを実行します。ルート資格情報が必要になります。" + '<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, "メッシュエージェントを追加", 2, null, x, 'fileDownload');
|
||
var servername = serverinfo.name;
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||
|
||
if (serverinfo.https == true)
|
||
{
|
||
var portStr = (serverinfo.port == 443)?'':(':' + serverinfo.port);
|
||
if ((features & 0x2000) == 0)
|
||
{
|
||
Q('agins_linux_area').value = '(wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo -E ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\' || ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
|
||
Q('agins_linux_area_un').value = '(wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n';
|
||
}
|
||
else
|
||
{
|
||
// Server asked that agent be installed to preferably not use a HTTP proxy.
|
||
Q('agins_linux_area').value = 'wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\' || ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
|
||
Q('agins_linux_area_un').value = 'wget https://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n';
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
|
||
if ((features & 0x2000) == 0)
|
||
{
|
||
Q('agins_linux_area').value = '(wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 -O ./meshinstall.sh || wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo -E ./meshinstall.sh http://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
|
||
Q('agins_linux_area_un').value = '(wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 -O ./meshinstall.sh || wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n';
|
||
}
|
||
else
|
||
{
|
||
// Server asked that agent be installed to preferably not use a HTTP proxy.
|
||
Q('agins_linux_area').value = 'wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
|
||
Q('agins_linux_area_un').value = 'wget http://' + servername + portStr + domainUrl + 'meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n';
|
||
}
|
||
}
|
||
Q('aginsSelect').focus();
|
||
addAgentToMeshClick();
|
||
return false;
|
||
}
|
||
|
||
function copyAgentUrl(url,addflag) {
|
||
var servername = serverinfo.name;
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||
var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
|
||
var c = 'https://' + servername + portStr + domainUrl + url;
|
||
if (addflag == 1) c += Q('aginsType').value;
|
||
copyTextToClip(c);
|
||
}
|
||
|
||
function addAgentToMeshClick() {
|
||
var v = Q('aginsSelect').value;
|
||
QV('agins_windows', v == 0);
|
||
QV('agins_linux', v == 1);
|
||
QV('agins_osx', v == 2);
|
||
QV('agins_windows_un', v == 3);
|
||
QV('agins_linux_un', v == 4);
|
||
QV('aginsTypeDiv', v == 0);
|
||
|
||
// Fix the links if needed
|
||
Q('aginsw32lnk').href = (Q('aginsw32lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
|
||
Q('aginsw64lnk').href = (Q('aginsw64lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
|
||
if (debugmode > 0) { Q('aginswmshlnk').href = (Q('aginswmshlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value; }
|
||
}
|
||
|
||
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 == 1) ? "1ノード" : format("{0}ノード", deviceHeaderTotal));
|
||
//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=\"' + "デバイスの電源が入っています。" + '\">' + "パワード" + '</span>', '<span title=\"' + "デバイスはスリープ状態(S1)です。" + '\">' + "睡眠" + '</span>', '<span title=\"' + "デバイスはスリープ状態(S2)です。" + '\">' + "睡眠" + '</span>', '<span title=\"' + "デバイスはディープスリープ状態(S3)です。" + '\">' + "深い眠り" + '</span>', '<span title=\"' + "デバイスは休止状態です(S4)。" + '\">' + "冬眠" + '</span>', '<span title=\"' + "デバイスは電源オフ状態です(S5)。" + '\">' + "ソフトオフ" + '</span>', '<span title=\"' + "デバイスは検出されましたが、電源状態を取得できませんでした。" + '\">' + "プレゼント" + '</span>'];
|
||
var powerStateStrings2 = ['', "デバイスに電源が入っています", "デバイスはスリープ状態です(S1)", "デバイスはスリープ状態です(S2)", "デバイスはディープスリープ状態です(S3)", "デバイスは休止状態です(S4)", "デバイスはソフトオフ状態です(S5)", "デバイスは存在しますが、電源状態を判別できません"];
|
||
var powerColorTable = ['pwsTransparent', 'pwsBlack', 'pwsBlue', 'pwsBlue2', 'pwsLightblue', 'pwsBlueviolet', 'pwsDarkgreen', 'pwsLightseagreen', 'pwsLightseagreen2'];
|
||
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=\"' + "メッシュエージェントが接続され、使用できる状態になりました。" + '\">' + "エージェント" + '</span>'); }
|
||
if ((node.conn & 2) != 0) { states.push('<span title=\"' + "Intel® AMT CIRAが接続され、使用できる状態になりました。" + '\">' + "CIRA" + '</span>'); }
|
||
else if ((node.conn & 4) != 0) { states.push('<span title=\"' + "Intel® AMTはルーティング可能です。" + '\">' + "AMT" + '</span>'); }
|
||
if ((node.conn & 8) != 0) { states.push('<span title=\"' + "メッシュエージェントは、別のエージェントをリレーとして使用して到達可能です。" + '\">' + "リレー" + '</span>'); }
|
||
if ((node.conn & 16) != 0) { states.push('<span title=\"' + "デバイスへのMQTT接続がアクティブです。" + '\">' + "MQTT" + '</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 "未知の";
|
||
}
|
||
|
||
function selectallButtonFunction() {
|
||
var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) checkcount++; }
|
||
for (var i=0;i<elements.length;i++) { elements[i].checked = (checkcount == 0); }
|
||
p1updateInfo();
|
||
}
|
||
|
||
function p1updateInfo() {
|
||
var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) { checkcount++; } }
|
||
if (checkcount > 0) {
|
||
QE('GroupActionButton', true);
|
||
Q('SelectAllButton').value = "なしを選択";
|
||
QV('cxmgroupsplit', true);
|
||
QV('cxmdesktop', true);
|
||
} else {
|
||
QE('GroupActionButton', false);
|
||
Q('SelectAllButton').value = "すべて選択";
|
||
QV('cxmgroupsplit', false);
|
||
QV('cxmdesktop', false);
|
||
}
|
||
}
|
||
|
||
function groupActionFunction() {
|
||
var addedOptions = '', nodeids = getCheckedDevices();
|
||
|
||
// Check if any of the selected devices have a MQTT connection active
|
||
if (features & 0x00400000) {
|
||
for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { addedOptions += '<option value=103>' + "MQTTメッセージを送信" + '</option>'; break; } }
|
||
}
|
||
|
||
// Display the "Uninstall Agent" option if allowed and we selected connected devices.
|
||
for (var i in nodeids) {
|
||
var node = getNodeFromId(nodeids[i]);
|
||
var mesh = meshes[node.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
if (((node.conn & 1) != 0) && ((meshrights & 32768) != 0)) { addedOptions += '<option value=104>' + "エージェントのアンインストール" + '</option>'; break; }
|
||
}
|
||
|
||
var x = "選択したすべてのデバイスで実行する操作を選択します。アクションは適切な権限でのみ実行されます。" + '<br /><br />';
|
||
x += addHtmlValue("操作", '<select id=d2groupop><option value=100>' + "ウェイクアップデバイス" + '</option><option value=4>' + "スリープデバイス" + '</option><option value=3>' + "デバイスをリセットする" + '</option><option value=2>' + "デバイスの電源を切る" + '</option><option value=102>' + "デバイスグループに移動" + '</option>' + addedOptions + '<option value=101>' + "デバイスを削除する" + '</option></select>');
|
||
setDialogMode(2, "グループアクション", 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=0;i<elements.length;i++) { if (elements[i].checked) { if (elements[i].value) { var nid = elements[i].value.substring(6); if (nodeids.indexOf(nid) == -1) { nodeids.push(nid); } } } }
|
||
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 = "選択したデバイスの削除を確認しますか?" + '<br /><br />';
|
||
x += '<label><input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />' + "確認する" + '</label>';
|
||
setDialogMode(2, "ノードを削除する", 3, groupActionFunctionDelEx, x);
|
||
QE('idx_dlgOkButton', false);
|
||
} else if (op == 102) {
|
||
// Move computers to a different group
|
||
p10showChangeGroupDialog(getCheckedDevices());
|
||
} else if (op == 103) {
|
||
// Send MQTT Message
|
||
p10showSendMqttMsgDialog(getCheckedDevices());
|
||
} else if (op == 104) {
|
||
// Uninstall agent
|
||
p10showSendUninstallAgentDialog(getCheckedDevices());
|
||
} else {
|
||
// Power operation
|
||
meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: parseInt(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); }
|
||
}
|
||
|
||
function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
|
||
function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap > bp) return -1; if (ap < bp) return 1; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
|
||
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.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
|
||
function onSearchFocus(x) { searchFocus = x; }
|
||
function onMapSearchFocus(x) { mapSearchFocus = x; }
|
||
function onUserSearchFocus(x) { userSearchFocus = x; }
|
||
function onConsoleFocus(x) { consoleFocus = x; }
|
||
|
||
function onSearchInputChanged() {
|
||
var x = Q('SearchInput').value.toLowerCase().trim(); putstore('_search', x);
|
||
var userSearch = null, ipSearch = null, groupSearch = null;
|
||
if (x.startsWith('user:')) { userSearch = x.substring(5); }
|
||
else if (x.startsWith('u:')) { userSearch = x.substring(2); }
|
||
else if (x.startsWith('ip:')) { ipSearch = x.substring(3); }
|
||
else if (x.startsWith('group:')) { groupSearch = x.substring(6); }
|
||
else if (x.startsWith('g:')) { groupSearch = x.substring(2); }
|
||
|
||
if (x == '') {
|
||
// No search
|
||
for (var d in nodes) { nodes[d].v = true; }
|
||
} else if (ipSearch != null) {
|
||
// IP address search
|
||
for (var d in nodes) { nodes[d].v = ((nodes[d].ip != null) && (nodes[d].ip.indexOf(ipSearch) >= 0)); }
|
||
} else if (groupSearch != null) {
|
||
// Group filter
|
||
for (var d in nodes) { nodes[d].v = (meshes[nodes[d].meshid].name.toLowerCase().indexOf(groupSearch) >= 0); }
|
||
} else if (userSearch != null) {
|
||
// User search
|
||
for (var d in nodes) {
|
||
nodes[d].v = false;
|
||
if (nodes[d].users && nodes[d].users.length > 0) { for (var i in nodes[d].users) { if (nodes[d].users[i].toLowerCase().indexOf(userSearch) >= 0) { nodes[d].v = true; } } }
|
||
}
|
||
} else {
|
||
// Device name search
|
||
try {
|
||
var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception.
|
||
for (var d in nodes) {
|
||
nodes[d].v = (rx.test(nodes[d].name.toLowerCase())) || (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase()));
|
||
if ((nodes[d].v == false) && nodes[d].tags) {
|
||
for (var s in nodes[d].tags) {
|
||
if (rx.test(nodes[d].tags[s].toLowerCase())) {
|
||
nodes[d].v = true;
|
||
break;
|
||
} else {
|
||
nodes[d].v = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
|
||
}
|
||
}
|
||
|
||
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 == 'connectbutton2' && currentNode && currentNode.agent && (currentNode.agent.id > 0) && (currentNode.agent.id < 5)) {
|
||
contextelement = elem;
|
||
var contextmenudiv = document.getElementById('termShellContextMenu');
|
||
contextmenudiv.style.left = event.pageX + 'px';
|
||
contextmenudiv.style.top = event.pageY + 'px';
|
||
contextmenudiv.style.display = 'block';
|
||
} else if (elem && elem != null && elem.id == 'connectbutton2' && currentNode && currentNode.agent && (currentNode.agent.id > 4)) {
|
||
contextelement = elem;
|
||
var contextmenudiv = document.getElementById('termShellContextMenuLinux');
|
||
contextmenudiv.style.left = event.pageX + 'px';
|
||
contextmenudiv.style.top = event.pageY + 'px';
|
||
contextmenudiv.style.display = 'block';
|
||
} else 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 if (elem && elem != null && elem.classList.contains('pluginTab')) {
|
||
contextelement = elem;
|
||
var contextmenudiv = document.getElementById('pluginTabContextMenu');
|
||
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';
|
||
|
||
// Get the node and set the menu options
|
||
var nodeid = contextelement.children[1].attributes.onclick.value;
|
||
var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
|
||
var mesh = meshes[node.meshid];
|
||
var meshlinks = mesh.links[userinfo._id];
|
||
var meshrights = meshlinks.rights;
|
||
var consoleRights = ((meshrights & 16) != 0);
|
||
|
||
// Check if we have terminal and file access
|
||
var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
|
||
var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
|
||
|
||
QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
|
||
QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
|
||
QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
|
||
QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
|
||
QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
|
||
}
|
||
|
||
return haltEvent(event);
|
||
}
|
||
|
||
function cmaction(action,event) {
|
||
var nodeid = contextelement.children[1].attributes.onclick.value;
|
||
nodeid = nodeid.substring(12, nodeid.length - 18);
|
||
if (action == 7) { Q('viewselect').value = 3; Q('viewselect').onchange(); Q('autoConnectDesktopCheckbox').checked = true; Q('autoConnectDesktopCheckbox').onclick(); } // Multi-Desktop
|
||
if ((action > 0) && (action < 7)) {
|
||
var panel = [0, 10, 12, 11, 13, 16, 15][action]; // (invalid), General, Desktop, Terminal, Files, Events, Console
|
||
if (event && (event.shiftKey == true)) {
|
||
// Open the device in a different tab
|
||
window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=' + panel + '&hide=16', 'meshcentral:' + nodeid);
|
||
} else {
|
||
// Go to the right panel
|
||
gotoDevice(nodeid, panel);
|
||
|
||
// If possible, connect...
|
||
var mesh = meshes[currentNode.meshid];
|
||
if ((currentNode.conn & 1) && (mesh.mtype == 2)) {
|
||
if ((panel == 11) && (desktop == null) && (currentNode.agent.caps & 1)) { connectDesktop(null, 3); } // Desktop
|
||
if ((panel == 12) && (terminal == null) && (currentNode.agent.caps & 2)) { connectTerminal(null, 1); } // Terminal
|
||
if ((panel == 13) && (files == null)) { connectFiles(null); } // files
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function cmmeshaction(action) {
|
||
var meshid = contextelement.attributes.onclick.value.substring(10, contextelement.attributes.onclick.value.length - 2);
|
||
var elements = document.getElementsByClassName('DeviceCheckbox');
|
||
if ((action == 1) || (action == 2)) {
|
||
for (var i = 0; i < elements.length; i++) {
|
||
if ((elements[i].attributes) && (elements[i].attributes['class']['value'].split(' ')[0] == meshid)) { elements[i].checked = (action == 1); }
|
||
}
|
||
}
|
||
//if (action == 3) { window.location = "multidesktop.aspx?mesh=" + meshid + "&auto=1"; }
|
||
p1updateInfo();
|
||
}
|
||
|
||
function cmtermaction(action) {
|
||
connectTerminal(null, 1, { protocol: action });
|
||
}
|
||
|
||
/*
|
||
function pluginTabClose() {
|
||
var pluginTab = contextelement;
|
||
var pname = pluginTab.getAttribute('x-data-plugin-sname');
|
||
var pdiv = Q('plugin-'+pname);
|
||
pdiv.parentNode.removeChild(pdiv);
|
||
pluginTab.parentNode.removeChild(pluginTab);
|
||
QV('p42', true);
|
||
goPlugin(-1);
|
||
}
|
||
*/
|
||
|
||
function hideContextMenu() {
|
||
QV('contextMenu', false);
|
||
QV('meshContextMenu', false);
|
||
QV('termShellContextMenu', false);
|
||
QV('termShellContextMenuLinux', false);
|
||
//QV('pluginTabContextMenu', 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
|
||
}
|
||
|
||
{{{StartGeoLocationJS}}}
|
||
|
||
// Add a feature for every Node and change style if connection status changes
|
||
function updateMapMarkers(selectedMesh) {
|
||
if ((xxmap != null) && (xxmap.map == null)) { try { loadmap(); } catch (ex) { console.error('loadmap() exception', ex); } }
|
||
if (xxmap == null) return;
|
||
var boundingBox = null;
|
||
for (var i in nodes) {
|
||
try {
|
||
var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
|
||
if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
|
||
var lat = loc[0], lon = loc[1], 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); }
|
||
}
|
||
} catch (ex) { console.error('updateMapMarkers() exception', ex, JSON.stringify(nodes[i])); }
|
||
}
|
||
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: "ノードの場所を変更する", callback: function (obj) { modifyMarkerloc(obj.data); } };
|
||
|
||
// Clear Marker item
|
||
var map_cm_clearMarker = { text: "ノードの場所を削除", 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: "ノードの場所を保存", callback: function (obj) { saveMarkerloc(obj.data); } };
|
||
|
||
// Build a context menu for a feature
|
||
var map_cm_nodemenu_items = [
|
||
{ text: "一般情報", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 10); } } },
|
||
{ text: "デスクトップ", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 11); } } },
|
||
{ text: "ターミナル", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 12); } } },
|
||
{ text: "Intel® AMT", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 14); } } },
|
||
'-',
|
||
{ text: "拡大する", callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 19); } },
|
||
{ text: "ズームアウト", callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 2); } }
|
||
];
|
||
|
||
// Context menu for clicks other than on feature
|
||
var contextmenu_items = [
|
||
{ text: "リフレッシュ", callback: function () { refreshMap(true, true); } },
|
||
{ text: "範囲に合わせてズーム", callback: function () { zoomToFitExtent(); } },
|
||
{ text: "センターマップはこちら", callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
|
||
{ text: "ここにノードを配置", 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 null;
|
||
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;
|
||
if ((features & 0x8000) == 0) { xxmap = null; return; } // Geolocation not supported
|
||
QV('viewselectmapoption', true);
|
||
QV('devViewButton4', true);
|
||
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);
|
||
var 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
|
||
var 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("開いた", 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 (ex) {
|
||
console.log(ex);
|
||
QV('viewselectmapoption', false);
|
||
QV('devViewButton4', 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);
|
||
if (loc != null) {
|
||
var 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 == 3 || 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 == "拡大する" || item.text == "ズームアウト") { item.data = feature; }
|
||
else { if (item != '-') { 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>' + "サーチ" + '</label>  <input type=text placeholder="' + "装置名" + '" 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>' + "デバイスが見つかりません。" + '</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, "配置するノードを選択します", 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].rnamel != null && nodes[i].rnamel.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].rnamel != null && nodes[i].rnamel.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 class="xmapItem">';
|
||
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 itemclass = (i % 2 == 0)?'xmapItemSel1':'xmapItemSel1';
|
||
x += '<div class="' + itemclass + '" onclick=mapGotoSelectedLocation(this)><div>' + dataInfo[i].display_name + '</div><div style=display:none>' + dataInfo[i].boundingbox[0] + '!#!' + dataInfo[i].boundingbox[1] + '!#!' + dataInfo[i].boundingbox[2] + '!#!' + dataInfo[i].boundingbox[3] + '</div></div>';
|
||
}
|
||
}
|
||
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>' + "場所が見つかりません。" + '<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());
|
||
}
|
||
|
||
{{{EndGeoLocationJS}}}
|
||
|
||
//
|
||
// 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[userinfo._id].rights;
|
||
}
|
||
|
||
var currentNode;
|
||
var powerTimelineNode = null;
|
||
var powerTimelineReq = null;
|
||
var powerTimelineUpdate = null;
|
||
var powerTimeline = null;
|
||
function getCurrentNode() { return currentNode; };
|
||
function gotoDevice(nodeid, panel, refresh, event) {
|
||
// Remind the user to verify the email address
|
||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "アカウントのセキュリティ", 1, null, "メールアドレスが確認されるまでデバイスにアクセスできません。これはパスワードの回復に必要です。 [マイアカウント]タブに移動して、メールアドレスを変更および確認します。"); return; }
|
||
|
||
// Remind the user to add two factor authentication
|
||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "アカウントのセキュリティ", 1, null, "二要素認証が有効になるまでデバイスにアクセスできません。これは、追加のセキュリティのために必要です。 [マイアカウント]タブに移動して、[アカウントセキュリティ]セクションを確認します。"); return; }
|
||
|
||
if (event && (event.shiftKey == true)) {
|
||
// Open the device in a different tab
|
||
window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=10&hide=16', 'meshcentral:' + nodeid);
|
||
return;
|
||
}
|
||
|
||
//disconnectAllKvmFunction();
|
||
var node = getNodeFromId(nodeid);
|
||
var mesh = meshes[node.meshid];
|
||
var meshrights = mesh.links[userinfo._id].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>' + "なし" + '</i>'; }
|
||
if (((meshrights & 4) != 0) && ((!mesh.flags) || ((mesh.flags & 2) == 0))) { nname = '<span tabindex=0 title=\"' + "サーバー側のデバイス名を編集するにはここをクリックしてください" + '\" onclick=showEditNodeValueDialog(0) onkeyup="if (event.key == \'Enter\') showEditNodeValueDialog(0)" style=cursor:pointer>' + nname + ' <img class=hoverButton src="images/link5.png" /></span>'; }
|
||
nname += '<span style=color:#AAA;font-size:small> - ' + EscapeHtml(mesh.name) + '</span>';
|
||
QH('p10deviceName', nname);
|
||
QH('p11deviceName', nname);
|
||
QH('p12deviceName', nname);
|
||
QH('p13deviceName', nname);
|
||
QH('p14deviceName', nname);
|
||
QH('p15deviceName', "コンソール -" + nname);
|
||
QH('p16deviceName', nname);
|
||
QH('p17deviceName', nname);
|
||
QH('p19deviceName', nname);
|
||
|
||
// Node attributes
|
||
var x = '<table style=width:100%>';
|
||
|
||
// Attribute: Mesh
|
||
x += addDeviceAttribute('<span title=\"' + "このコンピューターが属するデバイスグループの名前。" + '\">' + "グループ" + '</span>', '<a href=# title=\"' + "このコンピューターが属するデバイスグループの名前" + '\" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
|
||
|
||
// Attribute: Name
|
||
if ((node.rname != null) && (node.name != node.rname)) { x += addDeviceAttribute('<span title="The name of this computer as set in the operating system">Name</span>', '<span title="The name of this computer as set in the operating system">' + EscapeHtml(node.rname) + '</span>'); }
|
||
|
||
// Attribute: Host
|
||
if ((features & 1) == 0) { // If not WAN-only, local hostname is in use
|
||
if ((meshrights & 4) != 0) {
|
||
if (node.host) {
|
||
x += addDeviceAttribute("ホスト名", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
|
||
} else {
|
||
x += addDeviceAttribute("ホスト名", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>' + "なし" + '</i></span>');
|
||
}
|
||
} else {
|
||
x += addDeviceAttribute("ホスト名", EscapeHtml(node.host));
|
||
}
|
||
}
|
||
|
||
// Attribute: Description
|
||
var description = node.desc?EscapeHtml(node.desc):('<i>' + "なし" + '</i>');
|
||
if ((meshrights & 4) != 0) {
|
||
x += addDeviceAttribute("説明", '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + ' <img class=hoverButton src="images/link5.png" /></span>');
|
||
} else {
|
||
x += addDeviceAttribute("説明", description);
|
||
}
|
||
|
||
// Attribute: Mesh Agent
|
||
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("メッシュエージェント", str);
|
||
}
|
||
|
||
// Attribute: Intel AMT
|
||
if (node.intelamt != null) {
|
||
var str = '';
|
||
var provisioningStates = { 0: nobreak("アクティブ化されていない(前)"), 1: nobreak("アクティブ化されていない(イン)"), 2: nobreak("有効化") };
|
||
if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "不明な状態" + '</i>, v' + node.intelamt.ver; } else
|
||
|
||
if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "有効化" + '</i>'; }
|
||
else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "不明なバージョンと状態" + '</i>'; }
|
||
else {
|
||
str += provisioningStates[node.intelamt.state];
|
||
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { str += ' <span title=\"' + "Intel AMTはクライアントコントロールモードでアクティブ化されます" + '\">' + "CCM" + '</span>'; } else if (node.intelamt.flags & 4) { str += ' <span title=\"' + "Intel AMTは管理制御モードでアクティブ化されます" + '\">' + "ACM" + '</span>'; } }
|
||
str += (', v' + node.intelamt.ver);
|
||
}
|
||
|
||
if (node.intelamt.tls == 1) { str += ', <span title=\"' + "Intel AMTはTLSネットワークセキュリティでセットアップされています" + '\">' + "TLS" + '</span>'; }
|
||
if (node.intelamt.state == 2) {
|
||
if (node.intelamt.user == null || node.intelamt.user == '') {
|
||
if ((meshrights & 4) != 0) {
|
||
str += ', <i style=color:#FF0000;cursor:pointer title=\"' + "Intelを編集® AMTクレデンシャル" + '\" onclick=editDeviceAmtSettings("' + node._id + '")>' + "資格情報なし" + '</i>';
|
||
} else {
|
||
str += ', <i style=color:#FF0000>' + "資格情報なし" + '</i>';
|
||
}
|
||
}
|
||
str += ' ';
|
||
if ((meshrights & 4) != 0) {
|
||
str += '<img src=images/link4.png height=10 width=10 title=\"' + "Intelを編集® AMTクレデンシャル" + '\" style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
|
||
}
|
||
}
|
||
|
||
var meName = '<span title=\"Intel® Manageability Engine\">' + "Intel®私" + '<span>';
|
||
if (typeof node.intelamt.sku == 'number') {
|
||
if ((node.intelamt.sku & 8) != 0) { meName = '<span title=\"' + "Intel®アクティブ管理テクノロジー" + '\">' + "Intel® AMT" + '<span>'; }
|
||
else if ((node.intelamt.sku & 16) != 0) { meName = '<span title=\"' + "Intel®標準の管理性" + '\">' + "Intel® SM" + '<span>'; }
|
||
}
|
||
x += addDeviceAttribute(meName, str);
|
||
}
|
||
|
||
if (mesh.mtype == 2) {
|
||
// Attribute: Mesh Agent Tag
|
||
if ((node.agent != null) && (node.agent.tag != null)) {
|
||
var tag = EscapeHtml(node.agent.tag);
|
||
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
|
||
x += addDeviceAttribute("エージェントタグ", tag);
|
||
}
|
||
} else {
|
||
// Attribute: Intel AMT Tag
|
||
if ((node.intelamt != null) && (node.intelamt.tag != null)) {
|
||
var tag = EscapeHtml(node.intelamt.tag);
|
||
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
|
||
x += addDeviceAttribute("Intel® AMTタグ", tag);
|
||
}
|
||
}
|
||
|
||
// Attribute: Intel AMT
|
||
//if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel® AMT', node.intelamt.user); }
|
||
|
||
// Operating system description
|
||
if (node.osdesc) { x += addDeviceAttribute("オペレーティング・システム", node.osdesc); }
|
||
|
||
// Antivirus
|
||
if (node.av && node.av.length > 0) {
|
||
var y = [];
|
||
for (var i in node.av) {
|
||
if (node.av[i].product) {
|
||
var avx = EscapeHtml(node.av[i].product);
|
||
if (node.av[i].enabled !== true) { avx += ' - <span style=color:red>' + "無効" + '</span>'; }
|
||
if (node.av[i].updated !== true) { avx += ' - <span style=color:red>' + "時代遅れ" + '</span>'; }
|
||
if ((node.av[i].enabled == true) && (node.av[i].updated == true)) { avx += ' - <span style=color:green>' + "OK" + '</span>'; }
|
||
y.push(avx);
|
||
}
|
||
}
|
||
x += addDeviceAttribute("アンチウイルス", y.join('<br />'));
|
||
}
|
||
|
||
// Active Users
|
||
if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute(format("アクティブユーザー{0}", ((node.users.length > 1)?'s':'')), node.users.join(', ')); }
|
||
|
||
// 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=\"' + "メッシュエージェントが接続され、使用できる状態になりました。" + '\">' + "メッシュエージェント" + '</span>');
|
||
if ((node.conn & 2) != 0) cstate.push('<span title=\"' + "Intel® AMT CIRAが接続され、使用できる状態になりました。" + '\">' + "Intel® AMT CIRA" + '</span>');
|
||
else if ((node.conn & 4) != 0) cstate.push('<span title=\"' + "Intel® AMTはルーティング可能であり、すぐに使用できます。" + '\">' + "Intel® AMT" + '</span>');
|
||
if ((node.conn & 8) != 0) cstate.push('<span title=\"' + "メッシュエージェントは、別のエージェントをリレーとして使用して到達可能です。" + '\">' + "メッシュリレー" + '</span>');
|
||
if ((node.conn & 16) != 0) { cstate.push('<span title=\"' + "デバイスへのMQTT接続がアクティブです。" + '\">' + "MQTT" + '</span>'); }
|
||
x += addDeviceAttribute("接続性", cstate.join(', '));
|
||
}
|
||
|
||
// Node grouping tags
|
||
var groupingTags = '<i>' + "なし" + '</i>';
|
||
if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span class="tagSpan">' + node.tags[i] + '</span>'; } }
|
||
if ((meshrights & 4) != 0) {
|
||
x += addDeviceAttribute('Tags', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton src="images/link5.png" /></span>');
|
||
} else {
|
||
x += addDeviceAttribute('Tags', groupingTags);
|
||
}
|
||
|
||
x += '</table><br />';
|
||
// Show action button, only show if we have permissions 4, 8, 64
|
||
if ((meshrights & 76) != 0) { x += '<input type=button value=\"' + "行動" + '\" title=\"' + "デバイスの電源操作を実行します" + '\" onclick=deviceActionFunction() />'; }
|
||
x += '<input type=button value=\"' + "ノート" + '\" title=\"' + "このデバイスに関するメモを表示" + '\" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
|
||
x += '<input type=button value=\"' + "ログイベント" + '\" title=\"' + "このデバイスのイベントを書く" + '\" onclick=writeDeviceEvent("' + 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
|
||
masterUpdate(256);
|
||
|
||
// Show bottom buttons
|
||
x = '<div class="p10html3right">';
|
||
if ((meshrights & 4) != 0) {
|
||
// TODO: Show change group only if there is another mesh of the same type.
|
||
x += ' <a href=# onclick=p10showChangeGroupDialog(["' + node._id + '"]) title=\"' + "このデバイスを別のデバイスグループに移動する" + '\">' + "グループを変更" + '</a>';
|
||
x += ' <a href=# onclick=p10showDeleteNodeDialog("' + node._id + '") title=\"' + "このデバイスを削除" + '\">' + "デバイスを削除" + '</a>';
|
||
}
|
||
x += '</div><div class="p10html3left">';
|
||
if (mesh.mtype == 2) x += '<a href=# onclick=p10showNodeNetInfoDialog("' + node._id + '") title=\"' + "デバイスのネットワークインターフェイス情報を表示する" + '\">' + "インターフェース" + '</a> ';
|
||
if (xxmap != null) x += '<a href=# onclick=p10showNodeLocationDialog("' + node._id + '") title=\"' + "デバイスの位置情報を表示する" + '\">' + "ロケーション" + '</a> ';
|
||
if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a href=# onclick=p10showMeshCmdDialog(1,"' + node._id + '") title=\"' + "このサーバーを介してデバイスに接続するために使用されるトラフィックルーター" + '.\">' + "ルーター" + '</a> ';
|
||
|
||
// 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 href=# onclick=p10clickOnce("' + node._id + '","RDP2",3389) title=\"' + "ブラウザでMicrosoft ClickOnceサポートが必要です" + '.\">' + "RDP" + '</a> '; }
|
||
if (node.agent.id > 4) {
|
||
x += '<a href=# onclick=p10clickOnce("' + node._id + '","PSSH",22) title=\"' + "ブラウザでMicrosoft ClickOnceサポートが必要です。" + '\">' + "パテ" + '</a> ';
|
||
x += '<a href=# onclick=p10clickOnce("' + node._id + '","WSCP",22) title=\"' + "ブラウザでMicrosoft ClickOnceサポートが必要です。" + '\">' + "WinSCP" + '</a> ';
|
||
}
|
||
}
|
||
|
||
// MQTT options
|
||
if ((meshrights == 0xFFFFFFFF) && (features & 0x00400000)) { x += '<a href=# onclick=p10showMqttLoginDialog("' + node._id + '") title=\"' + "このデバイスのMQTTログイン資格情報を取得します。" + '\">' + "MQTTログイン" + '</a> '; }
|
||
x += '</div><br>'
|
||
|
||
QH('p10html3', x);
|
||
|
||
// Set the node power state
|
||
var 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=\"' + "接続されたエージェント" + '\">' + "接続されたエージェント" + '</span>'; }
|
||
if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "Intel®接続されたAMT" + '\">' + "Intel®接続されたAMT" + '</span>'; }
|
||
else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "Intel® AMTが検出されました" + '\">' + "Intel® AMTが検出されました" + '</span>'; }
|
||
if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "MQTT接続済み" + '\">' + "MQTTチャネルが接続されました" + '</span>'; }
|
||
if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>' + "最後に見たのは:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>'; }
|
||
QH('MainComputerState', powerstate);
|
||
|
||
// Set the node icon
|
||
Q('MainComputerImage').setAttribute('src', 'images/icons256-' + node.icon + '-1.png');
|
||
Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
|
||
|
||
// Check if we have terminal and file access
|
||
var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
|
||
var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
|
||
var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0));
|
||
|
||
// Setup/Refresh the desktop tab
|
||
if (terminalAccess) { setupTerminal(); }
|
||
if (fileAccess) { 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) && ((typeof node.intelamt.sku !== 'number') || ((node.intelamt.sku & 8) != 0)))
|
||
|| ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2)))))
|
||
&& ((meshrights & 8) || (meshrights & 256))
|
||
);
|
||
QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
|
||
QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
|
||
QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8) && amtAccess);
|
||
QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
|
||
QV('MainDevPlugins', false);
|
||
QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
|
||
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)) {
|
||
QH('p10html2', '');
|
||
powerTimelineReq = currentNode._id;
|
||
meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
|
||
meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
|
||
meshserver.send({ action: 'getsysinfo', nodeid: currentNode._id });
|
||
QH('p17info', '');
|
||
}
|
||
|
||
// Reset the desktop tools
|
||
QV('DeskTools', false);
|
||
showDeskToolsProcesses();
|
||
|
||
// Ask for device events
|
||
refreshDeviceEvents();
|
||
|
||
// Update the web page title
|
||
if ((currentNode) && (xxcurrentView >= 10) && (xxcurrentView < 20)) {
|
||
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + mesh.name;
|
||
} else {
|
||
document.title = decodeURIComponent('{{{extitle}}}');
|
||
}
|
||
|
||
// Clear user consent status if present
|
||
p11clearConsoleMsg();
|
||
p12clearConsoleMsg();
|
||
p13clearConsoleMsg();
|
||
|
||
// Device refresh plugin handler
|
||
if (pluginHandler != null) {
|
||
QH('p19headers', ''); QH('p19pages', '');
|
||
pluginHandler.callHook('onDeviceRefreshEnd', nodeid, panel, refresh, event);
|
||
var lastTab = getstore('_curPluginPage', null);
|
||
if (lastTab != null && Q('p19ph-' + lastTab) != null) pluginHandler.callPluginPage(lastTab, Q('p19ph-' + lastTab));
|
||
}
|
||
}
|
||
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 writeDeviceEvent(nodeid) {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "デバイスイベントを追加", 3, writeDeviceEventEx, '<textarea id=d2devEvent style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>' + "これにより、このデバイスのイベントログにエントリが追加されます。" + '<span>', nodeid);
|
||
}
|
||
|
||
function writeDeviceEventEx(buttons, tag) { meshserver.send({ action: 'setDeviceEvent', nodeid: decodeURIComponent(tag), msg: encodeURIComponent(Q('d2devEvent').value) }); }
|
||
|
||
function showNotes(readonly, noteid) {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "ノート", 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>' + "デバイスグループのメモは、他のデバイスグループ管理者が表示および変更できます。" + '<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 deviceChat(e) {
|
||
if (xxdialogMode) return;
|
||
var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
if (e && (e.shiftKey == true)) {
|
||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||
} else {
|
||
window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
|
||
}
|
||
meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
|
||
}
|
||
|
||
function deviceToggleBackground() {
|
||
if (xxdialogMode) return;
|
||
meshserver.send({ action: 'msg', type: 'deskBackground', nodeid: currentNode._id, op: 1 }); // Toggle desktop background image
|
||
}
|
||
|
||
function deviceUrlFunction() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "デバイスでページを開く", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
|
||
Q('d2devurl').focus();
|
||
}
|
||
|
||
function deviceUrlFunctionEx() {
|
||
meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
|
||
}
|
||
|
||
function deviceToastFunction() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "デバイス通知", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
|
||
Q('d2devToast').focus();
|
||
}
|
||
|
||
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[userinfo._id].rights;
|
||
var x = "このデバイスで実行する操作を選択します。" + '<br /><br />';
|
||
var y = '<select id=d2deviceop style=float:right;width:250px>';
|
||
if ((meshrights & 64) != 0) { y += '<option value=100>' + "目を覚ます" + '</option>'; } // Wake-up permission
|
||
if ((meshrights & 8) != 0) { y += '<option value=4>' + "睡眠" + '</option><option value=3>' + "リセットする" + '</option><option value=2>' + "電源を切る" + '</option>'; } // Remote control permission
|
||
if ((currentNode.conn & 16) != 0) { y += '<option value=103>' + "MQTTメッセージを送信" + '</option>'; }
|
||
if (((currentNode.conn & 1) != 0) && ((meshrights & 32768) != 0)) { y += '<option value=104>' + "エージェントのアンインストール" + '</option>'; }
|
||
y += '</select>';
|
||
x += addHtmlValue("操作", y);
|
||
setDialogMode(2, "デバイスアクション", 3, deviceActionFunctionEx, x);
|
||
}
|
||
|
||
function deviceActionFunctionEx() {
|
||
var op = Q('d2deviceop').value;
|
||
if (op == 100) {
|
||
// Device wake
|
||
meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] });
|
||
} else if (op == 103) {
|
||
// Send MQTT Message
|
||
p10showSendMqttMsgDialog([currentNode._id]);
|
||
} else if (op == 104) {
|
||
// Uninstall agent
|
||
p10showSendUninstallAgentDialog([currentNode._id]);
|
||
} else {
|
||
// Power operation
|
||
meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: parseInt(op) });
|
||
}
|
||
}
|
||
|
||
// Called when MeshCommander needs new credentials or updated credentials.
|
||
function updateAmtCredentials(forceDialog) {
|
||
var node = getNodeFromId(currentNode._id);
|
||
if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
|
||
editDeviceAmtSettings(currentNode._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 });
|
||
meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
|
||
}
|
||
}
|
||
|
||
// Draw device power bars. The bars are 766px wide.
|
||
function drawDeviceTimeline() {
|
||
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19)) return;
|
||
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();
|
||
var totalWidth = Q('masthead').offsetWidth - (160 + 9 + 9 + 14); // Compute the total width of the power bar
|
||
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) * totalWidth) / 86400000);
|
||
if (width > 0) {
|
||
var title = format('{0} from {1} to {2}.', powerStateStrings2[block[2]], printTime(new Date(ts)), printTime(new Date(te)));
|
||
datavalue += '<div class="pwState ' + powerColor(block[2]) + '" title="' + title + '" style="width:' + width + 'px;"></div>';
|
||
}
|
||
}
|
||
}
|
||
x += '<tr class=' + (((count % 2) == 0)?'altBack':'') + '><td><div> ' + printDate(date) + '<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 cellpadding=2 cellspacing=0><thead><tr style=><th scope=col style=text-align:center;width:150px>' + "日" + '</th><th scope=col style=text-align:center><a download href="devicepowerevents.ashx?id=' + currentNode._id + '" onclick="setDialogMode(0)"><img title=\"' + "電源イベントをダウンロードする" + '\" src="images/link4.png" /></a>' + "7日間の電源状態" + '</th></tr></thead><tbody>' + x + '</tbody></table>');
|
||
}
|
||
|
||
// Return a color for the given power state
|
||
function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'pwsYellow'; }
|
||
|
||
// 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>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
|
||
|
||
function editDeviceAmtSettings(nodeid, func, arg) {
|
||
if (xxdialogMode) return;
|
||
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
||
if ((meshrights & 4) == 0) return;
|
||
x += addHtmlValue("ユーザー名", '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||
x += addHtmlValue("パスワード", '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||
x += addHtmlValue("セキュリティ", '<select id=dp10tls style=width:236px><option value=0>' + "TLSセキュリティなし" + '</option><option value=1>' + "TLSセキュリティが必要" + '</option></select>');
|
||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
||
setDialogMode(2, "Intelを編集® AMTクレデンシャル", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
|
||
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(function () { tag.func(null, tag.arg); }, 300); }
|
||
}
|
||
}
|
||
|
||
function p10showSendMqttMsgDialog(nodeids) {
|
||
if (xxdialogMode) return false;
|
||
var x = addHtmlValue("トピック", '<input id=dp2topic style=width:230px maxlength=64 onchange=p10validateSendMqttMsgDialog() onkeyup=p10validateSendMqttMsgDialog(event,1) />');
|
||
x += addHtmlValue("メッセージ", '<div style=width:230px;margin:0;padding:0><textarea id=dp2msg maxlength=4096 style=width:100%;height:150px;resize:none onchange=p10validateSendMqttMsgDialog() onkeyup=p10validateSendMqttMsgDialog(event,1)></textarea></div>');
|
||
setDialogMode(2, "MQTTメッセージを送信", 3, p10showSendMqttMsgDialogEx, x, nodeids);
|
||
p10validateSendMqttMsgDialog();
|
||
Q('dp2topic').focus();
|
||
return false;
|
||
}
|
||
|
||
function p10validateSendMqttMsgDialog() {
|
||
QE('idx_dlgOkButton', (Q('dp2topic').value.length > 0) && (Q('dp2msg').value.length > 0));
|
||
}
|
||
|
||
function p10showSendMqttMsgDialogEx(b, nodeids) {
|
||
meshserver.send({ action: 'sendmqttmsg', nodeids: nodeids, topic: Q('dp2topic').value, msg: Q('dp2msg').value });
|
||
}
|
||
|
||
function p10showSendUninstallAgentDialog(nodeids) {
|
||
if (xxdialogMode) return false;
|
||
var x = '';
|
||
if (nodeids.length > 1) { x = format("選択した{0}エージェントをアンインストールしてもよろしいですか?", nodeids.length); } else { x = "選択したエージェントをアンインストールしてもよろしいですか?"; }
|
||
x += '<br /><br />';
|
||
if (nodeids.length > 1) { x += "これによりサーバーからデバイスが削除されることはありませんが、デバイスはサーバーに接続できなくなります。デバイスへのすべてのリモートアクセスが失われます。このコマンドが機能するには、デバイスが接続されている必要があります。"; } else { x += "このデバイスはサーバーから削除されませんが、デバイスはサーバーに接続できなくなります。デバイスへのすべてのリモートアクセスが失われます。このコマンドが機能するには、デバイスが接続されている必要があります。"; }
|
||
x += '<br /><br /><label style=color:red><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "確認する" + '</label>';
|
||
setDialogMode(2, "エージェントをアンインストールする", 3, p10showSendUninstallAgentDialogEx, x, nodeids);
|
||
p10validateSendUninstallAgentDialog();
|
||
return false;
|
||
}
|
||
|
||
function p10validateSendUninstallAgentDialog() { QE('idx_dlgOkButton', Q('p10check').checked); }
|
||
function p10showSendUninstallAgentDialogEx(b, nodeids) { meshserver.send({ action: 'uninstallagent', nodeids: nodeids }); }
|
||
|
||
function p10showChangeGroupDialog(nodeids) {
|
||
if (xxdialogMode) return false;
|
||
var targetMeshId = null;
|
||
if (nodeids.length == 1) { try { targetMeshId = meshes[getNodeFromId(nodeids[0])]._id; } catch (ex) { } }
|
||
|
||
// List all available alternative groups
|
||
var y = '<select id=p10newGroup style=width:236px>', count = 0;
|
||
for (var i in meshes) {
|
||
var meshrights = meshes[i].links[userinfo._id].rights;
|
||
if ((meshes[i]._id != targetMeshId) && (meshrights & 4)) { count++; y += '<option value=\'' + meshes[i]._id + '\'>' + meshes[i].name + '</option>'; }
|
||
}
|
||
y += '</select>';
|
||
|
||
if (count > 0) {
|
||
var x = (nodeids.length == 1) ? ("このデバイスの新しいグループを選択してください" + '<br /><br />') : ("選択したデバイスの新しいグループを選択します" + '<br /><br />');
|
||
x += addHtmlValue("新しいデバイスグループ", y);
|
||
setDialogMode(2, "グループを変更", 3, p10showChangeGroupDialogEx, x, nodeids);
|
||
} else {
|
||
setDialogMode(2, "グループを変更", 1, null, "同じタイプの他のデバイスグループは存在しません。");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function p10showChangeGroupDialogEx(b, nodeids) {
|
||
meshserver.send({ action: 'changeDeviceMesh', nodeids: nodeids, meshid: Q('p10newGroup').value });
|
||
}
|
||
|
||
function p10showDeleteNodeDialog(nodeid) {
|
||
if (xxdialogMode) return false;
|
||
var x = format("ノード{0}を削除してもよろしいですか?", EscapeHtml(currentNode.name)) + '<br /><br /><label><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "確認する" + '</label>';
|
||
setDialogMode(2, "ノードを削除", 3, p10showDeleteNodeDialogEx, x, nodeid);
|
||
p10validateDeleteNodeDialog();
|
||
return false;
|
||
}
|
||
|
||
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 });
|
||
return false;
|
||
}
|
||
|
||
// Show current location
|
||
var d2map = null;
|
||
function p10showNodeLocationDialog() {
|
||
if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return false; }
|
||
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" rel="noreferrer noopener" target=_blank>Open in Google maps</a></div>';
|
||
var x = '<div id=d2map style=width:100%;height:300px></div>';
|
||
setDialogMode(2, "デバイスの場所", 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 })
|
||
});
|
||
return false;
|
||
}
|
||
|
||
// Show network interfaces
|
||
function p10showNodeNetInfoDialog() {
|
||
if (xxdialogMode) return false;
|
||
setDialogMode(2, "ネットワークインターフェース", 1, null, '<div id=d2netinfo>' + "読み込み中..." + '</div>', 'if' + currentNode._id );
|
||
meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id });
|
||
return false;
|
||
}
|
||
|
||
// Show MeshCentral Router dialog
|
||
function p10showMeshRouterDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = '<div>' + "MeshCentralルーターは、TCPポートマッピング用のWindowsツールです。たとえば、このサーバーを介してRDPをリモートデバイスに接続できます。" + '</div><br />';
|
||
x += addHtmlValue('Win32 Executable', '<a style=cursor:pointer download href="meshagents?meshaction=winrouter" onclick="setDialogMode(0)">MeshCentralRouter.exe</a>');
|
||
setDialogMode(2, "MeshCentralルーター", 1, null, x, 'fileDownload');
|
||
}
|
||
|
||
// Request MQTT login credentials
|
||
function p10showMqttLoginDialog(nodeid) { meshserver.send({ action: 'getmqttlogin', nodeid: nodeid }); }
|
||
|
||
// Show MeshCmd dialog
|
||
function p10showMeshCmdDialog(mode, nodeid) {
|
||
if (xxdialogMode) return;
|
||
var y = '<select id=aginsSelect onclick=meshCmdOsClick() style=width:236px>';
|
||
y += '<option value=3>' + "Windows(32ビット)" + '</option>';
|
||
y += '<option value=4>' + "Windows(64ビット)" + '</option>';
|
||
y += '<option value=5>' + "Linux x86(32ビット)" + '</option>';
|
||
y += '<option value=6>' + "Linux x86(64ビット)" + '</option>';
|
||
y += '<option value=16>' + "MacOS(64ビット)" + '</option>';
|
||
y += '<option value=25>' + "Linux ARM、Raspberry Pi(32ビット)" + '</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" download></a>');
|
||
if (mode == 0) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=generic" download>MeshAction (.txt)</a>'); }
|
||
if (mode == 1) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=route&nodeid=' + nodeid + '" download>MeshAction (.txt)</a>'); }
|
||
x += '</div>';
|
||
setDialogMode(2, [ "MeshCmdをダウンロード", "ネットワークルーター" ][mode], 9, null, x, 'fileDownload');
|
||
meshCmdOsClick();
|
||
}
|
||
|
||
function meshCmdOsClick() {
|
||
var os = Q('aginsSelect').value, osn = '', osurl = '';
|
||
//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 == 16) { osn = 'MeshCmd (MacOS, 64bit)'; }
|
||
if (os == 25) { osn = 'MeshCmd (Linux ARM, 32bit)'; }
|
||
QH('meshcmddownloadid', osn);
|
||
Q('meshcmddownloadid').setAttribute('href', 'meshagents?meshcmd=' + os);
|
||
}
|
||
|
||
function p10showiconselector() {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
if ((meshrights & 4) == 0) return;
|
||
|
||
var x = '<br><div style=display:inline-block;width:40px></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i1 onclick=p10setIcon(1) onkeypress="if (event.key==\'Enter\') p10setIcon(1)"></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i2 onclick=p10setIcon(2) onkeypress="if (event.key==\'Enter\') p10setIcon(2)"></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i3 onclick=p10setIcon(3) onkeypress="if (event.key==\'Enter\') p10setIcon(3)"></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i4 onclick=p10setIcon(4) onkeypress="if (event.key==\'Enter\') p10setIcon(4)"></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i5 onclick=p10setIcon(5) onkeypress="if (event.key==\'Enter\') p10setIcon(5)"></div>';
|
||
x += '<div tabindex=0 style=display:inline-block class=i6 onclick=p10setIcon(6) onkeypress="if (event.key==\'Enter\') p10setIcon(6)"></div><br><br>';
|
||
setDialogMode(2, "アイコンの選択", 0, null, x);
|
||
QV('id_dialogclose', true);
|
||
}
|
||
|
||
function p10setIcon(icon) {
|
||
setDialogMode(0);
|
||
meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
|
||
}
|
||
|
||
var showEditNodeValueDialog_modes = ["装置名", "ホスト名", "説明", "タグ"];
|
||
var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
|
||
var showEditNodeValueDialog_modes3 = ['', '', '', "Tag1、Tag2、Tag3"];
|
||
function showEditNodeValueDialog(mode) {
|
||
if (xxdialogMode) return;
|
||
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
|
||
setDialogMode(2, "デバイスを編集", 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(); 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('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 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();
|
||
deskAdjust();
|
||
|
||
// 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; }
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
|
||
// Show the right buttons
|
||
QV('disconnectbutton1span', (deskState != 0));
|
||
QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
|
||
QV('connectbutton1hspan',
|
||
(deskState == 0) &&
|
||
(meshrights & 8) &&
|
||
((mesh.mtype == 1) ||
|
||
((currentNode.intelamt != null) &&
|
||
(currentNode.intelamt.state == 2) &&
|
||
(currentNode.intelamt.ver != null) &&
|
||
(typeof currentNode.intelamt.sku == 'number') &&
|
||
((currentNode.intelamt.sku & 8) != 0))
|
||
)
|
||
);
|
||
|
||
// Show the right settings
|
||
QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
|
||
QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
|
||
|
||
// Enable buttons
|
||
var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
|
||
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));
|
||
QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS
|
||
QE('DeskClip', deskState == 3);
|
||
QE('DeskType', deskState == 3);
|
||
QV('DeskWD', inputAllowed);
|
||
QE('DeskWD', deskState == 3);
|
||
QV('deskkeys', inputAllowed);
|
||
QE('deskkeys', deskState == 3);
|
||
|
||
// Display this only if we have Chat & Notify permissions
|
||
QV('DeskChatButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskNotifyButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
|
||
QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskBackgroundButton', (deskState == 3) && (desktop.contype == 1) && (mesh.mtype == 2) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && online);
|
||
QV('DeskControlSpan', inputAllowed)
|
||
QV('deskActionsBtn', (browserfullscreen == false));
|
||
QV('deskActionsSettings', (browserfullscreen == false));
|
||
if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
|
||
if (online == false) QV('DeskTools', false);
|
||
}
|
||
|
||
// Debug
|
||
var autoConnectDesktopTimer = null;
|
||
function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(function() { connectDesktop(null, 1) }, 1000); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
|
||
|
||
function connectDesktop(e, contype, tsid) {
|
||
if (xxdialogMode) return;
|
||
if ((e != null) && (e.shiftKey == false) && (contype == 3)) { contype = 1; } // If the shift key is not pressed, don't try to ask for session list.
|
||
QV('p11DeskSessionSelector', false);
|
||
p11clearConsoleMsg();
|
||
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, 2); return; }
|
||
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
||
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.localKeyMap = desktopsettings.localkeymap;
|
||
desktop.m.showmouse = desktopsettings.showmouse;
|
||
desktop.m.onScreenSizeChange = deskAdjust;
|
||
desktop.m.onKvmData = function (x) {
|
||
//console.log('onKvmData (' + x.length + '): ' + x);
|
||
// Send the presense probe only once if needed.
|
||
if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
|
||
var data = null;
|
||
try { data = JSON.parse(x); } catch (e) { }
|
||
if ((data != null) && (data.action != null)) {
|
||
if (data.action == 'restart') {
|
||
// Clear WebRTC channel
|
||
webRtcDesktopReset();
|
||
desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
|
||
} else if ((data.action == 'present') && (webRtcDesktop == null)) {
|
||
// Setup WebRTC channel
|
||
webRtcDesktop = { platform: data.platform };
|
||
var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
|
||
if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
|
||
else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }
|
||
|
||
webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("データチャネル", {}); // { ordered: false, maxRetransmits: 2 }
|
||
webRtcDesktop.webchannel.onopen = function () {
|
||
// Switch to software KVM
|
||
//if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
|
||
console.log('WebRTC Data Channel Open');
|
||
Q('deskstatus').textContent = StatusStrs[desktop.State] + "、Soft-KVM";
|
||
desktop.m.hold(true);
|
||
webRtcDesktop.webRtcActive = true;
|
||
webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
|
||
webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
|
||
webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
|
||
if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
|
||
if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
|
||
webRtcDesktop.softdesktop.Start();
|
||
|
||
// Check if we can get remote file access
|
||
// ###BEGIN###{DesktopInbandFiles}
|
||
/*
|
||
QV('go24', true); // Files
|
||
downloadFile = null;
|
||
p24files = webRtcDesktop.softdesktop;
|
||
p24targetpath = '';
|
||
webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
|
||
webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
|
||
*/
|
||
// ###END###{DesktopInbandFiles}
|
||
}
|
||
webRtcDesktop.webchannel.onclose = function (event) {
|
||
//if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); }
|
||
console.log('WebRTC Data Channel Closed');
|
||
webRtcDesktopReset();
|
||
}
|
||
webRtcDesktop.webrtc.onicecandidate = function (e) {
|
||
if (e.candidate == null) {
|
||
desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
|
||
} else {
|
||
webRtcDesktop.webrtcoffer.sdp += ('a=' + e.candidate.candidate + '\r\n'); // New candidate, add it to the SDP
|
||
}
|
||
}
|
||
webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
|
||
if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
|
||
}
|
||
webRtcDesktop.webrtc.createOffer(function (offer) {
|
||
// Got the offer
|
||
webRtcDesktop.webrtcoffer = offer;
|
||
webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
|
||
}, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
|
||
} else if ((data.action == 'answer') && (webRtcDesktop != null)) {
|
||
// Complete the WebRTC channel
|
||
webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
|
||
}
|
||
}
|
||
};
|
||
desktop.Start(desktopNode._id, 16994, '*', '*', 0);
|
||
desktop.contype = 2;
|
||
} else if ((contype == null) || (contype == 1) || ((contype == 3) && (currentNode.agent.id > 4))) {
|
||
// Setup the Mesh Agent remote desktop
|
||
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||
desktop.debugmode = debugmode;
|
||
desktop.m.debugmode = debugmode;
|
||
desktop.attemptWebRTC = attemptWebRTC;
|
||
if (tsid != null) { desktop.options = { tsid: tsid }; }
|
||
desktop.onStateChanged = onDesktopStateChange;
|
||
desktop.onConsoleMessageChange = function () {
|
||
p11clearConsoleMsg();
|
||
if (desktop.consoleMessage) {
|
||
QH('p11DeskConsoleMsg', EscapeHtml(desktop.consoleMessage).split('\n').join('<br />'));
|
||
QV('p11DeskConsoleMsg', true);
|
||
p11DeskConsoleMsgTimer = setTimeout(p11clearConsoleMsg, 8000);
|
||
}
|
||
}
|
||
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 if (contype == 3) {
|
||
// Ask for user sessions
|
||
meshserver.send({ action: 'msg', type: 'userSessions', nodeid: currentNode._id });
|
||
}
|
||
} else {
|
||
// Disconnect and clean up the remote desktop
|
||
desktop.Stop();
|
||
webRtcDesktopReset();
|
||
desktopNode = desktop = null;
|
||
if (pluginHandler != null) { pluginHandler.callHook('onDesktopDisconnect'); }
|
||
}
|
||
}
|
||
|
||
function p11clearConsoleMsg() { QV('p11DeskConsoleMsg', false); if (p11DeskConsoleMsgTimer) { clearTimeout(p11DeskConsoleMsgTimer); p11DeskConsoleMsgTimer = null; } }
|
||
function p12clearConsoleMsg() { QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
|
||
function p13clearConsoleMsg() { QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
|
||
|
||
var webRtcDesktop = null;
|
||
function webRtcDesktopReset() {
|
||
if (webRtcDesktop == null) return;
|
||
if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
|
||
if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
|
||
if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
|
||
webRtcDesktop = null;
|
||
// Switch back to hardware KVM
|
||
if (desktop && desktop.m) {
|
||
desktop.m.hold(false);
|
||
Q('deskstatus').textContent = StatusStrs[desktop.State];
|
||
}
|
||
// ###BEGIN###{DesktopInbandFiles}
|
||
/*
|
||
p24files = null;
|
||
p24downloadFileCancel() // If any downloads are in process, cancel them.
|
||
p24uploadFileCancel(); // If any uploads are in process, cancel them.
|
||
QV('go24', false); // Files
|
||
if (currentView == 24) { go(14); }
|
||
*/
|
||
// ###END###{DesktopInbandFiles}
|
||
}
|
||
|
||
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();
|
||
desktopNode = desktop = null;
|
||
QV('DeskFocus', false);
|
||
QV('termdisplays', false);
|
||
QV('deskRecordIcon', false);
|
||
deskFocusBtn.value = "オールフォーカス";
|
||
if (fullscreen == true) { deskToggleFull(); }
|
||
webRtcDesktopReset();
|
||
deskPreferedStickyDisplay = 0;
|
||
break;
|
||
case 2:
|
||
break;
|
||
case 3:
|
||
if (desktop && (desktop.serverIsRecording == true)) { QV('deskRecordIcon', true); }
|
||
desktop.startTime = new Date();
|
||
if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
|
||
break;
|
||
default:
|
||
//console.log('Unknown onDesktopStateChange state', state);
|
||
break;
|
||
}
|
||
updateDesktopButtons();
|
||
deskAdjust();
|
||
setTimeout(deskAdjust, 50);
|
||
}
|
||
|
||
function updateSessionTime() {
|
||
// Desktop
|
||
var seconds = 0;
|
||
if (desktop && desktop.startTime) {
|
||
seconds = Math.floor((new Date() - desktop.startTime) / 1000);
|
||
QH('DeskTimer', zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
|
||
} else {
|
||
QH('DeskTimer', '');
|
||
}
|
||
|
||
// Terminal
|
||
seconds = 0;
|
||
if (terminal && terminal.startTime) {
|
||
seconds = Math.floor((new Date() - terminal.startTime) / 1000);
|
||
QH('TermTimer', zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
|
||
} else {
|
||
QH('TermTimer', '');
|
||
}
|
||
|
||
if ((desktop == null) && (terminal == null)) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
|
||
}
|
||
|
||
function showDesktopSettings() {
|
||
if (xxdialogMode) return;
|
||
applyDesktopSettings();
|
||
updateDesktopButtons();
|
||
setDialogMode(7, "リモートデスクトップ設定", 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;
|
||
desktopsettings.localkeymap = d7localKeyMap.checked;
|
||
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 = "オールフォーカス"; }
|
||
if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function applyDesktopSettings() {
|
||
var r = '', ops = (features & 512)?[90,80,70,60,50,40,30,20,10,5,1]:[60,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; }
|
||
if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
|
||
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
|
||
}
|
||
|
||
// Enter browser fullscreen
|
||
function enterBrowserFullscreen(elem) {
|
||
if (elem.requestFullscreen) { elem.requestFullscreen(); }
|
||
else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); }
|
||
else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); }
|
||
else if (elem.webkitRequestFullscreen) { elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); }
|
||
}
|
||
|
||
// Exit browser fullscreen
|
||
function exitBrowserFullscreen() {
|
||
if (document.exitFullscreen) { document.exitFullscreen(); }
|
||
else if (document.msExitFullscreen) { document.msExitFullscreen(); }
|
||
else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); }
|
||
else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); }
|
||
}
|
||
|
||
// Return true if the browser is fullscreen. This is a delayed method that will return true/false late. Not very useful.
|
||
function isBrowserFullscreen() {
|
||
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) { return false; } else { return true; }
|
||
}
|
||
|
||
var fullscreen = false;
|
||
var browserfullscreen = false;
|
||
function deskToggleFull(e) {
|
||
fullscreen = !fullscreen;
|
||
if (fullscreen) {
|
||
QC('body').add('fulldesk');
|
||
QS('deskarea3x')['height'] = '100%';
|
||
QS('deskarea3x')['max-height'] = '100%';
|
||
// If shift is pressed, enter browser full screen.
|
||
if (e.shiftKey == true) { enterBrowserFullscreen(Q('deskarea0')); browserfullscreen = true; }
|
||
} else {
|
||
QC('body').remove('fulldesk');
|
||
var xh = (((args.hide & 1) ? 0 : 66) + ((args.hide & 2) ? 0 : 24) + ((args.hide & 4) ? 0 : 45) + ((args.hide & 8) ? 0 : 60)); // 0 to 195
|
||
QS('deskarea3x')['height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
|
||
QS('deskarea3x')['max-height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
|
||
if (browserfullscreen == true) { exitBrowserFullscreen(); browserfullscreen = false; }
|
||
}
|
||
deskAdjust();
|
||
updateDesktopButtons();
|
||
}
|
||
|
||
function deskToggleFocus() {
|
||
desktop.m.focusmode = (desktop.m.focusmode + 64) % 192;
|
||
Q('deskFocusBtn').value = ["オールフォーカス", "小焦点", "大焦点"][desktop.m.focusmode / 64];
|
||
}
|
||
|
||
function deskAdjust() {
|
||
var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
|
||
var deskH = Q('Desk').height, deskW = Q('Desk').width;
|
||
|
||
if (deskAspectRatio == 2) {
|
||
// Scale mode
|
||
QS('Desk')['margin-top'] = null;
|
||
QS('Desk').height = '100%';
|
||
QS('Desk').width = '100%';
|
||
//QS('deskarea3x').height = null;
|
||
QS('DeskParent').overflow = 'hidden';
|
||
} else if (deskAspectRatio == 1) {
|
||
// Zoomed mode
|
||
QS('Desk')['margin-top'] = '0px';
|
||
QS('Desk').height = deskH + 'px';
|
||
QS('Desk').width = deskW + 'px';
|
||
QS('DeskParent').overflow = 'scroll';
|
||
} else {
|
||
// Fixed aspect ratio
|
||
if ((parentH / parentW) > (deskH / deskW)) {
|
||
var hNew = ((deskH * parentW) / deskW) + 'px';
|
||
//if (webPageFullScreen || fullscreen) {
|
||
//QS('deskarea3x').height = null;
|
||
//} else {
|
||
// QS('deskarea3x').height = hNew;
|
||
//QS('deskarea3x').height = null;
|
||
//}
|
||
QS('Desk').height = hNew;
|
||
QS('Desk').width = '100%';
|
||
} else {
|
||
var wNew = ((deskW * parentH) / deskH) + 'px';
|
||
if (webPageFullScreen || fullscreen) {
|
||
QS('Desk').height = null;
|
||
} else {
|
||
QS('Desk').height = '100%';
|
||
}
|
||
QS('Desk').width = wNew;
|
||
}
|
||
QS('Desk')['margin-top'] = null;
|
||
QS('DeskParent').overflow = 'hidden';
|
||
}
|
||
}
|
||
|
||
function mdeskAdjust(mod, sw, sh, cv) {
|
||
if (!mod || !sw || !sh || !cv) return;
|
||
|
||
// Check if we are in single desktop mode
|
||
if (cv.id == 'Desk') { deskAdjust(); return; }
|
||
|
||
// Figure out and adjust the size to fill the width of the div
|
||
var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
|
||
var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
|
||
xw = realw + Math.floor((tw - (xw * realw)) / xw);
|
||
vsize.y = vsize.y * (xw / vsize.x);
|
||
vsize.x = xw;
|
||
var mh = vsize.y, mw = vsize.x;
|
||
if (mod.State != 0) { mh = vsize.y; mw = (sw / sh) * vsize.y; }
|
||
QS(cv.id)['max-height'] = mh + 'px';
|
||
QS(cv.id)['max-width'] = mw + 'px';
|
||
QS(cv.id)['margin-top'] = '0';
|
||
QS(cv.id)['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.sendCtrlMsg('{"action":"lock"}');
|
||
//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
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
|
||
}
|
||
} 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
|
||
}
|
||
} else if (ks == 5) { // WIN
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0xffe7,0]]); // Intel AMT: Meta-left down, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B], [desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
|
||
}
|
||
} else if (ks == 6) { // WIN+R
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0x72,1],[0x72,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'r' press, 'r' release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 82], [desktop.m.KeyAction.UP, 82], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'R' press, 'R' release, L-Winkey release
|
||
}
|
||
} else if (ks == 7) { // ALT-F4
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe9,1],[0xffc1,1],[0xffc1,0],[0xffe9,0]]); // Intel AMT: Alt down, 'F4' press, 'F4' release, Alt release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 115], [desktop.m.KeyAction.UP, 115], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'F4' press, 'F4' release, Alt release
|
||
}
|
||
} else if (ks == 8) { // CTRL-W
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe3,1],[0x77,1],[0x77,0],[0xffe3,0]]); // Intel AMT: Ctrl down, 'w' press, 'w' release, Ctrl release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 17], [desktop.m.KeyAction.DOWN, 87], [desktop.m.KeyAction.UP, 87], [desktop.m.KeyAction.EXUP, 17]]); // MeshAgent: Ctrl press, 'W' press, 'W' release, Ctrl release
|
||
}
|
||
} else if (ks == 9) { // ALT-TAB
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'TAB' press, 'TAB' release, Alt release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'TAB' press, 'TAB' release, Alt release
|
||
}
|
||
} else if (ks == 10) { // CTRL-ALT-DEL
|
||
desktop.m.sendcad();
|
||
} else if (ks == 11) { // WIN-LEFT
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7, 1], [0xff51, 1], [0xff51, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Left arrow press, Left arrow release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 37], [desktop.m.KeyAction.UP, 37], [desktop.m.KeyAction.EXUP, 0x5B]]);
|
||
}
|
||
} else if (ks == 12) { // WIN-RIGHT
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7, 1], [0xff53, 1], [0xff53, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Right arrow press, Right arrow release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 39], [desktop.m.KeyAction.UP, 39], [desktop.m.KeyAction.EXUP, 0x5B]]);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Remote desktop typing
|
||
function showDeskType() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
Q('DeskType').blur();
|
||
var x = '<div>' + "テキストを入力し、[OK]をクリックして、米国英語キーボードを使用してリモートで入力します。続行する前に、リモートカーソルを正しい位置に配置してください。" + '<div>';
|
||
x += '<textarea id=d2typeText style="margin-top:5px;width:100%;height:184px;resize:none" maxlength=2000></textarea>';
|
||
setDialogMode(2, "リモートキーボード入力", 3, showDeskTypeEx, x);
|
||
Q('d2typeText').focus();
|
||
}
|
||
|
||
var AmtDeskTypeTimer = null;
|
||
var AmtDeskTypeContent = null;
|
||
var DeskTypeTranslate = { 39: 222, 42: 106, 43: 107, 44: 188, 45: 189, 46: 190, 47: 191, 59: 186, 61: 187, 91: 219, 92: 220, 93: 221, 96: 192, 191: 111 };
|
||
var DeskTypeShiftTranslate = { 33: 49, 34: 222, 35: 51, 36: 52, 37: 53, 38: 55, 40: 57, 41: 48, 58: 186, 60: 188, 62: 190, 63: 191, 64: 50, 94: 54, 95: 189, 106: 56, 107: 187, 123: 219, 124: 220, 125: 221, 126: 192 };
|
||
function showDeskTypeEx() {
|
||
var txt = Q('d2typeText').value, ltxt = Q('d2typeText').value.toUpperCase(), x = [], shift = false;
|
||
if (desktop.contype == 2) {
|
||
// Intel AMT
|
||
for (var i in txt) { var a = txt.charCodeAt(i); x.push([a, 1], [a, 0]); }
|
||
AmtDeskTypeContent = x;
|
||
AmtDeskTypeTimer = setInterval(function () {
|
||
var key = AmtDeskTypeContent.shift();
|
||
if (desktop) { desktop.m.sendkey(key[0], key[1]); }
|
||
if ((desktop == null) || (AmtDeskTypeContent.length == 0)) { clearInterval(AmtDeskTypeTimer); AmtDeskTypeContent = null; }
|
||
}, 10);
|
||
} else {
|
||
// MeshAgent
|
||
for (var i in txt) {
|
||
var a = txt.charCodeAt(i), b = ltxt.charCodeAt(i);
|
||
if (((a >= 65) && (a <= 90)) || ((a >= 97) && (a <= 122))) {
|
||
if ((a == b) && (shift == false)) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
|
||
if ((a != b) && (shift == true)) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // LShift up
|
||
} else if ((a >= 48) && (a <= 57)) {
|
||
if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
|
||
} else if (DeskTypeTranslate[a]) {
|
||
if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
|
||
b = DeskTypeTranslate[a];
|
||
} else if (DeskTypeShiftTranslate[a]) {
|
||
if (shift == false) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
|
||
b = DeskTypeShiftTranslate[a];
|
||
}
|
||
x.push([desktop.m.KeyAction.DOWN, b], [desktop.m.KeyAction.UP, b]);
|
||
}
|
||
if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
|
||
desktop.m.SendKeyMsgKC(x);
|
||
}
|
||
}
|
||
|
||
// Show clipboard dialog
|
||
function showDeskClip() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
Q('DeskClip').blur();
|
||
var x = '';
|
||
x += '<input id=dlgClipGet type=button value="Get Clipboard" style=width:120px onclick=showDeskClipGet()>';
|
||
x += '<input id=dlgClipSet type=button value="Set Clipboard" style=width:120px onclick=showDeskClipSet()>';
|
||
x += '<div id=dlgClipStatus style="display:inline-block;margin-left:8px" ></div>';
|
||
x += '<textarea id=d2clipText style="width:100%;height:184px;resize:none" maxlength=65535></textarea>';
|
||
x += '<input type=button value="Close" style=width:80px;float:right onclick=dialogclose(0)><div style=height:26px;margin-top:3px><span id=linuxClipWarn style=display:none>' + "リモートクリップボードは60秒間有効です。" + '</span> </div><div></div>';
|
||
setDialogMode(2, "リモートクリップボード", 8, null, x, 'clipboard');
|
||
Q('d2clipText').focus();
|
||
}
|
||
|
||
function showDeskClipGet() {
|
||
if (desktop == null || desktop.State != 3) return;
|
||
meshserver.send({ action: 'msg', type: 'getclip', nodeid: currentNode._id });
|
||
}
|
||
|
||
function showDeskClipSet() {
|
||
if (desktop == null || desktop.State != 3) return;
|
||
meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
|
||
QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22));
|
||
}
|
||
|
||
// 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;
|
||
QH('DeskToolsProcesses', '');
|
||
QH('DeskToolsServices', '');
|
||
QV('deskToolsTopTabService', false);
|
||
changeDeskToolTab(0)
|
||
refreshDeskTools(0);
|
||
refreshDeskTools(1);
|
||
} else {
|
||
QV('DeskTools', false);
|
||
}
|
||
}
|
||
|
||
var deskToolTabSelection = 0;
|
||
function changeDeskToolTab(tabnum) {
|
||
deskToolTabSelection = tabnum;
|
||
QV('DeskToolsProcessTab', tabnum == 0);
|
||
QV('DeskToolsServiceTab', tabnum == 1);
|
||
QS('deskToolsTopTabProcess')['bottom'] = (tabnum == 0) ? '0px' : '3px';
|
||
QS('deskToolsTopTabService')['bottom'] = (tabnum == 1) ? '0px' : '3px';
|
||
QS('deskToolsTopTabProcess')['color'] = (tabnum == 0) ? 'black' : 'gray';
|
||
QS('deskToolsTopTabService')['color'] = (tabnum == 1) ? 'black' : 'gray';
|
||
}
|
||
|
||
// Refresh all of the desktop tool panels
|
||
function refreshDeskTools(x) {
|
||
var sel = (x == null) ? deskToolTabSelection : x;
|
||
QV('DeskToolsRefreshButton', false);
|
||
setTimeout(refreshDeskToolsEx, 500);
|
||
if (sel == 0) meshserver.send({ action: 'msg', type: 'ps', nodeid: currentNode._id });
|
||
if (sel == 1) meshserver.send({ action: 'msg', type: 'services', nodeid: currentNode._id });
|
||
}
|
||
function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
|
||
var deskTools = { sort: 1, ssort: 1, msg: null, smsg: null };
|
||
function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
|
||
function sortService(sort) { deskTools.ssort = sort; showDeskToolsServices(deskTools.smsg); }
|
||
function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return sortProcessName(a, b); }
|
||
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) { }
|
||
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) {
|
||
var c = p[i].c;
|
||
if (c.length > 30) { c = '<span title="' + c + '">' + c.substring(0,30) + '...</span>' }
|
||
x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a href=# style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=\'return 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>' + c + '</div></div>';
|
||
}
|
||
}
|
||
QH('DeskToolsProcesses', x);
|
||
}
|
||
}
|
||
function showDeskToolsServices(message) {
|
||
deskTools.smsg = message;
|
||
if (message == null) { QH('DeskToolsProcesses', ''); return; }
|
||
if (Q('DeskTools').nodeid != message.nodeid) return;
|
||
QV('deskToolsTopTabService', true);
|
||
var s = [], services = null;
|
||
try { services = JSON.parse(message.value); } catch (e) { }
|
||
deskTools.services = services;
|
||
if (services != null) {
|
||
for (var i in services) {
|
||
if (services[i].status) {
|
||
// Windows
|
||
s.push({ p: capitalizeFirstLetter(services[i].status.state.toLowerCase()), d: services[i].displayName, i: i });
|
||
} else if (services[i].serviceType) {
|
||
// Linux (TODO: This the service status is not displayed, not sure start/stop/restart will work).
|
||
s.push({ p: services[i].serviceType, d: services[i].name, i: i });
|
||
}
|
||
}
|
||
if (deskTools.ssort == 0) { s.sort(sortProcessPid); } else if (deskTools.ssort == 1) { s.sort(sortProcessName); }
|
||
var x = '';
|
||
for (var i in s) {
|
||
if (s[i].p != 0) {
|
||
var c = s[i].d;
|
||
if (c.length > 30) { c = '<span title="' + c + '">' + c.substring(0, 30) + '...</span>' }
|
||
x += '<div onclick=showServiceDetailsDialog(' + s[i].i + ') class=deskToolsBar><div style=width:70px;float:left;padding-right:5px>' + s[i].p + '</div><div>' + c + '</div></div>';
|
||
}
|
||
}
|
||
QH('DeskToolsServices', x);
|
||
}
|
||
}
|
||
|
||
function showServiceDetailsDialog(index) {
|
||
if (xxdialogMode) return;
|
||
var service = deskTools.services[index];
|
||
if (service != null) {
|
||
var x = '';
|
||
if (service.name) { x += addHtmlValue("名", service.name); }
|
||
if (service.displayName) { x += addHtmlValue("表示名", service.displayName); }
|
||
if (service.status) {
|
||
if (service.status.state) { x += addHtmlValue("状態", capitalizeFirstLetter(service.status.state.toLowerCase())); }
|
||
if (service.status.pid) { x += addHtmlValue("PID", service.status.pid); }
|
||
var serviceTypes = [];
|
||
if (service.status.isFileSystemDriver === true) { serviceTypes.push("FileSystemDriver"); }
|
||
if (service.status.isInteractive === true) { serviceTypes.push("インタラクティブ"); }
|
||
if (service.status.isKernelDriver === true) { serviceTypes.push("KernelDriver"); }
|
||
if (service.status.isOwnProcess === true) { serviceTypes.push("OwnProcess"); }
|
||
if (service.status.isSharedProcess === true) { serviceTypes.push("SharedProcess"); }
|
||
if (serviceTypes.length > 0) { x += addHtmlValue("タイプ", serviceTypes.join(', ')); }
|
||
}
|
||
x += '<br/><div style=float:right;margin-bottom:12px><input type=button value=\"' + "閉じる" + '\" onclick=showServiceDetailsDialogEx(0,' + index + ')></div><div style=margin-bottom:12px><input type=button value=\"' + "開始" + '\" onclick=showServiceDetailsDialogEx(1,' + index + ')><input type=button value=\"' + "やめる" + '\" onclick=showServiceDetailsDialogEx(2,' + index + ')><input type=button value=\"' + "再起動" + '\" onclick=showServiceDetailsDialogEx(3,' + index + ')></div>';
|
||
setDialogMode(2, "サービスの詳細", 8, null, x, name);
|
||
}
|
||
}
|
||
|
||
function showServiceDetailsDialogEx(action, index) {
|
||
setDialogMode(0);
|
||
if (action == 0) return;
|
||
var service = deskTools.services[index];
|
||
if (service != null) {
|
||
if (action == 1) { meshserver.send({ action: 'msg', type: 'serviceStart', nodeid: currentNode._id, serviceName: service.name }); }
|
||
if (action == 2) { meshserver.send({ action: 'msg', type: 'serviceStop', nodeid: currentNode._id, serviceName: service.name }); }
|
||
if (action == 3) { meshserver.send({ action: 'msg', type: 'serviceRestart', nodeid: currentNode._id, serviceName: service.name }); }
|
||
setTimeout(function () { refreshDeskTools(1) }, 1000);
|
||
}
|
||
}
|
||
|
||
// 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, displays, selDisplay) {
|
||
var displayCount = 0, displaySelector = '';
|
||
for (var i in displays) {
|
||
displayCount++;
|
||
displaySelector += '<option' + ((selDisplay == i) ? ' selected' : '') + ' value=' + i + '>' + displays[i] + '</option>';
|
||
if ((deskPreferedStickyDisplay == i) && (selDisplay != deskPreferedStickyDisplay)) { desktop.m.SetDisplay(i); }
|
||
}
|
||
QH('termdisplays', displaySelector);
|
||
QV('termdisplays', displayCount > 1);
|
||
}
|
||
|
||
function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
|
||
var deskPreferedStickyDisplay = 0;
|
||
function deskSetDisplay(e) { desktop.m.SetDisplay(deskPreferedStickyDisplay = parseInt(Q('termdisplays').value)); Q('termdisplays').blur(); }
|
||
|
||
// Double click detection. This is important for MacOS.
|
||
var dblClickDetectArgs = { t:0, x:0, y:0 };
|
||
function dblClickDetect(e) {
|
||
if (e.buttons != 1) return;
|
||
var t = Date.now();
|
||
if (((t - dblClickDetectArgs.t) < 250) && (Math.abs(e.clientX - dblClickDetectArgs.x) < 2) && (Math.abs(e.clientY - dblClickDetectArgs.y) < 2)) {
|
||
if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedblclick(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedblclick(e); } }
|
||
}
|
||
dblClickDetectArgs.t = t;
|
||
dblClickDetectArgs.x = e.clientX;
|
||
dblClickDetectArgs.y = e.clientY;
|
||
}
|
||
|
||
function dmousedown(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedown(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedown(e); } } dblClickDetect(e); }
|
||
function dmouseup(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mouseup(e); desktop.m.sendKeepAlive(); } else { desktop.m.mouseup(e); } }
|
||
function dmousemove(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousemove(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousemove(e); } } }
|
||
function dmousewheel(e) { setSessionActivity(); e.addx = Q('DeskParent').scrollLeft; e.addy = Q('DeskParent').scrollTop; if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousewheel(e); desktop.m.sendKeepAlive(); } else { if (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, "プロセス制御", 3, stopProcessEx, format("プロセス#{0} \"{1}\"を停止しますか?", id, name), id); return false; }
|
||
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(); 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) && (currentNode.agent.caps & 2));
|
||
QV('connectbutton2hspan', (termState == false) && ((terminalNode.intelamt != null) && (mesh.mtype == 1 || terminalNode.intelamt.state == 2) && ((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);
|
||
|
||
// Key buttons
|
||
QE('ctrlcbutton', termState);
|
||
QE('ctrlxbutton', termState);
|
||
QE('escbutton', termState);
|
||
QE('bsbutton', termState);
|
||
QE('pastebutton', termState);
|
||
QE('specialkeylist', termState);
|
||
QE('specialkeylistinput', termState);
|
||
|
||
// Terminal settings
|
||
QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
|
||
if (terminal) {
|
||
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
|
||
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n')?"CR + LF":"LF";
|
||
}
|
||
}
|
||
|
||
// 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
|
||
QE('termSizeList', true);
|
||
QH('termtitle', '');
|
||
QV('termRecordIcon', false);
|
||
xterminal.m.TermResetScreen();
|
||
xterminal.m.TermDraw();
|
||
if (terminal != null) { terminal.Stop(); terminal = null; }
|
||
break;
|
||
case 3:
|
||
QE('termSizeList', false);
|
||
if (xterminal && (xterminal.serverIsRecording == true)) { QV('termRecordIcon', true); }
|
||
terminal.startTime = new Date();
|
||
if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
|
||
break;
|
||
default:
|
||
QE('termSizeList', false);
|
||
//console.log('Unhandled onTerminalStateChange state', state);
|
||
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, options) {
|
||
p12clearConsoleMsg();
|
||
if (!terminal) {
|
||
if (contype == 2) {
|
||
// Setup the Intel AMT terminal
|
||
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal, 2); return; }
|
||
var termoptions = {};
|
||
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
|
||
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
|
||
terminal.debugmode = debugmode;
|
||
terminal.m.debugmode = debugmode;
|
||
terminal.m.onTitleChange = function (sender, title) { QH('termtitle', ' - ' + EscapeHtml(title)); }
|
||
terminal.onStateChanged = onTerminalStateChange;
|
||
terminal.Start(terminalNode._id, 16994, '*', '*', 0);
|
||
terminal.contype = 2;
|
||
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||
} else {
|
||
// Setup a mesh agent terminal
|
||
var termoptions = { protocol: ((options != null) && (typeof options.protocol == 'number'))?options.protocol:1 };
|
||
if ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) == -1) {
|
||
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; termoptions.xterm = true; }
|
||
if (Q('termSizeList').value == 3) {
|
||
// TODO: Try to improve terminal auto-size.
|
||
termoptions.width = Math.floor((Q('column_l').clientWidth - 60) / 10);
|
||
termoptions.height = Math.floor((Q('column_l').clientHeight - 120) / 20);
|
||
termoptions.xterm = true;
|
||
}
|
||
}
|
||
|
||
// If shift is pressed
|
||
if ((e && (e.shiftKey == true))) {
|
||
if (currentNode.agent.id > 4) {
|
||
if (termoptions.protocol == 1) { termoptions.protocol = 7; } // Switch to user shell
|
||
} else {
|
||
if (termoptions.protocol == 1) { termoptions.protocol = 6; } // Switch to Powershell
|
||
}
|
||
}
|
||
|
||
terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term', termoptions), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||
terminal.debugmode = debugmode;
|
||
terminal.m.debugmode = debugmode;
|
||
terminal.m.onTitleChange = function (sender, title) { QH('termtitle', ' - ' + EscapeHtml(title)); }
|
||
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 = false; // Never do WebRTC on terminal, because of a race condition we can't do it.
|
||
terminal.onStateChanged = onTerminalStateChange;
|
||
terminal.onConsoleMessageChange = function () {
|
||
p12clearConsoleMsg();
|
||
if (terminal.consoleMessage) {
|
||
QH('p12TermConsoleMsg', EscapeHtml(terminal.consoleMessage).split('\n').join('<br />'));
|
||
QV('p12TermConsoleMsg', true);
|
||
p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, 8000);
|
||
}
|
||
}
|
||
terminal.Start(terminalNode._id);
|
||
terminal.contype = 1;
|
||
terminal.m.terminalEmulation = 0;
|
||
terminal.m.fxEmulation = 0;
|
||
Q('id_ttypebutton').value = terminalEmulations[0];
|
||
}
|
||
} else {
|
||
//QH('Term', '');
|
||
terminal.Stop();
|
||
terminal = null;
|
||
}
|
||
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
|
||
}
|
||
|
||
var terminalEmulations = ["UTF8ターミナル", "拡張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)", "代替(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 termToggleCr() {
|
||
if (!terminal || xxdialogMode) return;
|
||
if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
|
||
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR + LF" : "LF";
|
||
}
|
||
|
||
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, "ペースト", 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(); files = null; }
|
||
}
|
||
|
||
function onFilesStateChange(xfiles, state) {
|
||
p13Connect.value = (state == 0) ? "つなぐ" : "切断する";
|
||
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);
|
||
QV('filesRecordIcon', false);
|
||
p13setActions();
|
||
if (files != null) { files.Stop(); files = null; }
|
||
break;
|
||
case 3:
|
||
p13targetpath = '';
|
||
if (files) {
|
||
files.sendText({ action: 'ls', reqid: 1, path: '' });
|
||
if (files.serverIsRecording == true) { QV('filesRecordIcon', true); }
|
||
}
|
||
break;
|
||
default:
|
||
//console.log('Unknown onFilesStateChange state', state);
|
||
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) {
|
||
p13clearConsoleMsg();
|
||
if (!files) {
|
||
// Setup a mesh agent files
|
||
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||
files.attemptWebRTC = attemptWebRTC;
|
||
files.onStateChanged = onFilesStateChange;
|
||
files.onConsoleMessageChange = function () {
|
||
p13clearConsoleMsg();
|
||
if (files.consoleMessage) {
|
||
QH('p13FilesConsoleMsg', EscapeHtml(files.consoleMessage).split('\n').join('<br />'));
|
||
QV('p13FilesConsoleMsg', true);
|
||
p13FilesConsoleMsgTimer = setTimeout(p13clearConsoleMsg, 8000);
|
||
}
|
||
}
|
||
files.Start(filesNode._id);
|
||
} else {
|
||
//QH('Term', '');
|
||
files.Stop();
|
||
files = null;
|
||
}
|
||
p13clipboard = p13clipboardFolder = null;
|
||
p13clipboardCut = 0;
|
||
p13updateClipview();
|
||
}
|
||
|
||
var p13filetree = null;
|
||
var p13targetpath = null;
|
||
var p13filetreelocation = [];
|
||
|
||
function p13gotFiles(data) {
|
||
if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; }
|
||
//console.log('p13gotFiles', data);
|
||
data = JSON.parse(decode_utf8(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, '\\'), 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;
|
||
}
|
||
|
||
function p13updateFiles(checkedNames) {
|
||
var html1 = '', html2 = '', displayPath = '<a href=# style=cursor:pointer onclick="return p13folderup(0)">' + "ルート" + '</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 href=# style=cursor:pointer onclick="return 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 = printDateTime(fdate) + ' '; }
|
||
|
||
// 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 + '\'> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p13folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p13folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||
} else {
|
||
var link = shortname;
|
||
if (f.s > 0) { link = '<a hrf=# rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\"return 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 + '\'> <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.sendText({ 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.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
|
||
return false;
|
||
}
|
||
|
||
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('p13ViewFileButton', false);
|
||
QE('p13SelectAllButton', false);
|
||
Q('p13SelectAllButton').value = "すべて選択";
|
||
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('p13ViewFileButton', (cc == 1) && (sfc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13SelectAllButton', tc > 0);
|
||
Q('p13SelectAllButton').value = (cc > 0 ? "なしを選択" : "すべて選択");
|
||
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 p13getFileSelDirCount() { var cc = 0, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '999')) cc++; } return cc; }
|
||
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, "新しいフォルダ", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
|
||
function p13createfolderEx() { files.sendText({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value }); p13folderup(999); }
|
||
function p13deletefile() { var cc = p13getFileSelCount(), rec = (p13getFileSelDirCount() > 0) ? '<br /><br /><label><input type=checkbox id=p13recdeleteinput>' + "再帰削除" + '</label><br>' : '<input type=checkbox id=p13recdeleteinput style=\'display:none\'>'; setDialogMode(2, "削除する", 3, p13deletefileEx, (cc > 1) ? (format("選択したアイテム{0}を削除しますか?", cc) + rec) : ("選択したアイテムを削除しますか?" + rec)); }
|
||
function p13deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(p13filetree.dir[checkboxes[i].value].n); } } files.sendText({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles, rec: Q('p13recdeleteinput').checked }); p13folderup(999); }
|
||
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, "リネーム", 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.sendText(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, "ファイルをアップロードする", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
|
||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
|
||
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
|
||
function p13viewfile() {
|
||
var checkboxes = document.getElementsByName('fd');
|
||
for (var i = 0; i < checkboxes.length; i++) {
|
||
if (checkboxes[i].checked) {
|
||
if (p13filetree.dir[checkboxes[i].value].s <= 204800) {
|
||
p13downloadfile(encodeURIComponent(p13filetreelocation.join('/') + '/' + p13filetree.dir[checkboxes[i].value].n), encodeURIComponent(p13filetree.dir[checkboxes[i].value].n), p13filetree.dir[checkboxes[i].value].s, 'viewer');
|
||
} else { messagebox("ファイルエディター", "編集できるのは200k未満のファイルのみです。"); }
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
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)) {
|
||
if (p13clipboardCut == 0) {
|
||
if (p13clipboard.length > 1) { x = format("{0}エントリのコピーをこの場所に確認しますか?", p13clipboard.length); } else { x = format("この場所への1つのエントリのコピーを確認しますか?"); }
|
||
} else {
|
||
if (p13clipboard.length > 1) { x = format("{0}エントリのこの場所への移動を確認しますか?", p13clipboard.length); } else { x = format("1エントリのこの場所への移動を確認しますか?"); }
|
||
}
|
||
}
|
||
setDialogMode(2, "ペースト", 3, p13pasteFileEx, x);
|
||
}
|
||
function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0?'copy':'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } }
|
||
function p13updateClipview() {
|
||
var x = '';
|
||
if ((p13clipboard != null) && (p13clipboard.length > 0)) {
|
||
if (p13clipboardCut == 0) {
|
||
if (p13clipboard.length > 1) {
|
||
x = format("コピー用に{0}エントリを保持しています" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "クリア" + '</a>.', p13clipboard.length);
|
||
} else {
|
||
x = format("コピー用に1つのエントリを保持" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "クリア" + '</a>.');
|
||
}
|
||
} else {
|
||
if (p13clipboard.length > 1) {
|
||
x = format("移動のために{0}エントリを保持しています" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "クリア" + '</a>.', p13clipboard.length);
|
||
} else {
|
||
x = format("移動のために1つのエントリを保持" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "クリア" + '</a>.');
|
||
}
|
||
}
|
||
}
|
||
QH('p13bottomstatus', x);
|
||
p13setActions();
|
||
}
|
||
function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; }
|
||
|
||
function p13fileDragDrop(e) {
|
||
haltEvent(e);
|
||
QV('p13bigfail', false);
|
||
QV('p13bigok', false);
|
||
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || p13filetree == null) return;
|
||
|
||
// Check if these are files we can upload, remove all folders.
|
||
var files = [];
|
||
for (var i in e.dataTransfer.files) { if ((e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0)) { files.push(e.dataTransfer.files[i]); } }
|
||
if (files.length == 0) return;
|
||
|
||
p13doUploadFiles(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(function () { QV('p13bigfail',false); QV('p13bigok',false); p13dragtimer=null; }, 10);
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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, tag) {
|
||
if (xxdialogMode || downloadFile || !files) return;
|
||
downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random(), tag: tag }
|
||
//console.log('p13downloadFileCancel', downloadFile);
|
||
files.sendText({ action: 'download', sub: 'start', id: downloadFile.id, path: downloadFile.path });
|
||
setDialogMode(2, "ダウンロードファイル", 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.sendText({ 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.sendText({ 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
|
||
if (downloadFile.tag == 'viewer') {
|
||
// View the file in the dialog box
|
||
setDialogMode(4, EscapeHtml(downloadFile.file), 3, p13editSaveBack, null, downloadFile.file);
|
||
QH('d4editorarea', EscapeHtml(downloadFile.data));
|
||
QS('dialog').width = 'auto';
|
||
QS('dialog').bottom = '80px';
|
||
QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
|
||
downloadFile = null;
|
||
} else {
|
||
// Save the file to disk
|
||
saveAs(data2blob(downloadFile.data), downloadFile.file); downloadFile = null; setDialogMode(0); // Save the file
|
||
}
|
||
} else {
|
||
files.sendText({ action: 'download', sub: 'ack', id: downloadFile.id }); // Send the ACK
|
||
}
|
||
}
|
||
|
||
var d4EditWrapVal = 0;
|
||
var d4EditSizeVal = 0;
|
||
function d4ToggleWrap(update) {
|
||
if (!update) { d4EditWrapVal = ++d4EditWrapVal % 2; }
|
||
Q('d4WrapButton').value = ["Wrap: ON","Wrap: OFF"][d4EditWrapVal];
|
||
QS('d4editorarea').overflow = (d4EditWrapVal == 0)?'auto':'scroll';
|
||
QS('d4editorarea')['white-space'] = (d4EditWrapVal == 0)?null:'pre';
|
||
putstore('editorWrap', d4EditWrapVal);
|
||
}
|
||
|
||
function d4ToggleSize(update) {
|
||
if (!update) { d4EditSizeVal = ++d4EditSizeVal % 4; }
|
||
QS('d4editorarea')['font-size'] = ['100%','125%','150%','200%'][d4EditSizeVal];
|
||
Q('d4SizeButton').value = ["Size: 100%","Size: 125%","Size: 150%","Size: 200%"][d4EditSizeVal];
|
||
putstore('editorSize', d4EditSizeVal);
|
||
}
|
||
|
||
function p13editSaveBack(b, tag) {
|
||
var data = new TextEncoder().encode(Q('d4editorarea').value);
|
||
p13uploadFileContinue(1, [{ name: tag, size: data.byteLength, type: 'text/plain', xdata: data }]);
|
||
}
|
||
|
||
/*
|
||
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, authCookie, authRelayCookie, domainUrl); // 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;
|
||
default:
|
||
console.log('Unknown onFileDownloadStateChange state', state);
|
||
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;
|
||
|
||
// Check if we are going to overwrite any files
|
||
var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
|
||
var targetFiles = [], overWriteCount = 0;
|
||
for (var i in p13filetree.dir) { if (winAgent) { targetFiles.push(p13filetree.dir[i].n.toLowerCase()); } else { targetFiles.push(p13filetree.dir[i].n); } }
|
||
for (var i = 0; i < files.length; i++) {
|
||
if (winAgent) {
|
||
if (targetFiles.indexOf(files[i].name.toLowerCase()) >= 0) { overWriteCount++; }
|
||
} else {
|
||
if (targetFiles.indexOf(files[i].name) >= 0) { overWriteCount++; }
|
||
}
|
||
}
|
||
|
||
if (overWriteCount == 0) {
|
||
// If no overwrite, go ahead with upload
|
||
p13uploadFileContinue(1, files);
|
||
} else {
|
||
// Otherwise, prompt for confirmation
|
||
setDialogMode(2, "ファイルをアップロードする", 3, p13uploadFileContinue, format("アップロードすると、{0}ファイル{1}が上書きされます。持続する?", overWriteCount, addLetterS(overWriteCount)), files);
|
||
}
|
||
}
|
||
|
||
function p13uploadFileContinue(b, files) {
|
||
uploadFile = {};
|
||
uploadFile.xpath = p13filetreelocation.join('/');
|
||
uploadFile.xfiles = files;
|
||
uploadFile.xfilePtr = -1;
|
||
setDialogMode(2, "ファイルをアップロードする", 10, p13uploadFileCancel, '<div id=p13dfileName>' + "接続しています..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
|
||
p13uploadReconnect();
|
||
}
|
||
|
||
function onFileUploadStateChange(xdownloadFile, state) {
|
||
switch (state) {
|
||
case 0:
|
||
setTimeout(function () { p13folderup(9999); }, 200); // Delay the file refresh
|
||
break;
|
||
case 3:
|
||
p13uploadNextFile();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Connect again
|
||
function p13uploadReconnect() {
|
||
uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
|
||
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;
|
||
|
||
if (file.xdata == null) {
|
||
// Load the data
|
||
uploadFile.xreader = new FileReader();
|
||
uploadFile.xreader.onload = function () {
|
||
uploadFile.xdata = uploadFile.xreader.result;
|
||
uploadFile.ws.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
|
||
};
|
||
uploadFile.xreader.readAsArrayBuffer(file);
|
||
} else {
|
||
// Data already loaded
|
||
uploadFile.xdata = file.xdata;
|
||
uploadFile.ws.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
|
||
}
|
||
} 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 deviceEventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in currentDeviceEvents) {
|
||
var event = currentDeviceEvents[i], time = new Date(event.time);
|
||
if (event.msg) {
|
||
if (event.h == null) { event.h = Math.random(); }
|
||
if (printDate(time) != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
dateHeader = printDate(time);
|
||
x += '<table class=p3eventsTable cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + dateHeader + '</td></tr>';
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = EscapeHtml(event.msg).split('(R)').join('®');
|
||
if (event.username) {
|
||
if ((userinfo.siteadmin & 2) && (event.userid)) {
|
||
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + EscapeHtml(event.username) + '</a> → ' + msg;
|
||
} else {
|
||
msg = EscapeHtml(event.username) + ' → ' + msg;
|
||
}
|
||
}
|
||
if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16';
|
||
x += '<tr onclick=showEventDetails(' + event.h + ',1) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1> </td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2> </td></tr><tr style=height:2px></tr>';
|
||
}
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = '<br><i>' + "イベントが見つかりません" + '</i><br><br>';
|
||
QH('p16events', x);
|
||
}
|
||
|
||
function refreshDeviceEvents() {
|
||
meshserver.send({ action: 'events', nodeid: currentNode._id, limit: parseInt(p16limitdropdown.value) });
|
||
}
|
||
|
||
function showEventDetails(h, mode) {
|
||
var eventList, xevent;
|
||
if (mode == 1) { eventList = currentDeviceEvents; }
|
||
if (mode == 2) { eventList = events; }
|
||
if (mode == 3) { eventList = currentUserEvents; }
|
||
for (var i in eventList) { if (eventList[i].h == h) { xevent = eventList[i]; break; } }
|
||
if (xevent) {
|
||
if (xxdialogMode) return false;
|
||
var x = '<div style=overflow-y:auto>';
|
||
for (var i in xevent) {
|
||
if ((i == 'h') || (i == '_id') || (i == 'ids') || (i == 'domain') || (xevent[i] == null) || (typeof xevent[i] == 'object')) continue;
|
||
x += addHtmlValue3(EscapeHtml(i), EscapeHtml(xevent[i]));
|
||
}
|
||
x += '</div>';
|
||
setDialogMode(2, "イベントの詳細", 9, null, x);
|
||
}
|
||
}
|
||
|
||
//
|
||
// CONSOLE
|
||
//
|
||
|
||
function agentConsoleHandleKeys(e) {
|
||
if ((e.ctrlKey) || (e.altKey)) { return true; }
|
||
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;
|
||
var consoleServerText = '';
|
||
function setupConsole() {
|
||
if (xxcurrentView == 115) {
|
||
// Setup server console
|
||
var samenode = (consoleNode == 'server');
|
||
consoleNode = 'server';
|
||
|
||
QH('p15deviceName', "私のサーバーコンソール");
|
||
QE('p15consoleText', true);
|
||
QH('p15statetext', '');
|
||
QH('p15coreName', '');
|
||
QV('p15outputselecttd', false);
|
||
|
||
if (samenode == false) {
|
||
QH('p15agentConsoleText', consoleServerText);
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
} else {
|
||
// Setup the console
|
||
var samenode = (consoleNode == currentNode);
|
||
consoleNode = currentNode;
|
||
|
||
var mesh = meshes[consoleNode.meshid];
|
||
var meshrights = mesh.links[userinfo._id].rights;
|
||
if ((meshrights & 16) != 0) {
|
||
if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
|
||
if (samenode == false) {
|
||
QH('p15agentConsoleText', consoleNode.consoleText);
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
var online = (((consoleNode.conn & 1) != 0) || ((consoleNode.conn & 16) != 0)) ? true : false;
|
||
var onlineText = ((consoleNode.conn & 1) != 0) ? "エージェントはオンラインです" : "エージェントはオフラインです"
|
||
if ((consoleNode.conn & 16) != 0) { onlineText += "、MQTTはオンラインです" }
|
||
QH('p15statetext', onlineText);
|
||
QE('p15consoleText', online);
|
||
QE('p15uploadCore', ((consoleNode.conn & 1) != 0));
|
||
QV('p15outputselecttd', (consoleNode.conn & 17) == 17);
|
||
} else {
|
||
QH('p15statetext', "アクセスが拒否されました");
|
||
QE('p15consoleText', false);
|
||
QE('p15uploadCore', false);
|
||
QV('p15outputselecttd', false);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Clear the console for this node
|
||
function p15consoleClear() {
|
||
QH('p15agentConsoleText', '');
|
||
Q('id_p15consoleClear').blur();
|
||
if (xxcurrentView == 115) {
|
||
consoleServerText = '';
|
||
} else {
|
||
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>> ' + EscapeHtml(v) + '<br/></div>';
|
||
|
||
if (xxcurrentView == 115) {
|
||
// Send the command to the server - TODO: In the future, we may support multiple servers.
|
||
consoleServerText += t;
|
||
meshserver.send({ action: 'serverconsole', value: v });
|
||
} else {
|
||
if (((consoleNode.conn & 16) != 0) && ((Q('p15outputselect').value == 2) || ((consoleNode.conn & 1) == 0))) {
|
||
// Send the command to MQTT
|
||
t = '<div style=color:orange>' + "MQTT" + '> ' + EscapeHtml(v) + '<br/></div>';
|
||
consoleNode.consoleText += t;
|
||
meshserver.send({ action: 'sendmqttmsg', topic: 'console', nodeids: [ consoleNode._id ], msg: v });
|
||
} else {
|
||
// Send the command to the mesh agent
|
||
consoleNode.consoleText += t;
|
||
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value: v });
|
||
}
|
||
}
|
||
|
||
Q('p15agentConsoleText').innerHTML += t;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
Q('p15consoleText').value = '';
|
||
|
||
// 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, source) {
|
||
if (node === 'serverconsole') {
|
||
// Server console data
|
||
data = '<div>' + data + '</div>'
|
||
consoleServerText += data;
|
||
if (consoleNode == 'server') {
|
||
Q('p15agentConsoleText').innerHTML += data;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
} else {
|
||
// Agent console data
|
||
if (source == 'MQTT') { data = '<div style=color:red>' + "MQTT" + '> ' + EscapeHtml(data) + '<br/></div>'; } else { data = '<div>' + data + '</div>' }
|
||
if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
|
||
if (consoleNode == node) {
|
||
Q('p15agentConsoleText').innerHTML += data;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Save console text to file
|
||
function p15downloadConsoleText() {
|
||
saveAs(new Blob([Q('p15agentConsoleText').innerText], { type: 'application/octet-stream' }), "console.txt");
|
||
}
|
||
|
||
// 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, type: 'default' }); } // Upload default core
|
||
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' }); } // Clear the core
|
||
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
||
else { setDialogMode(2, "エージェントアクションの実行", 3, p15uploadCoreEx, addHtmlValue("アクション", '<select id=d3coreMode style=width:230px><option value=1>' + "デフォルトのサーバーコアをアップロードする" + '</option><option value=2>' + "コアをクリアする" + '</option><option value=6>' + "復旧コアをアップロードする" + '</option><option value=3>' + "コアファイルをアップロードする" + '</option><option value=4>' + "ソフト切断エージェント" + '</option><option value=5>' + "ハード切断エージェント" + '</option></select>')); }
|
||
}
|
||
|
||
function p15uploadCoreEx() {
|
||
if (Q('d3coreMode').value == 1) {
|
||
// Upload default core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'default' });
|
||
} else if (Q('d3coreMode').value == 2) {
|
||
// Clear the core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' });
|
||
} 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 });
|
||
} else if (Q('d3coreMode').value == 6) {
|
||
// Upload a recovery core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type:'recovery' });
|
||
}
|
||
}
|
||
|
||
// Called then user opts to upload a file as core
|
||
function p15uploadCore2() {
|
||
if (xxdialogMode) return;
|
||
Q('d3localmodeform').action = 'uploadmeshcorefile.ashx';
|
||
Q('d3auth').value = authCookie;
|
||
Q('d3attrib').value = currentNode._id;
|
||
setDialogMode(3, "メッシュエージェントコアのアップロード", 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, type: 'custom', path: d3filetreelocation.join('/') + '/' + files[0] }); }
|
||
}
|
||
}
|
||
|
||
//
|
||
// MY ACCOUNT
|
||
//
|
||
|
||
function account_manageAuthApp() {
|
||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||
if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
|
||
return false;
|
||
}
|
||
|
||
function account_addOtp() {
|
||
if (xxdialogMode || (userinfo.otpsecret == 1) || ((features & 4096) == 0)) return;
|
||
setDialogMode(2, "認証アプリ", 2, function () { meshserver.send({ action: 'otpauth-setup', secret: Q('d2optsecret').attributes.secret.value, token: Q('d2otpauthinput').value }); }, ('<div id=d2optinfo>' + "読み込み中..." + '</div>'), 'otpauth-request');
|
||
meshserver.send({ action: 'otpauth-request' });
|
||
}
|
||
|
||
function account_addOtpCheck(e) {
|
||
var tokenIsValid = (Q('d2otpauthinput').value.length == 6);
|
||
QE('idx_dlgOkButton', tokenIsValid);
|
||
if (e && (e.keyCode == 13) && tokenIsValid) { dialogclose(1); }
|
||
}
|
||
|
||
function account_removeOtp() {
|
||
if (xxdialogMode || (userinfo.otpsecret != 1) || ((features & 4096) == 0)) return;
|
||
setDialogMode(2, "認証アプリ", 3, function () { meshserver.send({ action: 'otpauth-clear' }); }, "認証アプリケーションの削除2段階ログインを確認しますか?");
|
||
}
|
||
|
||
function account_manageOtp(action) {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-manage')) { dialogclose(0); }
|
||
if (xxdialogMode || ((features & 4096) == 0)) return false;
|
||
if ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)) { meshserver.send({ action: 'otpauth-getpasswords', subaction: action }); }
|
||
return false;
|
||
}
|
||
|
||
function account_manageHardwareOtp() {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-hardware-manage')) { dialogclose(0); }
|
||
if (xxdialogMode || ((features & 4096) == 0)) return false;
|
||
meshserver.send({ action: 'otp-hkey-get' });
|
||
return false;
|
||
}
|
||
|
||
function account_addhkey(type) {
|
||
if (type == 3) {
|
||
var x = "追加するキーの名前を入力します。" + '<br /><br />';
|
||
x += addHtmlValue("キー名", '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off placeholder="' + "私の鍵" + '" onkeyup=account_addhkeyValidate(event,2) />');
|
||
} else if (type == 2) {
|
||
var x = "キー名を入力し、OTPボックスを選択して、YubiKey&trade;のボタンを押します。" + '<br /><br />';
|
||
x += addHtmlValue("キー名", '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off placeholder="' + "私の鍵" + '" onkeyup=account_addhkeyValidate(event,1) />');
|
||
x += addHtmlValue("YubiKey&trade; OTP", '<input id=dp1key style=width:230px autocomplete=off onkeyup=account_addhkeyValidate(event,2) />');
|
||
}
|
||
setDialogMode(2, "セキュリティキーを追加", 3, account_addhkeyEx, x, type);
|
||
Q('dp1keyname').focus();
|
||
}
|
||
|
||
function account_addhkeyValidate(e,action) {
|
||
if ((e != null) && (e.keyCode == 13)) { if (action == 2) { dialogclose(1); } else { Q('dp1key').focus(); } }
|
||
}
|
||
|
||
function account_addhkeyEx(button, type) {
|
||
var name = Q('dp1keyname').value;
|
||
if (name == '') { name = 'MyKey'; }
|
||
if (type == 2) {
|
||
meshserver.send({ action: 'otp-hkey-yubikey-add', name: name, otp: Q('dp1key').value });
|
||
setDialogMode(2, "セキュリティキーを追加", 0, null, '<br />' + "確認しています..." + '<br /><br /><br />', 'otpauth-hardware-manage');
|
||
} else if (type == 3) {
|
||
meshserver.send({ action: 'webauthn-startregister', name: name });
|
||
}
|
||
}
|
||
|
||
function account_removehkey(index) {
|
||
meshserver.send({ action: 'otp-hkey-remove', index: index });
|
||
meshserver.send({ action: 'otp-hkey-get' });
|
||
}
|
||
|
||
var loclist = { 'af': "アフリカーンス語", 'sq': "アルバニア語", 'ar': "アラビア語(標準)", 'ar-dz': "アラビア語(アルジェリア)", 'ar-bh': "アラビア語(バーレーン)", 'ar-eg': "アラビア語(エジプト)", 'ar-iq': "アラビア語(イラク)", 'ar-jo': "アラビア語(ヨルダン)", 'ar-kw': "アラビア語(クウェート)", 'ar-lb': "アラビア語(レバノン)", 'ar-ly': "アラビア語(リビア)", 'ar-ma': "アラビア語(モロッコ)", 'ar-om': "アラビア語(オマーン)", 'ar-qa': "アラビア語(カタール)", 'ar-sa': "アラビア語(サウジアラビア)", 'ar-sy': "アラビア語(シリア)", 'ar-tn': "アラビア語(チュニジア)", 'ar-ae': "アラビア語(U.A.E.)", 'ar-ye': "アラビア語(イエメン)", 'an': "アラゴン語", 'hy': "アルメニア人", 'as': "アッサム語", 'ast': "アストゥリアス", 'az': "アゼルバイジャン語", 'eu': "バスク", 'bg': "ブルガリア語", 'be': "ベラルーシ語", 'bn': "ベンガル語", 'bs': "ボスニア語", 'br': "ブルトン", 'my': "ビルマ語", 'ca': "カタロニア語", 'ch': "チャモロ", 'ce': "チェチェン", 'zh': "中国語", 'zh-hk': "中国語(香港)", 'zh-cn': "中国語(PRC)", 'zh-sg': "中国語(シンガポール)", 'zh-tw': "中国語(台湾)", 'cv': "チュヴァシュ", 'co': "コルシカ", 'cr': "クリー語", 'hr': "クロアチア語", 'cs': "チェコ語", 'da': "デンマーク語", 'nl': "オランダ語(標準)", 'nl-be': "オランダ語(ベルギー)", 'en': "英語", 'en-au': "英語(オーストラリア)", 'en-bz': "英語(ベリーズ)", 'en-ca': "英語(カナダ)", 'en-ie': "英語(アイルランド)", 'en-jm': "英語(ジャマイカ)", 'en-nz': "英語(ニュージーランド)", 'en-ph': "英語(フィリピン)", 'en-za': "英語(南アフリカ)", 'en-tt': "英語(トリニダードトバゴ)", 'en-gb': "英語(イギリス)", 'en-us': "英語(米国)", 'en-zw': "英語(ジンバブエ)", 'eo': "エスペラント", 'et': "エストニア語", 'fo': "フェロー語", 'fa': "ペルシア語(ペルシャ語)", 'fj': "フィジー人", 'fi': "フィンランド語", 'fr': "フランス語(標準)", 'fr-be': "フランス語(ベルギー)", 'fr-ca': "フランス語(カナダ)", 'fr-fr': "フランス語(フランス)", 'fr-lu': "フランス語(ルクセンブルグ)", 'fr-mc': "フランス語(モナコ)", 'fr-ch': "フランス語(スイス)", 'fy': "フリジア語", 'fur': "フリウリアン", 'gd': "ゲール語(スコットランド)", 'gd-ie': "ゲール語(アイルランド語)", 'gl': "ガラシアン", 'ka': "グルジア語", 'de': "ドイツ語(標準)", 'de-at': "ドイツ語(オーストリア)", 'de-de': "ドイツ語(ドイツ)", 'de-li': "ドイツ語(リヒテンシュタイン)", 'de-lu': "ドイツ語(ルクセンブルグ)", 'de-ch': "ドイツ語(スイス)", 'el': "ギリシャ語", 'gu': "グジュラティ", 'ht': "ハイチ語", 'he': "ヘブライ語", 'hi': "ヒンディー語", 'hu': "ハンガリー語", 'is': "アイスランド語", 'id': "インドネシア人", 'iu': "イヌクティトゥット語", 'ga': "アイルランド人", 'it': "イタリア語(標準)", 'it-ch': "イタリア語(スイス)", 'ja': "日本人", 'kn': "カンナダ語", 'ks': "カシミール", 'kk': "カザフ", 'km': "クメール", 'ky': "キルギス", 'tlh': "クリンゴン", 'ko': "韓国語", 'ko-kp': "韓国語(北朝鮮)", 'ko-kr': "韓国語(韓国)", 'la': "ラテン", 'lv': "ラトビア", 'lt': "リトアニア語", 'lb': "ルクセンブルク語", 'mk': "マケドニア語", 'ms': "マレー語", 'ml': "マラヤーラム語", 'mt': "マルタ語", 'mi': "マオリ", 'mr': "マラーティー語", 'mo': "モルダビア", 'nv': "ナバホ", 'ng': "ンドンガ", 'ne': "ネパール語", 'no': "ノルウェー語", 'nb': "ノルウェー語(ボクマル)", 'nn': "ノルウェー語(ニーノシュク)", 'oc': "オクシタン", 'or': "オリヤ", 'om': "オロモ", 'fa-ir': "ペルシャ語/イラン", 'pl': "研磨", 'pt': "ポルトガル語", 'pt-br': "ポルトガル語(ブラジル)", 'pa': "パンジャブ語", 'pa-in': "パンジャブ語(インド)", 'pa-pk': "パンジャブ語(パキスタン)", 'qu': "ケチュア", 'rm': "Rhaeto-Romanic", 'ro': "ルーマニア語", 'ro-mo': "ルーマニア語(モルダビア)", 'ru': "ロシア", 'ru-mo': "ロシア語(モルダビア)", 'sz': "サミ(ラップ語)", 'sg': "サンゴ", 'sa': "サンスクリット", 'sc': "サルデーニャ", 'sd': "シンディ", 'si': "シンハラ語", 'sr': "セルビア語", 'sk': "スロバキア", 'sl': "スロベニア語", 'so': "ソマニ", 'sb': "ソルビアン", 'es': "スペイン語", 'es-ar': "スペイン語(アルゼンチン)", 'es-bo': "スペイン語(ボリビア)", 'es-cl': "スペイン語(チリ)", 'es-co': "スペイン語(コロンビア)", 'es-cr': "スペイン語(コスタリカ)", 'es-do': "スペイン語(ドミニカ共和国)", 'es-ec': "スペイン語(エクアドル)", 'es-sv': "スペイン語(エルサルバドル)", 'es-gt': "スペイン語(グアテマラ)", 'es-hn': "スペイン語(ホンジュラス)", 'es-mx': "スペイン語(メキシコ)", 'es-ni': "スペイン語(ニカラグア)", 'es-pa': "スペイン語(パナマ)", 'es-py': "スペイン語(パラグアイ)", 'es-pe': "スペイン語(ペルー)", 'es-pr': "スペイン語(プエルトリコ)", 'es-es': "スペイン語(スペイン)", 'es-uy': "スペイン語(ウルグアイ)", 'es-ve': "スペイン語(ベネズエラ)", 'sx': "ストゥ", 'sw': "スワヒリ語", 'sv': "スウェーデンの", 'sv-fi': "スウェーデン語(フィンランド)", 'sv-sv': "スウェーデン語(スウェーデン)", 'ta': "タミル語", 'tt': "タタール", 'te': "テルガ", 'th': "タイ語", 'tig': "ティグレ", 'ts': "ツォンガ", 'tn': "ツワナ", 'tr': "トルコ語", 'tk': "トルクメン", 'uk': "ウクライナ語", 'hsb': "上ソルビア語", 'ur': "ウルドゥー語", 've': "ベンダー", 'vi': "ベトナム人", 'vo': "ヴォラプク", 'wa': "ワロン", 'cy': "ウェールズ", 'xh': "コーサ", 'ji': "イディッシュ語", 'zu': "ズールー" };
|
||
function account_showLocalizationSettings() {
|
||
if (xxdialogMode) return false;
|
||
var n = getstore('loctag', 0), y = '';
|
||
var x = '<select id=d2locselect style=width:240px><option value=\"*\">' + "ユーザーブラウザーの値" + '</option>';
|
||
for (var i in loclist) { x += '<option value="' + i + '"' + ((n == i)?' selected':'') + '>' + i + ' - ' + loclist[i] + '</option>'; }
|
||
x += '</select>';
|
||
if (serverinfo.languages && serverinfo.languages.length > 0) {
|
||
y += "言語を変更するには、ページを更新する必要があります。" + '<br /><br />';
|
||
var z = '<select id=d2langselect style=width:240px><option value=\"*\">' + "ユーザーブラウザーの値" + '</option>';
|
||
for (var i in serverinfo.languages) {
|
||
var lang = serverinfo.languages[i];
|
||
z += '<option value="' + lang + '"' + ((userinfo.lang == lang)?' selected':'') + '>' + lang + ' - ' + loclist[lang] + '</option>';
|
||
}
|
||
z += '</select>';
|
||
y += addHtmlValue("言語", z);
|
||
}
|
||
y += addHtmlValue("日時", x);
|
||
|
||
if ((userinfo.siteadmin == 0xFFFFFFFF) && (domain == '')) {
|
||
y += '<br /><a rel="noreferrer noopener" target="_blank" href="translator.htm">' + "MeshCentralの翻訳を支援" + '</a>';
|
||
}
|
||
|
||
setDialogMode(2, "ローカリゼーション設定", 3, account_showLocalizationSettingsEx, y);
|
||
return false;
|
||
}
|
||
|
||
function account_showLocalizationSettingsEx() {
|
||
// Set user language
|
||
var lang = Q('d2langselect').value;
|
||
if ((lang == '*') && (userinfo.lang == null)) { lang = userinfo.lang; }
|
||
if (lang != userinfo.lang) { meshserver.send({ action: 'changelang', lang: lang }); }
|
||
|
||
// Set date localization
|
||
var n = getstore('loctag', 0);
|
||
var m = Q('d2locselect').value;
|
||
if (n != m) {
|
||
if (m != '*') { args.locale = m; } else { delete args.locale; }
|
||
putstore('loctag', args.locale);
|
||
masterUpdate(0xFFFFFFFF); // Refresh everything.
|
||
}
|
||
}
|
||
|
||
function account_enableNotifications() {
|
||
if (Notification) { Notification.requestPermission().then(function (permission) { QV('accountEnableNotificationsSpan', permission != 'granted'); }); }
|
||
return false;
|
||
}
|
||
|
||
function account_showAccountNotifySettings() {
|
||
if (xxdialogMode) return false;
|
||
var x = '';
|
||
x += '<div><label><input id=p2notifyPlayNotifySound type=checkbox />' + "通知音。" + '</label></div>';
|
||
x += '<div><label><input id=p2notifyGroupName type=checkbox />' + "Display Device Group Name" + '</label></div>';
|
||
x += '<div><label><input id=p2notifyIntelDeviceConnect type=checkbox />' + "デバイス接続。" + '</label></div>';
|
||
x += '<div><label><input id=p2notifyIntelDeviceDisconnect type=checkbox />' + "デバイスの切断。" + '</label></div>';
|
||
x += '<div><label><input id=p2notifyIntelAmtKvmActions type=checkbox />' + "Intel® AMTデスクトップおよびシリアルイベント。" + '</label></div>';
|
||
setDialogMode(2, "通知設定", 3, account_showAccountNotifySettingsEx, x);
|
||
var n = getstore('notifications', 0);
|
||
Q('p2notifyPlayNotifySound').checked = (n & 1);
|
||
Q('p2notifyIntelDeviceConnect').checked = (n & 2);
|
||
Q('p2notifyIntelDeviceDisconnect').checked = (n & 4);
|
||
Q('p2notifyIntelAmtKvmActions').checked = (n & 8);
|
||
Q('p2notifyGroupName').checked = (n & 16);
|
||
return false;
|
||
}
|
||
|
||
function account_showAccountNotifySettingsEx() {
|
||
var n = 0;
|
||
n += Q('p2notifyPlayNotifySound').checked ? 1 : 0;
|
||
n += Q('p2notifyIntelDeviceConnect').checked ? 2 : 0;
|
||
n += Q('p2notifyIntelDeviceDisconnect').checked ? 4 : 0;
|
||
n += Q('p2notifyIntelAmtKvmActions').checked ? 8 : 0;
|
||
n += Q('p2notifyGroupName').checked ? 16 : 0;
|
||
putstore('notifications', n);
|
||
}
|
||
|
||
function account_showVerifyEmail() {
|
||
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return false;
|
||
var x = "[OK]をクリックして確認メールを送信します:" + '<br /><div style=padding:8px><b>' + EscapeHtml(userinfo.email) + '</b></div>' + "確認を受けるまで数分お待ちください。";
|
||
setDialogMode(2, "メール確認", 3, account_showVerifyEmailEx, x);
|
||
return false;
|
||
}
|
||
|
||
function account_showVerifyEmailEx() {
|
||
meshserver.send({ action: 'verifyemail', email: userinfo.email });
|
||
}
|
||
|
||
function account_showChangeEmail() {
|
||
if (xxdialogMode) return false;
|
||
var x = "ここでアカウントのメールアドレスを変更します。" + '<br /><br />';
|
||
x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=256 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
|
||
setDialogMode(2, "メールアドレスの変更", 3, account_changeEmail, x);
|
||
if (userinfo.email != null) { Q('dp2email').value = userinfo.email; }
|
||
account_validateEmail();
|
||
Q('dp2email').focus();
|
||
return false;
|
||
}
|
||
|
||
function account_validateEmail(e, email) {
|
||
QE('idx_dlgOkButton', validateEmail(Q('dp2email').value) && (Q('dp2email').value != userinfo.email));
|
||
if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
|
||
}
|
||
|
||
function account_changeEmail() {
|
||
meshserver.send({ action: 'changeemail', email: Q('dp2email').value });
|
||
}
|
||
|
||
function account_showDeleteAccount() {
|
||
if (xxdialogMode) return false;
|
||
var x = "このアカウントを削除するには、下の両方のボックスにアカウントのパスワードを入力して[OK]をクリックします。" + '<br /><br />';
|
||
x += '<form method=post><input type=hidden name=action value=deleteaccount /><input type=hidden name=authcookie value=" + authCookie + " /><table style=margin-left:80px><tr>';
|
||
x += '<td align=right>' + "パスワード:" + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>';
|
||
x += '</tr><tr><td align=right>' + "パスワード:" + '</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, "アカウントを削除する", 0, null, x);
|
||
account_validateDeleteAccount();
|
||
Q('apassword1').focus();
|
||
return false;
|
||
}
|
||
|
||
function account_showChangePassword() {
|
||
if (xxdialogMode) return false;
|
||
var x = "下のボックスに古いパスワードと新しいパスワードを2回入力して、アカウントのパスワードを変更します。";
|
||
if (features & 0x00010000) { " パスワードヒントは使用できますが、推奨されません。"; }
|
||
x += '<br /><br />';
|
||
//x += "<form action='" + domainUrl + "changepassword' method=post>";
|
||
x += '<table style=margin-left:60px>';
|
||
x += '<tr><td align=right>' + nobreak("以前のパスワード:") + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
|
||
x += '<tr><td align=right>' + nobreak("新しいパスワード:") + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
|
||
x += '<tr><td align=right>' + nobreak("新しいパスワード:") + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
|
||
if (features & 0x00010000) { x += '<tr><td align=right>' + "パスワードのヒント:" + '</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>'; }
|
||
x += '</table>'
|
||
if (passRequirements) {
|
||
var r = [], rc = 0;
|
||
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
|
||
if (rc > 0) { x += '<br /><span style=font-size:x-small>' + "要件:" + r.join(', ') + '.</span>'; }
|
||
}
|
||
x += '<br />';
|
||
//x += '<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, "パスワードを変更する", 3, account_showChangePasswordEx, x);
|
||
Q('apassword0').focus();
|
||
account_validateNewPassword();
|
||
return false;
|
||
}
|
||
|
||
function account_showChangePasswordEx() {
|
||
if (Q('apassword1').value == Q('apassword2').value) {
|
||
var r = { action: 'changepassword', oldpass: Q('apassword0').value, newpass: Q('apassword1').value };
|
||
if (features & 0x00010000) { r.hint = Q('apasswordhint').value; }
|
||
meshserver.send(r);
|
||
}
|
||
}
|
||
|
||
function account_createMesh() {
|
||
if (xxdialogMode) return false;
|
||
|
||
// Check if we are disallowed from creating a device group
|
||
if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "新しいデバイスグループ", 1, null, "このアカウントには、新しいデバイスグループを作成する権限がありません。"); return false; }
|
||
|
||
// Remind the user to verify the email address
|
||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "アカウントのセキュリティ", 1, null, "メールアドレスが確認されるまでデバイスにアクセスできません。これはパスワードの回復に必要です。 [マイアカウント]タブに移動して、メールアドレスを変更および確認します。"); return false; }
|
||
|
||
// Remind the user to add two factor authentication
|
||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "アカウントのセキュリティ", 1, null, "二要素認証が有効になるまでデバイスにアクセスできません。これは、追加のセキュリティのために必要です。 [マイアカウント]タブに移動して、[アカウントセキュリティ]セクションを確認します。"); return false; }
|
||
|
||
// We are allowed, let's prompt to information
|
||
var x = "以下のオプションを使用して、新しいデバイスグループを作成します。" + '<br /><br />';
|
||
x += addHtmlValue("名", '<input id=dp2meshname style=width:230px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,1) />');
|
||
x += addHtmlValue("タイプ", '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,2) ><option value=2>' + "ソフトウェアエージェントを使用して管理する" + '</option><option value=1>' + "Intel® AMTのみ、エージェントなし" + '</option></select></div>');
|
||
x += addHtmlValue("説明", '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
|
||
setDialogMode(2, "新しいデバイスグループ", 3, account_createMeshEx, x);
|
||
account_validateMeshCreate();
|
||
Q('dp2meshname').focus();
|
||
return false;
|
||
}
|
||
|
||
function account_validateMeshCreate(e, x) {
|
||
if ((x == 1) && (e != null) && (e.key == "入る") && (Q('dp2meshname').value.length > 0)) { Q('dp2meshtype').focus(); }
|
||
if ((x == 2) && (e != null) && (e.key == "入る")) { Q('dp2meshdesc').focus(); }
|
||
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() {
|
||
var r = '', ok = (Q('apassword0').value.length > 0) && (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value) && (Q('apassword0').value != Q('apassword1').value);
|
||
if ((features & 0x00010000) && (Q('apasswordhint').value == Q('apassword1').value)) { ok = false; }
|
||
if (Q('apassword1').value != '') {
|
||
if (passRequirements == null || passRequirements == '') {
|
||
// No password requirements, display password strength
|
||
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||
if (passStrength >= 80) { r = '<span style=color:green>' + "強い" + '<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>' + "良い" + '<span>'; } else { r = '<span style=color:red>' + "弱い" + '<span>'; }
|
||
} else {
|
||
// Password requirements provided, use that
|
||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||
if (passReq == false) { ok = false; r = '<span style=color:red>' + "方針" + '<span>' }
|
||
}
|
||
}
|
||
QH('dxPassWarn', r);
|
||
//QE('account_dlgOkButton', ok);
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
// 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);
|
||
}
|
||
|
||
// Check password requirements
|
||
function checkPasswordRequirements(password, requirements) {
|
||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||
for (var i = 0; i < password.length; i++) {
|
||
if (/\d/.test(password[i])) { num++; }
|
||
if (/[a-z]/.test(password[i])) { lower++; }
|
||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||
if (/\W/.test(password[i])) { nonalpha++; }
|
||
}
|
||
if (requirements.num && (num < requirements.num)) return false;
|
||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||
return true;
|
||
}
|
||
|
||
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 = 0;
|
||
if (meshes[i].links[userinfo._id]) { meshrights = meshes[i].links[userinfo._id].rights; }
|
||
var rights = "部分的権利";
|
||
if (meshrights == 0xFFFFFFFF) rights = "完全な管理者"; else if (meshrights == 0) rights = "権利なし";
|
||
|
||
// Print the mesh information
|
||
r += '<div onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) 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 tabindex=0 style=height:100%;cursor:pointer onclick=gotoMesh(\'' + i + '\') onkeypress="if (event.key==\'Enter\') 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);
|
||
return false;
|
||
}
|
||
|
||
function server_showRestoreDlg() {
|
||
if (xxdialogMode) return false;
|
||
var x = "バックアップを使用してサーバーを復元します。<span style = color:red>これにより既存のサーバーデータが削除されます</ span>。あなたが何をしているかを知っている場合にのみ、これを行ってください。" + '<br /><br />';
|
||
x += '<form action="/restoreserver.ashx" enctype="multipart/form-data" method="post"><div>';
|
||
x += '<input type=hidden name=auth value=' + authCookie + '>';
|
||
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=' + "キャンセル" + ' 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, "サーバーの復元", 0, null, x);
|
||
account_validateServerRestore();
|
||
return false;
|
||
}
|
||
|
||
function account_validateServerRestore() {
|
||
QE('account_dlgOkButton', Q('account_dlgFileInput').files.length == 1);
|
||
}
|
||
|
||
function server_showVersionDlg() {
|
||
if (xxdialogMode) return false;
|
||
setDialogMode(2, "MeshCentralバージョン", 1, null, "読み込み中...", 'MeshCentralServerUpdate');
|
||
meshserver.send({ action: 'serverversion' });
|
||
return false;
|
||
}
|
||
|
||
function server_showVersionDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); }
|
||
function server_showVersionDlgEx() { meshserver.send({ action: 'serverupdate' }); }
|
||
|
||
function server_showErrorsDlg() {
|
||
if (xxdialogMode) return false;
|
||
setDialogMode(2, "MeshCentralエラー", 1, null, "読み込み中...", 'MeshCentralServerErrors');
|
||
meshserver.send({ action: 'servererrors' });
|
||
return false;
|
||
}
|
||
function server_showErrorsDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); }
|
||
function server_showErrorsDlgEx() { meshserver.send({ action: 'serverclearerrorlog' }); }
|
||
function d2CopyServerErrorsToClip() { saveAs(new Blob([Q('d2ServerErrorsLogPre').innerText], { type: 'application/octet-stream' }), "servererrors.txt"); }
|
||
|
||
//
|
||
// MY MESHS
|
||
//
|
||
|
||
var currentMesh;
|
||
function p20updateMesh() {
|
||
if (currentMesh == null) return;
|
||
QH('p20meshName', EscapeHtml(currentMesh.name));
|
||
var meshtype = format("不明な#{0}", currentMesh.mtype);
|
||
var meshrights = 0;
|
||
try { meshrights = currentMesh.links[userinfo._id].rights; } catch (ex) { }
|
||
if (currentMesh.mtype == 1) meshtype = "Intel® AMTのみ、エージェントなし";
|
||
if (currentMesh.mtype == 2) meshtype = "ソフトウェアエージェントを使用して管理";
|
||
|
||
var x = '';
|
||
x += addHtmlValue("名", addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
|
||
x += addHtmlValue("説明", addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):('<i>' + "なし" + '</i>')), 'p20editmesh(2)', (meshrights & 1) != 0));
|
||
|
||
// Display group type
|
||
x += addHtmlValue("タイプ", meshtype);
|
||
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
|
||
|
||
// Display features
|
||
if (currentMesh.mtype == 2) {
|
||
var meshFeatures = [];
|
||
if (currentMesh.flags) {
|
||
if (currentMesh.flags & 1) { meshFeatures.push("自動削除"); }
|
||
if (currentMesh.flags & 2) { meshFeatures.push("ホスト名の同期"); }
|
||
}
|
||
meshFeatures = meshFeatures.join(', ');
|
||
if (meshFeatures == '') { meshFeatures = '<i>' + "なし" + '</i>'; }
|
||
x += addHtmlValue("特徴", addLinkConditional(meshFeatures, 'p20editmeshfeatures()', meshrights & 1));
|
||
}
|
||
|
||
// Display user consent
|
||
if (currentMesh.mtype == 2) {
|
||
meshFeatures = [];
|
||
var consent = 0;
|
||
if (currentMesh.consent) { consent = currentMesh.consent; }
|
||
if (serverinfo.consent) { consent |= serverinfo.consent; }
|
||
if ((consent & 0x0040) && (consent & 0x0008)) { meshFeatures.push("デスクトッププロンプト+ツールバー"); } else if (consent & 0x0040) { meshFeatures.push("デスクトップツールバー"); } else if (consent & 0x0008) { meshFeatures.push("デスクトッププロンプト"); } else { if (consent & 0x0001) { meshFeatures.push("デスクトップ通知"); } }
|
||
if (consent & 0x0010) { meshFeatures.push("端末プロンプト"); } else { if (consent & 0x0002) { meshFeatures.push("ターミナル通知"); } }
|
||
if (consent & 0x0020) { meshFeatures.push("ファイルプロンプト"); } else { if (consent & 0x0004) { meshFeatures.push("ファイル通知"); } }
|
||
if (consent == 7) { meshFeatures = ["常に通知する"]; }
|
||
if ((consent & 56) == 56) { meshFeatures = ["常にプロンプト"]; }
|
||
|
||
meshFeatures = meshFeatures.join(', ');
|
||
if (meshFeatures == '') { meshFeatures = '<i>' + "なし" + '</i>'; }
|
||
x += addHtmlValue("ユーザーの同意", addLinkConditional(meshFeatures, 'p20editmeshconsent()', meshrights & 1));
|
||
}
|
||
|
||
// Display user consent
|
||
var meshNotify = 0, meshNotifyStr = [];
|
||
if (userinfo.links && userinfo.links[currentMesh._id] && userinfo.links[currentMesh._id].notify) { meshNotify = userinfo.links[currentMesh._id].notify; }
|
||
if (meshNotify & 2) { meshNotifyStr.push("つなぐ"); }
|
||
if (meshNotify & 4) { meshNotifyStr.push("切断する"); }
|
||
if (meshNotify & 8) { meshNotifyStr.push("Intel® AMT"); }
|
||
if (meshNotifyStr.length == 0) { meshNotifyStr.push('<i>' + "なし" + '</i>'); }
|
||
x += addHtmlValue("通知", addLink(meshNotifyStr.join(', '), 'p20editMeshNotify()'));
|
||
|
||
// Intel AMT setup
|
||
var intelAmtPolicy = "ポリシーなし";
|
||
if (currentMesh.amt) {
|
||
if (currentMesh.amt.type == 1) { intelAmtPolicy = 'Deactivate Client Control Mode (CCM)'; }
|
||
else if (currentMesh.amt.type == 2) {
|
||
intelAmtPolicy = "シンプルクライアントコントロールモード(CCM)";
|
||
if (currentMesh.amt.cirasetup == 2) { intelAmtPolicy += " + CIRA"; }
|
||
} else if (currentMesh.amt.type == 3) {
|
||
intelAmtPolicy = "シンプル管理制御モード(ACM)";
|
||
if (currentMesh.amt.cirasetup == 2) { intelAmtPolicy += " + CIRA"; }
|
||
}
|
||
}
|
||
x += addHtmlValue("Intel® AMT", addLinkConditional(intelAmtPolicy, 'p20editMeshAmt()', meshrights & 1));
|
||
|
||
// Display group note support
|
||
if (meshrights & 1) { x += '<br><input type=button value=' + "ノート" + ' title=\"' + "このデバイスグループに関するメモを表示する" + '\" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
|
||
|
||
x += '<br style=clear:both><br>';
|
||
var currentMeshLinks = currentMesh.links[userinfo._id];
|
||
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a href=# onclick="return p20showAddMeshUserDialog()" style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "ユーザーを追加" + '</a>'; }
|
||
|
||
if ((meshrights & 4) != 0) {
|
||
if (currentMesh.mtype == 1) {
|
||
x += '<a href=# onclick=\'return addCiraDeviceToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "新しいIntel®を追加しますインターネット上にあるAMTコンピューター。" + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "CIRAをインストールする" + '</a>';
|
||
x += '<a href=# onclick=\'return addDeviceToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "新しいIntel®を追加しますローカルネットワーク上にあるAMTコンピューター。" + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "ローカルにインストール" + '</a>';
|
||
if (currentMesh.amt && (currentMesh.amt.type == 2)) { // CCM activation
|
||
x += '<a href=# onclick=\'return showCcmActivation(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "Intel AMTクライアント制御モード(CCM)アクティベーションを実行します。" + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "アクティベーション" + '</a>';
|
||
} else if (currentMesh.amt && (currentMesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation
|
||
x += '<a href=# onclick=\'return showAcmActivation(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "Intel AMT管理制御モード(ACM)アクティベーションを実行します。" + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "アクティベーション" + '</a>';
|
||
}
|
||
}
|
||
if (currentMesh.mtype == 2) {
|
||
x += '<a href=# onclick=\'return addAgentToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "メッシュエージェントをインストールして、このメッシュに新しいコンピューターを追加します。" + '\"><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "インストール" + '</a>';
|
||
x += '<a href=# onclick=\'return inviteAgentToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "このメッシュにメッシュエージェントをインストールするように招待します。" + '\"><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "招待する" + '</a>';
|
||
}
|
||
}
|
||
|
||
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>' + "ユーザー認証" + '</th><th scope=col style=text-align:left></th></tr>';
|
||
|
||
// Sort the users for this mesh
|
||
var count = 1, sortedusers = [];
|
||
for (var i in currentMesh.links) {
|
||
var uname = i.split('/')[2];
|
||
if (currentMesh.links[i].name) { uname = currentMesh.links[i].name; }
|
||
if (i == userinfo._id) { uname = userinfo.name; }
|
||
sortedusers.push({ id: i, name: uname, rights: currentMesh.links[i].rights });
|
||
}
|
||
sortedusers.sort(function(a, b) { if (a.name > b.name) return 1; if (a.name < b.name) return -1; return 0; });
|
||
|
||
// Display all users for this mesh
|
||
for (var i in sortedusers) {
|
||
var trash = '', rights = "部分的権利", r = sortedusers[i].rights;
|
||
if (r == 0xFFFFFFFF) rights = "完全な管理者"; else if (r == 0) rights = "権利なし";
|
||
if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a href=# onclick=\'return p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '")\' title=\"' + "このデバイスグループのユーザー権限を削除します" + '\" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
|
||
x += '<tr tabindex=0 onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") onkeypress="if (event.key==\'Enter\') p20viewuser(\'' + encodeURIComponent(sortedusers[i].id) + '\')" style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title=\"' + "ユーザー" + '\" class=m2></div><div> ' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<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 href=# onclick=p20showDeleteMeshDialog() style=cursor:pointer>' + "グループを削除" + '</a></span></div>'; }
|
||
|
||
QH('p20info', x);
|
||
}
|
||
|
||
function p20editMeshAmt() {
|
||
if (xxdialogMode) return;
|
||
var x = '', acmoption = '';
|
||
if ((features & 0x100000) != 0) { acmoption = '<option value=3>' + "シンプル管理制御モード(ACM)" + '</option>'; }
|
||
if (currentMesh.mtype == 1) {
|
||
x += addHtmlValue("タイプ", '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>' + "ポリシーなし" + '</option><option value=2>' + "シンプルクライアントコントロールモード(CCM)" + '</option>' + acmoption + '</select>');
|
||
} else {
|
||
x += addHtmlValue("タイプ", '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>' + "ポリシーなし" + '</option><option value=1>' + "クライアント制御モード(CCM)を無効にする" + '</option><option value=2>' + "シンプルクライアントコントロールモード(CCM)" + '</option>' + acmoption + '</select>');
|
||
}
|
||
x += '<div id=dp20amtpolicydiv></div>';
|
||
setDialogMode(2, "Intel® AMTポリシー", 3, p20editMeshAmtEx, x);
|
||
if (currentMesh.amt) { Q('dp20amtpolicy').value = currentMesh.amt.type; }
|
||
p20editMeshAmtChange();
|
||
|
||
// Set the current Intel AMT policy
|
||
if (currentMesh.amt && (currentMesh.amt.type == 2) || (currentMesh.amt.type == 3)) {
|
||
Q('dp20amtpolicypass').value = currentMesh.amt.password;
|
||
if ((currentMesh.amt.type == 2) && (currentMesh.amt.badpass != null)) { Q('dp20amtbadpass').value = currentMesh.amt.badpass; }
|
||
if ((features & 0x400) == 0) { Q('dp20amtcira').value = currentMesh.amt.cirasetup; }
|
||
}
|
||
|
||
dp20amtValidatePolicy();
|
||
}
|
||
|
||
function p20editMeshAmtChange() {
|
||
var ptype = Q('dp20amtpolicy').value, x = '';
|
||
if (ptype >= 2) {
|
||
x = addHtmlValue("パスワード*", '<input id=dp20amtpolicypass type=password style=width:230px maxlength=32 onchange=dp20amtValidatePolicy() onkeyup=dp20amtValidatePolicy() autocomplete=off />')
|
||
x += addHtmlValue("パスワード*", '<input id=dp20amtpolicypass2 type=password style=width:230px maxlength=32 onchange=dp20amtValidatePolicy() onkeyup=dp20amtValidatePolicy() autocomplete=off />')
|
||
if ((ptype == 2) && (currentMesh.mtype == 2)) { x += addHtmlValue("パスワード", '<select id=dp20amtbadpass style=width:230px><option value=0>' + "何もしない" + '</option><option value=1>' + "インテルを再アクティブ化® AMT" + '</option></select>'); }
|
||
if ((features & 0x400) == 0) {
|
||
if (ptype == 2) {
|
||
x += addHtmlValue('<span title="' + "クライアントが開始したリモートアクセス" + '">' + "CIRA" + '</span>', '<select id=dp20amtcira style=width:230px><option value=0>' + "設定しないでください" + '</option><option value=1>' + "サーバーに接続しない" + '</option><option value=2>' + "サーバーに接続する" + '</option></select>');
|
||
} else {
|
||
x += addHtmlValue('<span title="' + "クライアントが開始したリモートアクセス" + '">' + "CIRA" + '</span>', '<select id=dp20amtcira style=width:230px><option value=0>' + "設定しないでください" + '</option><option value=2>' + "サーバーに接続する" + '</option></select>');
|
||
}
|
||
}
|
||
x += '<br/><span style="font-size:10px">' + "*空白のままにして、各デバイスにランダムなパスワードを割り当てます。" + '</span><br/>';
|
||
if (currentMesh.mtype == 2) {
|
||
if (ptype == 2) {
|
||
x += '<span style="font-size:10px">' + "このポリシーは、Intel®を搭載したデバイスには影響しません。 ACMモードのAMT。" + '</span><br/>';
|
||
x += '<span style="font-size:10px">' + "エージェントはアクティベーションを実行するため、これは安全なポリシーではありません。" + '</span>';
|
||
} else {
|
||
x += '<span style="font-size:10px">' + "アクティベーション中、エージェントは管理者パスワード情報にアクセスできます。" + '</span>';
|
||
}
|
||
}
|
||
}
|
||
QH('dp20amtpolicydiv', x);
|
||
setTimeout(dp20amtValidatePolicy, 1);
|
||
}
|
||
|
||
function dp20amtValidatePolicy() {
|
||
var ok = true, ptype = Q('dp20amtpolicy').value;
|
||
if ((ptype == 2) || (ptype == 3)) {
|
||
var pass = Q('dp20amtpolicypass').value, pass2 = Q('dp20amtpolicypass2').value;
|
||
ok = ((pass === pass2) && ((pass === '') ? true : passwordcheck(pass)));
|
||
}
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
function p20editMeshAmtEx() {
|
||
var ptype = parseInt(Q('dp20amtpolicy').value), amtpolicy = { type: ptype };
|
||
if (ptype == 2) {
|
||
amtpolicy = { type: ptype, password: Q('dp20amtpolicypass').value };
|
||
if (currentMesh.mtype == 2) { amtpolicy.badpass = parseInt(Q('dp20amtbadpass').value); }
|
||
if ((features & 0x400) == 0) { amtpolicy.cirasetup = parseInt(Q('dp20amtcira').value); } else { amtpolicy.cirasetup = 1; }
|
||
} else if (ptype == 3) {
|
||
amtpolicy = { type: ptype, password: Q('dp20amtpolicypass').value };
|
||
if ((features & 0x400) == 0) { amtpolicy.cirasetup = parseInt(Q('dp20amtcira').value); } else { amtpolicy.cirasetup = 1; }
|
||
}
|
||
meshserver.send({ action: 'meshamtpolicy', meshid: currentMesh._id, amtpolicy: amtpolicy });
|
||
}
|
||
|
||
function p20showDeleteMeshDialog() {
|
||
if (xxdialogMode) return false;
|
||
var x = format("グループ{0}を削除してもよろしいですか?デバイスグループを削除すると、このグループ内のデバイスに関するすべての情報も削除されます。", EscapeHtml(currentMesh.name)) + '<br /><br />';
|
||
x += '<label><input id=p20check type=checkbox onchange=p20validateDeleteMeshDialog() />' + "確認する" + '</label>';
|
||
setDialogMode(2, "グループを削除", 3, p20showDeleteMeshDialogEx, x);
|
||
p20validateDeleteMeshDialog();
|
||
return false;
|
||
}
|
||
|
||
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;
|
||
var x = addHtmlValue("名", '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate(event) />');
|
||
x += addHtmlValue("説明", '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
|
||
setDialogMode(2, "デバイスグループの編集", 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(e) {
|
||
QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
|
||
if (e && e.key == 'Enter') { Q('dp20meshdesc').focus(); }
|
||
}
|
||
|
||
function p20editmeshconsent() {
|
||
if (xxdialogMode) return;
|
||
var x = '', consent = (currentMesh.consent) ? currentMesh.consent : 0;
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px"><b>' + "デスクトップ" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag1 ' + ((consent & 0x0001) ? 'checked' : '') + '>' + "ユーザーに通知" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag2 ' + ((consent & 0x0008) ? 'checked' : '') + '>' + "ユーザーの同意を求める" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag7 ' + ((consent & 0x0040) ? 'checked' : '') + '>' + "接続ツールバーを表示" + '</label></div>';
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:8px"><b>' + "ターミナル" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag3 ' + ((consent & 0x0002) ? 'checked' : '') + '>' + "ユーザーに通知" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag4 ' + ((consent & 0x0010) ? 'checked' : '') + '>' + "ユーザーの同意を求める" + '</label></div>';
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:8px"><b>' + "ファイル" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag5 ' + ((consent & 0x0004) ? 'checked' : '') + '>' + "ユーザーに通知" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag6 ' + ((consent & 0x0020) ? 'checked' : '') + '>' + "ユーザーの同意を求める" + '</label></div>';
|
||
setDialogMode(2, "デバイスグループユーザーの同意の編集", 3, p20editmeshconsentEx, x);
|
||
if (serverinfo.consent) {
|
||
if (serverinfo.consent & 0x0001) { Q('d20flag1').checked = true; }
|
||
if (serverinfo.consent & 0x0008) { Q('d20flag2').checked = true; }
|
||
if (serverinfo.consent & 0x0002) { Q('d20flag3').checked = true; }
|
||
if (serverinfo.consent & 0x0010) { Q('d20flag4').checked = true; }
|
||
if (serverinfo.consent & 0x0004) { Q('d20flag5').checked = true; }
|
||
if (serverinfo.consent & 0x0020) { Q('d20flag6').checked = true; }
|
||
if (serverinfo.consent & 0x0040) { Q('d20flag7').checked = true; }
|
||
QE('d20flag1', !(serverinfo.consent & 0x0001));
|
||
QE('d20flag2', !(serverinfo.consent & 0x0008));
|
||
QE('d20flag3', !(serverinfo.consent & 0x0002));
|
||
QE('d20flag4', !(serverinfo.consent & 0x0010));
|
||
QE('d20flag5', !(serverinfo.consent & 0x0004));
|
||
QE('d20flag6', !(serverinfo.consent & 0x0020));
|
||
if (debugmode == 1) { QE('d20flag7', !(serverinfo.consent & 0x0040)); }
|
||
}
|
||
}
|
||
|
||
function p20editmeshconsentEx() {
|
||
var consent = 0;
|
||
if (Q('d20flag1').checked) { consent += 0x0001; }
|
||
if (Q('d20flag2').checked) { consent += 0x0008; }
|
||
if (Q('d20flag3').checked) { consent += 0x0002; }
|
||
if (Q('d20flag4').checked) { consent += 0x0010; }
|
||
if (Q('d20flag5').checked) { consent += 0x0004; }
|
||
if (Q('d20flag6').checked) { consent += 0x0020; }
|
||
if (Q('d20flag7').checked) { consent += 0x0040; }
|
||
meshserver.send({ action: 'editmesh', meshid: currentMesh._id, consent: consent });
|
||
}
|
||
|
||
function p20editmeshfeatures() {
|
||
if (xxdialogMode) return;
|
||
var flags = (currentMesh.flags)?currentMesh.flags:0;
|
||
var x = '<div><label><input type=checkbox id=d20flag1 ' + ((flags & 1) ? 'checked' : '') + '>Remove device on disconnect</label><br></div>';
|
||
x += '<div><label><input type=checkbox id=d20flag2 ' + ((flags & 2) ? 'checked' : '') + '>Sync server device name to hostname</label><br></div>';
|
||
setDialogMode(2, "デバイスグループ機能の編集", 3, p20editmeshfeaturesEx, x);
|
||
}
|
||
|
||
function p20editmeshfeaturesEx() {
|
||
var flags = 0;
|
||
if (Q('d20flag1').checked) { flags += 1; }
|
||
if (Q('d20flag2').checked) { flags += 2; }
|
||
meshserver.send({ action: 'editmesh', meshid: currentMesh._id, flags: flags });
|
||
}
|
||
|
||
function p20showAddMeshUserDialog(userid) {
|
||
if (xxdialogMode) return false;
|
||
var x = '';
|
||
if (userid == null) {
|
||
x += "ユーザーがこのデバイスグループとこのグループ内のデバイスを管理できるようにします。";
|
||
if (features & 0x00080000) { x += " ユーザーは、デバイスグループに追加する前にこのサーバーに1回ログインする必要があります。" }
|
||
x += '<br /><br /><div style=\'position:relative\'>';
|
||
x += addHtmlValue("ユーザー名", '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() placeholder="user1, user2, user3" />');
|
||
x += '<div id=dp20usersuggest class=suggestionBox style=\'top:30px;left:130px;display:none\'></div>';
|
||
x += '</div><br>';
|
||
} else {
|
||
userid = decodeURIComponent(userid);
|
||
var uname = userid.split('/')[2];
|
||
if (users && users[userid]) { uname = users[userid].name; }
|
||
if (userinfo._id == userid) { uname = userinfo.name; }
|
||
x += format("ユーザー{0}のグループ権限。", uname) + '<br /><br />';
|
||
}
|
||
x += '<div style="height:120px;overflow-y:scroll;border:1px solid gray">';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>' + "完全な管理者" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>' + "デバイスグループの編集" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20manageusers>' + "デバイスグループユーザーの管理" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20managecomputers>' + "デバイスグループコンピューターの管理" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>' + "リモコン" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>' + "リモートビューのみ" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>' + "限定入力のみ" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>' + "ターミナルアクセスなし" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>' + "ファイルアクセスなし" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>' + "Intel®なしAMT" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>' + "メッシュエージェントコンソール" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>' + "サーバーファイル" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>' + "ウェイクデバイス" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "デバイスノートの編集" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "自分のイベントのみを表示" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "チャットと通知" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20uninstall>' + "エージェントのアンインストール" + '</label><br>';
|
||
x += '</div>';
|
||
if (userid == null) {
|
||
setDialogMode(2, "ユーザーをデバイスグループに追加する", 3, p20showAddMeshUserDialogEx, x);
|
||
Q('dp20username').focus();
|
||
} else {
|
||
setDialogMode(2, "ユーザーデバイスグループ権限の編集", 7, p20showAddMeshUserDialogEx, x, userid);
|
||
var cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
|
||
if (meshrights == 0xFFFFFFFF) {
|
||
Q('p20fulladmin').checked = true;
|
||
} else {
|
||
if (meshrights & 1) { Q('p20editmesh').checked = true; }
|
||
if (meshrights & 2) { Q('p20manageusers').checked = true; }
|
||
if (meshrights & 4) { Q('p20managecomputers').checked = true; }
|
||
if (meshrights & 8) {
|
||
Q('p20remotecontrol').checked = true;
|
||
if (meshrights & 256) { Q('p20remoteview').checked = true; }
|
||
if (meshrights & 512) { Q('p20noterminal').checked = true; }
|
||
if (meshrights & 1024) { Q('p20nofiles').checked = true; }
|
||
if (meshrights & 2048) { Q('p20noamt').checked = true; }
|
||
if (meshrights & 4096) { Q('p20remotelimitedinput').checked = true; }
|
||
}
|
||
if (meshrights & 16) { Q('p20meshagentconsole').checked = true; }
|
||
if (meshrights & 32) { Q('p20meshserverfiles').checked = true; }
|
||
if (meshrights & 64) { Q('p20wakedevices').checked = true; }
|
||
if (meshrights & 128) { Q('p20editnotes').checked = true; }
|
||
if (meshrights & 8192) { Q('p20limitevents').checked = true; }
|
||
if (meshrights & 16384) { Q('p20chatnotify').checked = true; }
|
||
if (meshrights & 32768) { Q('p20uninstall').checked = true; }
|
||
}
|
||
}
|
||
p20validateAddMeshUserDialog();
|
||
return false;
|
||
}
|
||
|
||
function p20setname(name) {
|
||
name = decodeURIComponent(name);
|
||
var xusers = Q('dp20username').value.split(',');
|
||
for (var i in xusers) { xusers[i] = xusers[i].trim(); }
|
||
xusers[xusers.length - 1] = name;
|
||
Q('dp20username').value = xusers.join(', ');
|
||
p20validateAddMeshUserDialog();
|
||
return false;
|
||
}
|
||
|
||
function p20validateAddMeshUserDialog() {
|
||
var meshrights = currentMesh.links[userinfo._id].rights;
|
||
var ok = true;
|
||
if (Q('dp20username')) {
|
||
var xusers = Q('dp20username').value.split(',');
|
||
for (var i in xusers) {
|
||
var xuser = xusers[i] = xusers[i].trim();
|
||
if (xuser.length == 0) { ok = false; } else if (xuser.indexOf('"') >= 0) { ok = false; }
|
||
}
|
||
|
||
// Fill the suggestion box
|
||
var showsuggestbox = false, exactMatch = false;
|
||
if (users != null) {
|
||
var lastuser = xusers[xusers.length - 1].trim(), lastuserl = lastuser.toLowerCase(), matchingUsers = [];
|
||
if (lastuser.length > 0) {
|
||
for (var i in users) {
|
||
if (users[i].name === lastuser) { exactMatch = true; break; }
|
||
if (users[i].name.toLowerCase().indexOf(lastuserl) >= 0) { matchingUsers.push(users[i].name); if (matchingUsers.length >= 8) break; }
|
||
}
|
||
if ((exactMatch == false) && (matchingUsers.length > 0)) {
|
||
var x = '';
|
||
for (var i in matchingUsers) { x += '<a href=# onclick=\'p20setname("' + encodeURIComponent(matchingUsers[i]) + '")\'>' + matchingUsers[i] + '</a><br />'; }
|
||
QH('dp20usersuggest', x);
|
||
showsuggestbox = true;
|
||
}
|
||
}
|
||
}
|
||
QV('dp20usersuggest', showsuggestbox);
|
||
}
|
||
QE('idx_dlgOkButton', ok);
|
||
|
||
var nc = !Q('p20fulladmin').checked;
|
||
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
||
QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF));
|
||
QE('p20manageusers', nc);
|
||
QE('p20managecomputers', nc);
|
||
QE('p20remotecontrol', nc);
|
||
QE('p20meshagentconsole', nc);
|
||
QE('p20meshserverfiles', nc);
|
||
QE('p20wakedevices', nc);
|
||
QE('p20editnotes', nc);
|
||
QE('p20limitevents', nc);
|
||
QE('p20remoteview', nc && Q('p20remotecontrol').checked);
|
||
QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
|
||
QE('p20noterminal', nc && Q('p20remotecontrol').checked);
|
||
QE('p20nofiles', nc && Q('p20remotecontrol').checked);
|
||
QE('p20noamt', nc && Q('p20remotecontrol').checked);
|
||
QE('p20chatnotify', nc);
|
||
QE('p20uninstall', nc);
|
||
}
|
||
|
||
function p20showAddMeshUserDialogEx(b, t) {
|
||
if (b == 2) {
|
||
p20viewuserEx(b, t);
|
||
} else {
|
||
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;
|
||
if (Q('p20remoteview').checked == true) meshadmin += 256;
|
||
if (Q('p20noterminal').checked == true) meshadmin += 512;
|
||
if (Q('p20nofiles').checked == true) meshadmin += 1024;
|
||
if (Q('p20noamt').checked == true) meshadmin += 2048;
|
||
if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096;
|
||
if (Q('p20limitevents').checked == true) meshadmin += 8192;
|
||
if (Q('p20chatnotify').checked == true) meshadmin += 16384;
|
||
if (Q('p20uninstall').checked == true) meshadmin += 32768;
|
||
}
|
||
|
||
if (t == null) {
|
||
var users = Q('dp20username').value.split(','), users2 = [];
|
||
for (var i in users) { users2.push(users[i].trim()); }
|
||
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, usernames: users2, meshadmin: meshadmin });
|
||
} else {
|
||
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, usernames: [ t.split('/')[2] ], meshadmin: meshadmin });
|
||
}
|
||
}
|
||
}
|
||
|
||
function p20viewuser(userid) {
|
||
if (xxdialogMode) return;
|
||
var xuserid = decodeURIComponent(userid);
|
||
var cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[xuserid].rights;
|
||
if (((userinfo._id) != xuserid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) {
|
||
p20showAddMeshUserDialog(userid);
|
||
} else {
|
||
var r = [];
|
||
if (meshrights == 0xFFFFFFFF) r.push("完全な管理者(すべての権利)"); else {
|
||
if ((meshrights & 1) != 0) r.push("デバイスグループの編集");
|
||
if ((meshrights & 2) != 0) r.push("デバイスグループユーザーの管理");
|
||
if ((meshrights & 4) != 0) r.push("デバイスグループコンピューターの管理");
|
||
if ((meshrights & 8) != 0) r.push("リモコン");
|
||
if ((meshrights & 16) != 0) r.push("エージェントコンソール");
|
||
if ((meshrights & 32) != 0) r.push("サーバーファイル");
|
||
if ((meshrights & 64) != 0) r.push("ウェイクデバイス");
|
||
if ((meshrights & 128) != 0) r.push("メモを編集");
|
||
if (((meshrights & 8) != 0) && (meshrights & 256) != 0) r.push("リモートビューのみ");
|
||
if (((meshrights & 8) != 0) && (meshrights & 512) != 0) r.push("ターミナルなし");
|
||
if (((meshrights & 8) != 0) && (meshrights & 1024) != 0) r.push("ファイルなし");
|
||
if (((meshrights & 8) != 0) && (meshrights & 2048) != 0) r.push("Intel®なしAMT");
|
||
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("制限された入力");
|
||
if ((meshrights & 8192) != 0) r.push("自己イベントのみ");
|
||
if ((meshrights & 16384) != 0) r.push("チャットと通知");
|
||
if ((meshrights & 32768) != 0) r.push("アンインストール");
|
||
}
|
||
if (r.length == 0) { r.push("権利なし"); }
|
||
var uname = xuserid.split('/')[2];
|
||
if (users && users[xuserid]) { uname = users[xuserid].name; }
|
||
if (userinfo._id == xuserid) { uname = userinfo.name; }
|
||
var buttons = 1, x = addHtmlValue("ユーザー名", EscapeHtml(decodeURIComponent(uname)));
|
||
if (xuserid.split('/')[2] != uname) { x += addHtmlValue("ユーザー識別子", EscapeHtml(xuserid.split('/')[2])); }
|
||
|
||
x += addHtmlValue("許可", r.join("、"));
|
||
if (((userinfo._id) != xuserid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
|
||
setDialogMode(2, "デバイスグループユーザー", buttons, p20viewuserEx, x, xuserid);
|
||
}
|
||
}
|
||
|
||
function p20viewuserEx(button, userid) {
|
||
if (button != 2) return;
|
||
var uname = userid.split('/')[2];
|
||
if (users && users[userid]) { uname = users[userid].name; }
|
||
if (userinfo._id == userid) { uname = userinfo.name; }
|
||
setDialogMode(2, "リモートメッシュユーザー", 3, p20viewuserEx2, format("ユーザー{0}の削除を確認しますか?", EscapeHtml(decodeURIComponent(uname))), userid);
|
||
}
|
||
function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); return false; }
|
||
function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); }
|
||
|
||
function p20editMeshNotify() {
|
||
if (xxdialogMode) return false;
|
||
var meshNotify = 0;
|
||
if (userinfo.links && userinfo.links[currentMesh._id] && userinfo.links[currentMesh._id].notify) { meshNotify = userinfo.links[currentMesh._id].notify; }
|
||
var x = 'Notification settings must also be turned on in account settings.<br /><br />';
|
||
x += '<div><label><input id=p20notifyIntelDeviceConnect type=checkbox />Device connections.</label></div>';
|
||
x += '<div><label><input id=p20notifyIntelDeviceDisconnect type=checkbox />Device disconnections.</label></div>';
|
||
x += '<div><label><input id=p20notifyIntelAmtKvmActions type=checkbox />Intel® AMT desktop and serial events.</label></div>';
|
||
setDialogMode(2, "通知設定", 3, p20editMeshNotifyEx, x);
|
||
Q('p20notifyIntelDeviceConnect').checked = (meshNotify & 2);
|
||
Q('p20notifyIntelDeviceDisconnect').checked = (meshNotify & 4);
|
||
Q('p20notifyIntelAmtKvmActions').checked = (meshNotify & 8);
|
||
return false;
|
||
}
|
||
|
||
function p20editMeshNotifyEx() {
|
||
var meshNotify = 0;
|
||
meshNotify += Q('p20notifyIntelDeviceConnect').checked ? 2 : 0;
|
||
meshNotify += Q('p20notifyIntelDeviceDisconnect').checked ? 4 : 0;
|
||
meshNotify += Q('p20notifyIntelAmtKvmActions').checked ? 8 : 0;
|
||
meshserver.send({ action: 'changemeshnotify', meshid: currentMesh._id, notify: meshNotify });
|
||
}
|
||
|
||
//
|
||
// Mesh Summary
|
||
//
|
||
|
||
function setupMeshSummaryStats() {
|
||
var draw = Chart.controllers.doughnut.prototype.draw;
|
||
Chart.controllers.doughnut = Chart.controllers.doughnut.extend({
|
||
draw: function() {
|
||
draw.apply(this, arguments);
|
||
let ctx = this.chart.chart.ctx;
|
||
let _fill = ctx.fill;
|
||
ctx.fill = function() {
|
||
ctx.save();
|
||
ctx.shadowColor = 'blue';
|
||
ctx.shadowBlur = 10;
|
||
ctx.shadowOffsetX = 2;
|
||
ctx.shadowOffsetY = 2;
|
||
_fill.apply(this, arguments)
|
||
ctx.restore();
|
||
}
|
||
}
|
||
});
|
||
|
||
window.meshPowerChart = new Chart(document.getElementById('meshPowerChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#20F', '#40D', '#60B', '#809', '#A07', '#C05'] }] },
|
||
options: { responsive: true, legend: { position: 'none' }, animation: { animateScale: true, animateRotate: true }, layout: { padding: { left: 10, right: 10, top: 10, bottom: 10 } } }
|
||
});
|
||
window.meshOsChart = new Chart(document.getElementById('meshOsChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#20F', '#40D', '#60B', '#809', '#A07', '#C05'] }] },
|
||
options: { responsive: true, legend: { position: 'none' }, animation: { animateScale: true, animateRotate: true }, layout: { padding: { left: 10, right: 10, top: 10, bottom: 10 } } }
|
||
});
|
||
window.meshConnChart = new Chart(document.getElementById('meshConnChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#20F', '#40D', '#60B', '#809', '#A07', '#C05'] }], labels: ["Not Connected", "エージェント", "Intel AMT", "Agent + Intel AMT"] },
|
||
options: { responsive: true, legend: { position: 'none' }, animation: { animateScale: true, animateRotate: true }, layout: { padding: { left: 10, right: 10, top: 10, bottom: 10 } } }
|
||
});
|
||
}
|
||
|
||
function p21updateMesh() {
|
||
if (currentMesh == null) return;
|
||
QH('p21meshName', EscapeHtml(currentMesh.name));
|
||
|
||
// Update charts
|
||
var power = {};
|
||
var conn = {};
|
||
var agentTypes = {};
|
||
var powerStates = {};
|
||
var connectivityStates = [ 0, 0, 0, 0 ]; // None, Agent, AMT, Agent + AMT
|
||
var showAgents = false;
|
||
var showPower = false;
|
||
var showConn = false;
|
||
for (var i in nodes) {
|
||
if (nodes[i].meshid == currentMesh._id) {
|
||
if (nodes[i].agent) { showAgents = true; if (agentTypes[nodes[i].agent.id] == null) { agentTypes[nodes[i].agent.id] = 1; } else { agentTypes[nodes[i].agent.id]++; } }
|
||
if (nodes[i].pwr) { showPower = true; if (powerStates[nodes[i].pwr] == null) { powerStates[nodes[i].pwr] = 1; } else { powerStates[nodes[i].pwr]++; } }
|
||
if (nodes[i].conn == 0) { showConn = true; connectivityStates[0]++; }
|
||
else if ((nodes[i].conn & 6) != 0) { showConn = true; if ((nodes[i].conn & 1) != 0) { connectivityStates[3]++; } else { connectivityStates[2]++; } }
|
||
else if ((nodes[i].conn & 1) != 0) { showConn = true; connectivityStates[1]++; }
|
||
}
|
||
}
|
||
|
||
var agentsData = [], agentsLabels = [], powerData = [], powerLabels = [];
|
||
for (var i in agentTypes) { agentsData.push(agentTypes[i]); agentsLabels.push(agentsStr[i]); }
|
||
for (var i in powerStates) { powerData.push(powerStates[i]); powerLabels.push(powerStatetable[i]); }
|
||
window.meshPowerChart.config.data.datasets[0].data = powerData;
|
||
window.meshPowerChart.config.data.labels = powerLabels;
|
||
window.meshPowerChart.update();
|
||
if (currentMesh.mtype == 2) {
|
||
window.meshOsChart.config.data.datasets[0].data = agentsData;
|
||
window.meshOsChart.config.data.labels = agentsLabels;
|
||
window.meshOsChart.update();
|
||
}
|
||
window.meshConnChart.config.data.datasets[0].data = connectivityStates;
|
||
window.meshConnChart.update();
|
||
|
||
// Update tables
|
||
var x = '', count = 0;
|
||
if (powerData.length > 0) {
|
||
var xpowerStates = [];
|
||
for (var i in powerStates) { xpowerStates.push([powerStatetable[i], powerStates[i]]); }
|
||
xpowerStates.sort(function(a, b){ return -(a[1]-b[1]) });
|
||
x += '<table style="margin-top:10px;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>' + "Power States" + '</th><th scope=col style=text-align:left></th></tr>';
|
||
for (var i in xpowerStates) { x += '<tr style=' + (((++count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><divclass=m2></div><div> ' + xpowerStates[i][0] + '<div></div></div></td><td><div style=float:right>' + xpowerStates[i][1] + ' </div><div></div></td></tr>'; }
|
||
x += '</tbody></table>';
|
||
}
|
||
|
||
if ((agentsData.length > 0) && (currentMesh.mtype == 2)) {
|
||
count = 0;
|
||
var xagentTypes = [];
|
||
for (var i in agentTypes) { xagentTypes.push([agentsStr[i], agentTypes[i]]); }
|
||
xagentTypes.sort(function(a, b){ return -(a[1]-b[1]) });
|
||
x += '<table style="margin-top:10px;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>' + "Agent Types" + '</th><th scope=col style=text-align:left></th></tr>';
|
||
for (var i in xagentTypes) { x += '<tr style=' + (((++count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><divclass=m2></div><div> ' + xagentTypes[i][0] + '<div></div></div></td><td><div style=float:right>' + xagentTypes[i][1] + ' </div><div></div></td></tr>'; }
|
||
x += '</tbody></table>';
|
||
}
|
||
|
||
if (showConn) {
|
||
count = 0;
|
||
var xconnectivityStates = [];
|
||
for (var i = 0; i < 4; i++) { xconnectivityStates.push([["Not Connected", "エージェント", "Intel AMT", "Agent + Intel AMT"][i], connectivityStates[i]]); }
|
||
xconnectivityStates.sort(function(a, b){ return -(a[1]-b[1]) });
|
||
x += '<table style="margin-top:10px;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>' + "接続性" + '</th><th scope=col style=text-align:left></th></tr>';
|
||
for (var i = 0; i < 4; i++) { if (xconnectivityStates[i][1] > 0) { x += '<tr style=' + (((++count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><divclass=m2></div><div> ' + xconnectivityStates[i][0] + '<div></div></div></td><td><div style=float:right>' + xconnectivityStates[i][1] + ' </div><div></div></td></tr>'; } }
|
||
x += '</tbody></table>';
|
||
}
|
||
|
||
if (x == '') { x = '<i>' + "No devices in this device group." + '</i>'; }
|
||
|
||
QH('p21info', x);
|
||
|
||
// Only show the OS chart if the mesh is agent type.
|
||
QS('meshPowerChartDiv')['display'] = (showPower)?'inline-block':'none';
|
||
QS('meshOsChartDiv')['display'] = ((currentMesh.mtype == 2) && showAgents)?'inline-block':'none';
|
||
QS('meshConnChartDiv')['display'] = (showConn)?'inline-block':'none';
|
||
}
|
||
|
||
//
|
||
// 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 href=# style=cursor:pointer onclick="return p5folderup(0)">' + "ルート" + '</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 href=# style=cursor:pointer onclick="return 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 = printDateTime(fdate) + ' '; }
|
||
|
||
// Figure out the size
|
||
var fsize = '';
|
||
if (f.s != null) { fsize = getFileSizeStr(f.s); }
|
||
|
||
var h = '';
|
||
if (f.t < 3 || f.t == 4) {
|
||
var right = (f.t == 1 || f.t == 4)?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 + '"> <span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||
} else {
|
||
var link = shortname, publiclink = '';
|
||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "リンク" + '</a>)'; }
|
||
if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download 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 + '"> <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 getNiceSize(bytes) {
|
||
if (bytes <= 0) return "ストレージ制限を超えています";
|
||
if (bytes < 2048) return format("残り{0}バイト", bytes);
|
||
if (bytes < 2097152) return format("残り{0}キロバイト", Math.round(bytes / 1024));
|
||
if (bytes < 2147483648) return format("残り{0}メガバイト", Math.round(bytes / 1024 / 1024));
|
||
return format("残り{0}ギガバイト", Math.round(bytes / 1024 / 1024 / 1024));
|
||
}
|
||
|
||
function getNiceSize2(bytes) {
|
||
if (bytes <= 0) return "なし";
|
||
if (bytes < 2048) return format("{0} b", bytes);
|
||
if (bytes < 2097152) return format("{0} Kb", Math.round(bytes / 1024));
|
||
if (bytes < 2147483648) return format("{0} Mb", Math.round(bytes / 1024 / 1024));
|
||
return format("{0} Gb", Math.round(bytes / 1024 / 1024 / 1024));
|
||
}
|
||
|
||
function p5getQuotabar(f) {
|
||
while (f.t > 1 && f.t != 4) { f = f.parent; }
|
||
if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
|
||
var tf = Math.floor(f.s / 1024), tq = (f.maxbytes - f.s);
|
||
var title;
|
||
if (f.c > 1) { title = format("{0} k個の{1}ファイル。 {2} k最大", tf, f.c, (Math.floor(f.maxbytes / 1024 / 1024))); } else { title = format("{0} k in 1ファイル。 {1} k最大", tf, (Math.floor(f.maxbytes / 1024 / 1024))); }
|
||
return '<span title="' + title + '">' + getNiceSize(tq) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
|
||
}
|
||
|
||
function p5showPublicLink(u) { setDialogMode(2, "公開リンク", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); return false; }
|
||
|
||
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('p5ViewFileButton', (cc == 1) && (sfc == 1) && (filetreelocation.length > 0));
|
||
QE('p5SelectAllButton', tc > 0);
|
||
Q('p5SelectAllButton').value = (cc > 0 ? "なしを選択" : "すべて選択");
|
||
QE('p5CutButton', (sfc > 0) && (cc == sfc));
|
||
QE('p5CopyButton', (sfc > 0) && (cc == sfc));
|
||
QE('p5PasteButton', (p5clipboard != null) && (p5clipboard.length > 0) && (filetreelocation.length > 0));
|
||
}
|
||
|
||
function getFileSelCount(includeDirs) { var cc = 0, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == '3'))) cc++; } return cc; }
|
||
function getFileSelDirCount() { var cc = 0, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '999')) cc++; } return cc; }
|
||
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バイト"; return format("{0}バイト", size); }
|
||
function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); return false; }
|
||
function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); return false; }
|
||
function p5createfolder() { setDialogMode(2, "新しいフォルダ", 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(), rec = (getFileSelDirCount() > 0) ? '<br /><br /><label><input type=checkbox id=p5recdeleteinput>' + "再帰削除" + '</label><br>' : '<input type=checkbox id=p5recdeleteinput style=\'display:none\'>'; setDialogMode(2, "削除する", 3, p5deletefileEx, (cc > 1) ? (format("選択したアイテム{0}を削除しますか?", cc) + rec) : ("選択したアイテムを削除しますか?" + rec)); }
|
||
function p5deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(checkboxes[i].value); } } meshserver.send({ action: 'fileoperation', fileop: 'delete', path: filetreelocation, delfiles: delfiles, rec: Q('p5recdeleteinput').checked }); }
|
||
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, "リネーム", 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 && 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, "ファイルをアップロードする", 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="p5updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /><span id=p5confirmOverwriteSpan style=display:none><br /><label><input type=checkbox id=p5confirmOverwrite onchange="p5updateUploadDialogOk(\'p5uploadinput\')" />' + "上書きを確認しますか?" + '</label></span></form>'); p5updateUploadDialogOk('p5uploadinput'); }
|
||
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
|
||
function p5updateUploadDialogOk() {
|
||
// Check if these are files we can upload, remove all folders.
|
||
var xallfiles = Q('p5uploadinput').files, files = [];
|
||
for (var i in xallfiles) { if ((xallfiles[i].size != null) && (xallfiles[i].size != 0)) { files.push(xallfiles[i]); } }
|
||
|
||
// Check if these files are duplicates of existing files.
|
||
var filetreex = filetree, allfiles = [], overWriteCount = 0;
|
||
for (var i in filetreelocation) {
|
||
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) { filetreex = filetreex.f[filetreelocation[i]]; }
|
||
}
|
||
QE('idx_dlgOkButton', xallfiles.length > 0);
|
||
if (xallfiles.length > 0) {
|
||
if (filetreex.f != null) {
|
||
for (var i in filetreex.f) { allfiles.push(i); }
|
||
for (var i = 0; i < xallfiles.length; i++) {
|
||
if (allfiles.indexOf(xallfiles[i].name) >= 0) { overWriteCount++; } // TODO: If the server is Windows, we need to lowercase both names.
|
||
}
|
||
}
|
||
QV('p5confirmOverwriteSpan', overWriteCount > 0);
|
||
if (overWriteCount > 0) {
|
||
QE('idx_dlgOkButton', Q('p5confirmOverwrite').checked);
|
||
} else {
|
||
Q('p5confirmOverwrite').checked = false;
|
||
QE('idx_dlgOkButton', true);
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
function p5viewfile() {
|
||
var checkboxes = document.getElementsByName('fc');
|
||
for (var i = 0; i < checkboxes.length; i++) {
|
||
if (checkboxes[i].checked) {
|
||
console.log(filetreelocation.join('/') + '/' + checkboxes[i].value); // TODO: Download and show this file
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
|
||
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')) {
|
||
console.log('yy', checkboxes[i].value);
|
||
p5clipboard.push(checkboxes[i].value);
|
||
}
|
||
}
|
||
p5updateClipview();
|
||
}
|
||
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("{1}エントリ{2}のうち{0}をこの場所に拘束しますか?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "ペースト", 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 = format("{2}の{0}エントリを保持しています{1}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"コピー":"動く")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "クリア" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
|
||
function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); return false; }
|
||
|
||
function p5fileDragDrop(e) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
QV('bigfail', false);
|
||
QV('bigok', false);
|
||
//QV('p5fileCatchAllInput', false);
|
||
|
||
// Check if these are files we can upload, remove all folders.
|
||
if (e.dataTransfer == null) return;
|
||
var files = [];
|
||
for (var i in e.dataTransfer.files) { if ((e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0)) { files.push(e.dataTransfer.files[i]); } }
|
||
if (files.length == 0) return;
|
||
|
||
// Check if these files are duplicates of existing files.
|
||
var filetreex = filetree, allfiles = [], overWriteCount = 0;
|
||
for (var i in filetreelocation) {
|
||
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) { filetreex = filetreex.f[filetreelocation[i]]; }
|
||
}
|
||
if (filetreex.f != null) {
|
||
for (var i in filetreex.f) { allfiles.push(i); }
|
||
for (var i = 0; i < e.dataTransfer.files.length; i++) {
|
||
if (allfiles.indexOf(e.dataTransfer.files[i].name) >= 0) { overWriteCount++; } // TODO: If the server is Windows, we need to lowercase both names.
|
||
}
|
||
}
|
||
|
||
if (overWriteCount == 0) {
|
||
// If no overwrite, go ahead with upload
|
||
p5PerformUpload(1, files);
|
||
} else {
|
||
// Otherwise, prompt for confirmation
|
||
setDialogMode(2, "ファイルをアップロードする", 3, p5PerformUpload, format("アップロードすると、{0}ファイル{1}が上書きされます。持続する?", overWriteCount, addLetterS(overWriteCount)), files);
|
||
}
|
||
}
|
||
|
||
function p5PerformUpload(b, files) {
|
||
// For Chrome & Firefox
|
||
var error = 0;
|
||
p5uploadFile(); // Display the the dialog box
|
||
try { Q('p5uploadinput').files = files; } catch (ex) { error = 1; } // Set the files in the dialog box
|
||
if (error == 0) { p5uploadFileEx(); } // Press the submit button
|
||
setDialogMode(0); // Close the dialog box
|
||
|
||
// For IE browser - This will not work with very large files
|
||
if (error == 1) {
|
||
if (filetreelocation.length == 0) return;
|
||
var names = [], sizes = [], types = [], datas = [], readercount = files.length, totalSize = 0;
|
||
for (var i = 0; i < files.length; i++) { totalSize += files[i].size; }
|
||
if (totalSize > 1300000) { p5uploadFile(); return; } // File is too large, not sure what the real maximum is.
|
||
for (var i = 0; i < files.length; i++) {
|
||
var reader = new FileReader(), file = 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('*'); // This will not work for large files, there is a limit on the data size in a field.
|
||
Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
|
||
Q('p5fileDragAuthCookie').value = authCookie;
|
||
Q('p5loginSubmit2').click();
|
||
}
|
||
}
|
||
reader.readAsDataURL(file);
|
||
}
|
||
}
|
||
}
|
||
|
||
var p5dragtimer = null;
|
||
function p5fileDragOver(e) {
|
||
if (xxdialogMode) return;
|
||
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) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
if (e.target.id != 'p5filetable') {
|
||
QV('bigfail', false);
|
||
QV('bigok', false);
|
||
//QV('p5fileCatchAllInput', false);
|
||
} else {
|
||
p5dragtimer = setTimeout(function () { QV('bigfail',false); QV('bigok',false); p5dragtimer=null; }, 10);
|
||
}
|
||
}
|
||
|
||
/*
|
||
function p5fileCatchAllInputChanged(e) {
|
||
p5fileDragLeave(e);
|
||
Q('p5fileDragLink2').value = encodeURIComponent(filetreelinkpath);
|
||
Q('p5fileCatchAllSubmit').click();
|
||
}
|
||
*/
|
||
|
||
//
|
||
// MY EVENTS
|
||
//
|
||
|
||
// Highlights the device being hovered
|
||
function eventMouseHover(e, over) {
|
||
e.children[1].classList.remove('g1s');
|
||
e.children[2].style['background-color'] = ((over == 0) ? '#c9c9c9' : '#b9b9b9');
|
||
e.children[3].classList.remove('g2s');
|
||
if (over == 1) { e.children[1].classList.add('g1s'); e.children[3].classList.add('g2s'); }
|
||
}
|
||
|
||
function eventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in events) {
|
||
var event = events[i], time = new Date(event.time);
|
||
if (event.msg) {
|
||
if (event.h == null) { event.h = Math.random(); }
|
||
if (printDate(time) != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
dateHeader = printDate(time);
|
||
x += '<table class=p3eventsTable cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + dateHeader + '</td></tr>';
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = EscapeHtml(event.msg).split('(R)').join('®');
|
||
if (event.nodeid) {
|
||
var node = getNodeFromId(event.nodeid);
|
||
if (node != null) {
|
||
icon = 'si' + node.icon;
|
||
msg = '<a href=# onclick=\'gotoDevice("' + event.nodeid + '",10);haltEvent(event);\'>' + EscapeHtml(node.name) + '</a> → ' + msg;
|
||
}
|
||
}
|
||
if (event.username) {
|
||
if ((userinfo.siteadmin & 2) && (event.userid)) {
|
||
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + EscapeHtml(event.username) + '</a> → ' + msg;
|
||
} else {
|
||
msg = EscapeHtml(event.username) + ' → ' + msg;
|
||
}
|
||
}
|
||
if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16';
|
||
x += '<tr onclick=showEventDetails(' + event.h + ',2) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1> </td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2> </td></tr><tr style=height:2px></tr>';
|
||
}
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = '<br><i>' + "イベントが見つかりません" + '</i><br><br>';
|
||
QH('p3events', x);
|
||
}
|
||
|
||
function refreshEvents() {
|
||
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
|
||
}
|
||
|
||
function p3showDownloadEventsDialog(mode) {
|
||
if (xxdialogMode) return;
|
||
var x = "以下のファイル形式のいずれかでイベントのリストをダウンロードします。" + '<br /><br />';
|
||
x += addHtmlValue("CSV形式", '<a href=# style=cursor:pointer onclick="return p3downloadEventsDialogCSV(' + mode + ')">' + "eventslist.csv" + '</a>');
|
||
x += addHtmlValue("JSON形式", '<a href=# style=cursor:pointer onclick="return p3downloadEventsDialogJSON(' + mode + ')">' + "eventslist.json" + '</a>');
|
||
setDialogMode(2, "イベントリストのエクスポート", 1, null, x, mode);
|
||
}
|
||
|
||
function p3downloadEventsDialogCSV(mode) {
|
||
var csv, eventList;
|
||
if (mode == 1) { eventList = currentDeviceEvents; }
|
||
if (mode == 2) { eventList = events; }
|
||
if (mode == 3) { eventList = currentUserEvents; }
|
||
csv = "時間、タイプ、アクション、ユーザー、メッセージ" + '\r\n';
|
||
for (var i in eventList) { csv += '\"' + eventList[i].time + '\",\"' + eventList[i].etype + '\",\"' + ((eventList[i].action != null) ? eventList[i].action : '') + '\",\"' + ((eventList[i].username != null) ? eventList[i].username : '') + '\",\"' + ((eventList[i].msg != null) ? eventList[i].msg : '') + '\"\r\n'; }
|
||
saveAs(new Blob([csv], { type: 'application/octet-stream' }), "eventslist.csv");
|
||
return false;
|
||
}
|
||
|
||
function p3downloadEventsDialogJSON(mode) {
|
||
var r = [], eventList;
|
||
if (mode == 1) { eventList = currentDeviceEvents; }
|
||
if (mode == 2) { eventList = events; }
|
||
if (mode == 3) { eventList = currentUserEvents; }
|
||
for (var i in eventList) { r.push(events[i]); }
|
||
saveAs(new Blob([JSON.stringify(r)], { type: 'application/octet-stream' }), "eventslist.json");
|
||
return false;
|
||
}
|
||
|
||
//
|
||
// MY USERS
|
||
//
|
||
|
||
function updateUsers() {
|
||
QV('MainMenuMyUsers', (users != null) && ((features & 4) == 0));
|
||
QV('LeftMenuMyUsers', (users != null) && ((features & 4) == 0));
|
||
QV('UserNewAccountButton', ((features & 4) == 0) && (serverinfo.domainauth == false));
|
||
if ((users == null) || ((features & 4) != 0)) { QH('p3users', ''); return; }
|
||
|
||
// Sort the list of user id's
|
||
var sortedUserIds = [], maxUsers = 100, hiddenUsers = 0;
|
||
for (var i in users) { sortedUserIds.push(i); }
|
||
sortedUserIds.sort();
|
||
|
||
// Get search
|
||
var userSearch = Q('UserSearchInput').value.toLowerCase();
|
||
var emailSearch = userSearch;
|
||
if (userSearch.startsWith('email:')) { userSearch = null; emailSearch = emailSearch.substring(6); }
|
||
else if (userSearch.startsWith('name:')) { emailSearch = null; userSearch = userSearch.substring(5); }
|
||
else if (userSearch.startsWith('e:')) { userSearch = null; emailSearch = emailSearch.substring(2); }
|
||
else if (userSearch.startsWith('n:')) { emailSearch = null; userSearch = userSearch.substring(2); }
|
||
|
||
// Display the users using the sorted list
|
||
var x = '<table class=p3usersTable cellpadding=0 cellspacing=0>', addHeader = true;
|
||
x += '<th>' + "名" + '<th style=width:80px>Groups<th style=width:120px>' + nobreak("最終アクセス") + '<th style=width:120px>' + "許可";
|
||
|
||
// Online users
|
||
for (var i in sortedUserIds) {
|
||
var user = users[sortedUserIds[i]], sessions = null;
|
||
if (wssessions != null) { sessions = wssessions[user._id]; }
|
||
if ((sessions != null) &&
|
||
((userSearch != null) && ((userSearch == '') || (user.name.toLowerCase().indexOf(userSearch) >= 0)) ||
|
||
((emailSearch != null) && ((user.email != null) && (user.email.toLowerCase().indexOf(emailSearch) >= 0))))
|
||
) {
|
||
if (maxUsers > 0) {
|
||
if (addHeader) { x += '<tr><td class=userTableHeader colspan=4>' + "オンラインユーザー"; addHeader = false; }
|
||
x += addUserHtml(user, sessions);
|
||
maxUsers--;
|
||
} else {
|
||
hiddenUsers++;
|
||
}
|
||
}
|
||
}
|
||
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) &&
|
||
((userSearch != null) && ((userSearch == '') || (user.name.toLowerCase().indexOf(userSearch) >= 0)) ||
|
||
((emailSearch != null) && ((user.email != null) && (user.email.toLowerCase().indexOf(emailSearch) >= 0))))
|
||
) {
|
||
if (maxUsers > 0) {
|
||
if (addHeader) { x += '<tr><td class=userTableHeader colspan=4>' + "オフラインユーザー"; addHeader = false; }
|
||
x += addUserHtml(user, sessions);
|
||
maxUsers--;
|
||
} else {
|
||
hiddenUsers++;
|
||
}
|
||
}
|
||
}
|
||
x += '</table>';
|
||
if (hiddenUsers == 1) { x += '<br />' + "さらに1人のユーザーが表示されていません。検索ボックスを使用してユーザーを検索してください..." + '<br />'; }
|
||
else if (hiddenUsers > 1) { x += '<br />' + format("{0}個のユーザーが表示されていません。検索ボックスを使用してユーザーを検索してください...", hiddenUsers) + '<br />'; }
|
||
if (maxUsers == 100) { x += '<br />' + "ユーザが見つかりませんでした。" + '<br />'; }
|
||
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), lastAccess = '', permissions = '';
|
||
if (sessions != null) {
|
||
gray = '';
|
||
if (self) {
|
||
msg = '<span style=float:right;margin-top:1px;margin-right:4px title=' + "チャット" + '><a href=# onclick=userChat(event,\"' + encodeURIComponent(user._id) + '\",\"' + encodeURIComponent(user.name) + '\")><img src=\'images/icon-chat.png\' height=16 width=16 style=padding-top:2px /></a></span>';
|
||
msg += '<span style=float:right;margin-top:1px;margin-left:4px;margin-right:4px title=Notify><a href=# onclick=\'return showUserAlertDialog(event,\"' + encodeURIComponent(user._id) + '\")\'><img src=\'images/icon-notify.png\' height=16 width=16 style=padding-top:2px /></a></span>';
|
||
}
|
||
if (sessions == 1) { lastAccess += nobreak("1セッション"); } else { lastAccess += nobreak(format("{0}セッション", sessions)); }
|
||
} else {
|
||
if (user.login) { lastAccess += '<span title=\"' + format("最終ログイン:{0}", printDateTime(new Date(user.login * 1000))) + '\">' + printDate(new Date(user.login * 1000)) + '</span>'; }
|
||
}
|
||
if (self) { permissions += '<a href=# style=cursor:pointer onclick=\'return showUserAdminDialog(event,\"' + encodeURIComponent(user._id) + '\")\'>'; }
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { permissions += "ロック済み" + ', '; }
|
||
permissions += '<span title=\'' + "サーバーの許可" + '\'>';
|
||
|
||
var urights = user.siteadmin & (0xFFFFFFFF - 224);
|
||
if ((user.siteadmin == null) || (urights == 0)) {
|
||
permissions += "ユーザー";
|
||
} else if (urights == 8) {
|
||
permissions += "ユーザー+ファイル";
|
||
} else if (user.siteadmin == 0xFFFFFFFF) {
|
||
permissions += "管理者";
|
||
} else if ((urights & 2) != 0) {
|
||
permissions += "マネージャー";
|
||
} else {
|
||
permissions += "部分的";
|
||
}
|
||
if ((user.siteadmin != null) && (user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & (64 + 128)) != 0)) { permissions += '*'; }
|
||
permissions += '</span>';
|
||
//if ((user.quota != null) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
|
||
if (self) { permissions += '</a>'; }
|
||
|
||
var groups = 0
|
||
if (user.links) { for (var i in user.links) { groups++; } }
|
||
|
||
var username = EscapeHtml(user.name), emailVerified = '';
|
||
if (serverinfo.emailcheck == true) { emailVerified = ((user.emailVerified != true) ? ' <b style=color:red title="Email is not verified">✗</b>' : ' <b style=color:green title="Email is verified">✓</b>'); }
|
||
if (user.email != null) {
|
||
if (((features & 0x200000) == 0) || (user.email.toLowerCase() != user.name.toLowerCase())) {
|
||
// Username & email are different
|
||
username += ', <a href=# onclick=\'return doemail(event,\"' + user.email + '\")\'>' + user.email + '</a>' + emailVerified;
|
||
} else {
|
||
// Username & email are the same
|
||
username += ' <a href=# onclick=\'return doemail(event,\"' + user.email + '\")\'><img src="images/mail12.png" height=9 width=12 title="Send email to user" style="margin-top:2px" /></a>' + emailVerified;
|
||
}
|
||
}
|
||
|
||
if ((user.otpsecret > 0) || (user.otphkeys > 0)) { username += ' <img src="images/key12.png" height=12 width=11 title="2nd factor authentication enabled" style="margin-top:2px" />'; }
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { username += ' <img src="images/padlock12.png" height=12 width=8 title="Account is locked" style="margin-top:2px" />'; }
|
||
|
||
x += '<tr tabindex=0 onmouseover=userMouseHover(this,1) onmouseout=userMouseHover(this,0) onkeypress="if (event.key==\'Enter\') gotoUser(\'' + encodeURIComponent(user._id) + '\')"><td style=cursor:pointer onclick=gotoUser(\"' + encodeURIComponent(user._id) + '\")>';
|
||
x += '<div class=bar>';
|
||
x += '<div class=baricon><div class="' + icon + gray + '"></div></div>';
|
||
x += '<div class=g1></div><div class=g2></div>';
|
||
x += '<div><span>' + username + '</span>' + msg + '</div></div><td style=text-align:center>' + groups + '<td style=text-align:center>' + lastAccess + '<td style=text-align:center>' + permissions;
|
||
return x;
|
||
}
|
||
|
||
// Highlights the user being hovered
|
||
function userMouseHover(element, over) {
|
||
var e = element.children[0].children[0];
|
||
e.children[1].classList.remove('g1s');
|
||
e.children[2].classList.remove('g2s');
|
||
if (over == 1) { e.children[1].classList.add('g1s'); e.children[2].classList.add('g2s'); }
|
||
element.children[0].children[0].style['background-color'] = ((over == 0) ? '#c9c9c9' : '#b9b9b9');
|
||
}
|
||
|
||
function userChat(e, userid, name) {
|
||
haltEvent(e);
|
||
var url = '/messenger?id=meshmessenger/' + userid + '/' + encodeURIComponent(userinfo._id) + '&title=' + name;
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
window.open(url, 'meshmessenger:' + userid);
|
||
meshserver.send({ action: 'meshmessenger', userid: decodeURIComponent(userid) });
|
||
return false;
|
||
}
|
||
|
||
function showUserAlertDialog(e, userid) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
setDialogMode(2, format("{0}に通知", EscapeHtml(users[decodeURIComponent(userid)].name)), 3, showUserAlertDialogEx, "このユーザーにテキスト通知を送信します。" + '<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 false;
|
||
haltEvent(e);
|
||
window.open('mailto:' + addr);
|
||
return false;
|
||
}
|
||
|
||
function p4batchAccountCreate() {
|
||
if (xxdialogMode) return;
|
||
var x = "次の形式のJSONファイルをインポートして、一度に多くのアカウントを作成します。" + '<br /><pre>[\r\n {"user":"x1","pass":"x","email":"x1@x"},\r\n {"user":"x2","pass":"x","resetNextLogin":true}\r\n]</pre><input style=width:370px type=file id=d4importFile accept=".json" onchange=p4batchAccountCreateValidate() />';
|
||
setDialogMode(2, "ユーザーアカウントのインポート", 3, p4batchAccountCreateEx, x);
|
||
QE('idx_dlgOkButton', false);
|
||
}
|
||
|
||
function p4batchAccountCreateValidate() {
|
||
QE('idx_dlgOkButton', Q('d4importFile').value != null);
|
||
}
|
||
|
||
function p4batchAccountCreateEx() {
|
||
var fr = new FileReader();
|
||
fr.onload = function (r) {
|
||
var j = null;
|
||
try { j = JSON.parse(r.target.result); } catch (ex) { setDialogMode(2, "ユーザーアカウントのインポート", 1, null, format("無効なJSONファイル:{0}。", ex)); return; }
|
||
if ((j != null) && (Array.isArray(j))) {
|
||
var ok = true;
|
||
for (var i in j) {
|
||
if ((typeof j[i].user != 'string') || (j[i].user.length < 1) || (j[i].user.length > 64)) { ok = false; }
|
||
if ((typeof j[i].pass != 'string') || (j[i].pass.length < 1) || (j[i].pass.length > 256)) { ok = false; }
|
||
if (checkPasswordRequirements(j[i].pass, passRequirements) == false) { ok = false; }
|
||
if ((j[i].email != null) && ((typeof j[i].email != 'string') || (j[i].email.length < 1) || (j[i].email.length > 128))) { ok = false; }
|
||
}
|
||
if (ok == false) { setDialogMode(2, "ユーザーアカウントのインポート", 1, null, "JSONファイル形式が無効です。"); } else { meshserver.send({ action: 'adduserbatch', users: j }); }
|
||
} else { setDialogMode(2, "ユーザーアカウントのインポート", 1, null, "JSONファイル形式が無効です。"); }
|
||
};
|
||
fr.readAsText(Q('d4importFile').files[0]);
|
||
}
|
||
|
||
function p4downloadUserInfo() {
|
||
if (xxdialogMode) return;
|
||
var x = "以下のファイル形式のいずれかでユーザーのリストをダウンロードします。" + '<br /><br />';
|
||
x += addHtmlValue("CSV形式", '<a href=# style=cursor:pointer onclick=\'return p4downloadUserInfoCSV()\'>' + "userlist.csv" + '</a>');
|
||
x += addHtmlValue("JSON形式", '<a href=# style=cursor:pointer onclick=\'return p4downloadUserInfoJSON()\'>' + "userlist.json" + '</a>');
|
||
setDialogMode(2, "ユーザーリストのエクスポート", 1, null, x);
|
||
}
|
||
|
||
function p4downloadUserInfoCSV() {
|
||
var csv = "id、名前、電子メール、作成、lastlogin、グループ、authfactors" + '\r\n';
|
||
for (var i in users) {
|
||
var multiFactor = false, factors = [];
|
||
if ((users[i].otpsecret > 0) || (users[i].otphkeys > 0)) {
|
||
multiFactor = true;
|
||
if (users[i].otpsecret > 0) { factors.push('AuthApp'); }
|
||
if (users[i].otphkeys > 0) { factors.push('SecurityKey'); }
|
||
if (users[i].otpkeys > 0) { factors.push('BackupCodes'); }
|
||
}
|
||
csv += '\"' + users[i]._id + '\",\"' + users[i].name + '\",\"' + (users[i].email ? users[i].email : '') + '\",\"' + (users[i].creation ? new Date(users[i].creation * 1000) : '') + '\",\"' + (users[i].login ? new Date(users[i].login * 1000) : '') + '\",\"' + (users[i].groups ? users[i].groups.join(',') : '') + '\",\"' + (multiFactor ? factors.join(',') : '') + '\"\r\n';
|
||
}
|
||
saveAs(new Blob([csv], { type: 'application/octet-stream' }), "userlist.csv");
|
||
return false;
|
||
}
|
||
|
||
function p4downloadUserInfoJSON() {
|
||
var r = []
|
||
for (var i in users) { r.push(users[i]); }
|
||
saveAs(new Blob([JSON.stringify(r)], { type: 'application/octet-stream' }), "userlist.json");
|
||
return false;
|
||
}
|
||
|
||
function showUserBroadcastDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = "接続されているすべてのユーザーにメッセージをブロードキャストします。" + '<textarea id=broadcastMessage value="" maxlength="256"/></textarea>';
|
||
setDialogMode(2, "同報メッセージ", 3, showUserBroadcastDialogEx, x);
|
||
Q('broadcastMessage').focus();
|
||
}
|
||
|
||
function showUserBroadcastDialogEx() {
|
||
meshserver.send({ action: 'userbroadcast', msg: Q('broadcastMessage').value });
|
||
}
|
||
|
||
function showCreateNewAccountDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
if ((features & 0x200000) == 0) { x += addHtmlValue("名", '<input id=p4name maxlength=64 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />'); }
|
||
x += addHtmlValue("Eメール", '<input id=p4email maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += addHtmlValue("パスワード", '<input id=p4pass1 type=password maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += addHtmlValue("パスワード", '<input id=p4pass2 type=password maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += '<div><label><input id=p4randomPassword onchange=showCreateNewAccountDialogValidate() type=checkbox />' + "パスワードをランダム化します。" + '</label></div>';
|
||
x += '<div><label><input id=p4resetNextLogin onchange=showCreateNewAccountDialogValidate() type=checkbox />' + "次回ログイン時にパスワードを強制的にリセットします。" + '</label></div>';
|
||
if (serverinfo.emailcheck) {
|
||
x += '<div><label><input id=p4verifiedEmail onchange=showCreateNewAccountDialogValidate() type=checkbox />' + "メールが確認されました。" + '</label></div>';
|
||
x += '<div><label><input id=p4invitationEmail type=checkbox />' + "招待メールを送信します。" + '</label></div>';
|
||
}
|
||
|
||
if (passRequirements) {
|
||
var r = [], rc = 0;
|
||
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
|
||
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>' + format("要件:{0}。", r.join(', ')) + '</div>'; }
|
||
}
|
||
|
||
setDialogMode(2, "アカウントを作成する", 3, showCreateNewAccountDialogEx, x);
|
||
showCreateNewAccountDialogValidate();
|
||
if ((features & 0x200000) == 0) { Q('p4name').focus(); } else { Q('p4email').focus(); }
|
||
}
|
||
|
||
function showCreateNewAccountDialogValidate(x) {
|
||
var ve = true;
|
||
if (serverinfo.emailcheck) {
|
||
ve = validateEmail(Q('p4email').value);
|
||
QE('p4verifiedEmail', ve);
|
||
QE('p4invitationEmail', ve && Q('p4resetNextLogin').checked && Q('p4verifiedEmail').checked);
|
||
if (ve == false) { Q('p4verifiedEmail').checked = false; }
|
||
if ((Q('p4resetNextLogin').checked == false) || (Q('p4verifiedEmail').checked == false)) { Q('p4invitationEmail').checked = false; }
|
||
}
|
||
QE('p4pass1', !Q('p4randomPassword').checked);
|
||
QE('p4pass2', !Q('p4randomPassword').checked);
|
||
|
||
if ((x == null) && (Q('p4email').value.length > 0) && (ve == false)) { QE('idx_dlgOkButton', false); return; }
|
||
var ok = true;
|
||
if ((features & 0x200000) == 0) { ok &= (!Q('p4name') || ((Q('p4name').value.length > 0) && (Q('p4name').value.indexOf(' ') == -1))); } // Username is not email address
|
||
if (Q('p4randomPassword').checked == false) { ok &= (Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value && checkPasswordRequirements(Q('p4pass1').value, passRequirements)); }
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
function showCreateNewAccountDialogEx() {
|
||
var username = ((features & 0x200000) == 0) ? Q('p4name').value : Q('p4email').value; // Username is email address
|
||
var x = { action: 'adduser', username: username, email: Q('p4email').value, pass: Q('p4pass1').value, resetNextLogin: Q('p4resetNextLogin').checked, randomPassword: Q('p4randomPassword').checked };
|
||
if (serverinfo.emailcheck) {
|
||
x.emailVerified = Q('p4verifiedEmail').checked;
|
||
x.emailInvitation = Q('p4invitationEmail').checked;
|
||
}
|
||
meshserver.send(x);
|
||
}
|
||
|
||
function showUserGroupDialog(e, userid) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
userid = decodeURIComponent(userid);
|
||
var user = users[userid.toLowerCase()], groups = "";
|
||
if (user.groups != null) { groups = user.groups.join(', ') }
|
||
var x = "管理レルム名のコンマ区切りリストを入力します。" + '<br /><br />';
|
||
x += addHtmlValue("レルム", '<input id=dp4usergroups style=width:230px value="' + groups + '" placeholder=\"' + "Name1、Name2、Name3" + '\" maxlength=256 onchange=p4validateUserGroups() onkeyup=p4validateUserGroups() />');
|
||
setDialogMode(2, "管理レルム", 3, showUserGroupDialogEx, x, user);
|
||
focusTextBox('dp4usergroups');
|
||
p4validateUserGroups();
|
||
return false;
|
||
}
|
||
|
||
function p4validateUserGroups() {
|
||
var groups = Q('dp4usergroups').value;
|
||
var k = 0, i = groups.indexOf('\"') + groups.indexOf('/') + groups.indexOf('>') + groups.indexOf('<') + groups.indexOf('\'');
|
||
var g = groups.split(',');
|
||
for (var j in g) { if (g[j].trim().length == 0) k++; }
|
||
QE('idx_dlgOkButton', (groups == '') || ((i == -5) && (k < 1)));
|
||
}
|
||
|
||
function showUserGroupDialogEx(event, user) {
|
||
var groups = Q('dp4usergroups').value, g = groups.split(','), g2 = [];
|
||
for (var j in g) { var x = g[j].trim(); if (x.length > 0) { g2.push(x); } }
|
||
meshserver.send({ action: 'edituser', id: user._id, groups: g2 });
|
||
}
|
||
|
||
function showUserAdminDialog(e, userid) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
userid = decodeURIComponent(userid);
|
||
var x = '<div><div id=d2AdminPermissions>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fileaccess>' + "サーバーファイル" + '</label>, <input type=number onchange=showUserAdminDialogValidate() maxlength=10 id=ua_fileaccessquota>k max, blank for default<br><hr/>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fulladmin>' + "完全な管理者" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverbackup>' + "サーバーバックアップ" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverrestore>' + "サーバーの復元" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverupdate>' + "サーバーの更新" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_manageusers>' + "ユーザーを管理する" + '</label><br>';
|
||
x += '<hr/></div><label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_lockedaccount>' + "アカウントをロック" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_nonewgroups>' + "新しいデバイスグループはありません" + '</label><br>';
|
||
x += '<label><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_nomeshcmd>' + "ツールなし(MeshCmd / Router)" + '</label><br>';
|
||
x += '</div>';
|
||
var user = users[userid.toLowerCase()];
|
||
setDialogMode(2, "サーバーの許可", 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
|
||
Q('ua_nonewgroups').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 64) != 0)); // No New Groups
|
||
Q('ua_nomeshcmd').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 128) != 0)); // No Tools (MeshCMD / Router)
|
||
}
|
||
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_fileaccessquota', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_serverupdate', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QV('d2AdminPermissions', userinfo.siteadmin == 0xFFFFFFFF)
|
||
QE('ua_lockedaccount', (userinfo.siteadmin & 2) && (user.siteadmin != 0xFFFFFFFF) && (userinfo._id != user._id));
|
||
QE('ua_nonewgroups', (userinfo.siteadmin & 2) && (user.siteadmin != 0xFFFFFFFF) && (userinfo._id != user._id));
|
||
QE('ua_nomeshcmd', (userinfo.siteadmin & 2) && (user.siteadmin != 0xFFFFFFFF) && (userinfo._id != user._id));
|
||
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_lockedaccount', !Q('ua_fulladmin').checked);
|
||
QE('ua_nonewgroups', !Q('ua_fulladmin').checked);
|
||
QE('ua_nomeshcmd', !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;
|
||
if (Q('ua_nonewgroups').checked == true) siteadmin += 64;
|
||
if (Q('ua_nomeshcmd').checked == true) siteadmin += 128;
|
||
}
|
||
var x = { action: 'edituser', id: user._id, siteadmin: siteadmin };
|
||
if (isNaN(quota) == false) { x.quota = (quota * 1024); }
|
||
meshserver.send(x);
|
||
}
|
||
|
||
function onUserSearchInputChanged() { updateUsers(); }
|
||
|
||
//
|
||
// 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 = [], premsg = '';
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { premsg = '<img src="images/padlock12.png" height=12 width=8 title="Account is locked" style="margin-top:2px" /> '; msg.push("ロックされたアカウント"); }
|
||
if ((user.siteadmin == null) || ((user.siteadmin & (0xFFFFFFFF - 224)) == 0)) { msg.push("サーバーの権利なし"); } else if (user.siteadmin == 8) { msg.push("サーバーファイルへのアクセス"); } else if (user.siteadmin == 0xFFFFFFFF) { msg.push("完全な管理者"); } else { msg.push("部分的権利"); }
|
||
if ((user.siteadmin != null) && (user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & (64 + 128)) != 0)) { msg.push("制限事項"); }
|
||
|
||
// Show user attributes
|
||
var x = '<div style=min-height:80px><table style=width:100%>';
|
||
var email = user.email?EscapeHtml(user.email):'<i>' + "設定されていません" + '</i>', everify = '';
|
||
if (serverinfo.emailcheck) { everify = ((user.emailVerified == true) ? '<b style=color:green;cursor:pointer title=\"' + "メールが確認されました" + '\">✓</b> ' : '<b style=color:red;cursor:pointer title=\"' + "メールが確認されていません" + '\">✗</b> '); }
|
||
if (user.name.toLowerCase() != user._id.split('/')[2]) { x += addDeviceAttribute("ユーザー識別子", user._id.split('/')[2]); }
|
||
if (((features & 0x200000) == 0) && ((user.siteadmin != 0xFFFFFFFF) || (userinfo.siteadmin == 0xFFFFFFFF))) { // If we are not site admin, we can't change a admin email.
|
||
x += addDeviceAttribute("Eメール", everify + '<a href=# style=cursor:pointer onclick=p30showUserEmailChangeDialog(event,\"' + userid + '\")>' + email + '</a> <a href=# style=cursor:pointer onclick=\'return doemail(event,\"' + user.email + '\")\'><img class=hoverButton src="images/link1.png" /></a>');
|
||
} else {
|
||
x += addDeviceAttribute("Eメール", everify + email + ' <a href=# style=cursor:pointer onclick=\'return doemail(event,\"' + user.email + '\")\'><img class=hoverButton src="images/link1.png" /></a>');
|
||
}
|
||
x += addDeviceAttribute("サーバーの権利", premsg + '<a href=# style=cursor:pointer onclick=\'return showUserAdminDialog(event,\"' + userid + '\")\'>' + msg.join(', ') + '</a>');
|
||
if (user.quota) x += addDeviceAttribute("サーバークォータ", EscapeHtml(parseInt(user.quota) / 1024) + ' k');
|
||
x += addDeviceAttribute("作成", printDateTime(new Date(user.creation * 1000)));
|
||
if (user.login) x += addDeviceAttribute("前回のログイン", printDateTime(new Date(user.login * 1000)));
|
||
if (user.passchange == -1) { x += addDeviceAttribute("パスワード", "次回ログイン時に変更されます。"); }
|
||
else if (user.passchange) { x += addDeviceAttribute("パスワード", format("最終変更:{0}", printDateTime(new Date(user.passchange * 1000)))); }
|
||
|
||
// Device Groups
|
||
var linkCount = 0, linkCountStr = '<i>' + "なし" + '<i>';
|
||
if (user.links) {
|
||
for (var i in user.links) { linkCount++; }
|
||
if (linkCount == 1) { linkCountStr = "1グループ"; } else if (linkCount > 1) { linkCountStr = format("{0}グループ", linkCount); }
|
||
}
|
||
x += addDeviceAttribute("デバイスグループ", linkCountStr);
|
||
|
||
// Administrative Realms
|
||
if ((userinfo.siteadmin == 0xFFFFFFFF) || (userinfo.siteadmin & 2)) {
|
||
var userGroups = '<i>' + "なし" + '</i>';
|
||
if (user.groups) { userGroups = ''; for (var i in user.groups) { userGroups += '<span class="tagSpan">' + user.groups[i] + '</span>'; } }
|
||
x += addDeviceAttribute("管理レルム", addLinkConditional(userGroups, 'showUserGroupDialog(event,\"' + userid + '\")', (userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.groups == null) && (userinfo._id != user._id) && (user.siteadmin != 0xFFFFFFFF))));
|
||
}
|
||
|
||
var multiFactor = 0;
|
||
if ((user.otpsecret > 0) || (user.otphkeys > 0)) {
|
||
multiFactor = 1;
|
||
var factors = [];
|
||
if (user.otpsecret > 0) { factors.push("認証アプリ"); }
|
||
if (user.otphkeys > 0) { factors.push("セキュリティキー"); }
|
||
if (user.otpkeys > 0) { factors.push("バックアップコード"); }
|
||
x += addDeviceAttribute("セキュリティ", '<img src="images/key12.png" height=12 width=11 title=\"' + "二要素認証が有効" + '\" style="margin-top:2px" /> ' + factors.join(', '));
|
||
}
|
||
|
||
x += '</table></div><br />';
|
||
|
||
// Add action buttons
|
||
x += '<input type=button value=\"' + "ノート" + '\" title=\"' + "このユーザーに関するメモを表示" + '\" onclick=showNotes(false,"' + userid + '") />';
|
||
if (!self && (activeSessions > 0)) { x += '<input type=button value=\"' + "通知する" + '\" title=\"' + "ユーザー通知を送信する" + '\" 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 href=# style=cursor:pointer onclick=\'return p30showDeleteUserDialog()\' title="Remove this user">Delete User</a>';
|
||
x += '</div><div style=font-size:x-small>';
|
||
if (userinfo.siteadmin == 0xFFFFFFFF) x += '<a href=# style=cursor:pointer onclick=\'return p30showUserChangePassDialog(' + multiFactor + ')\' 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つのアクティブなセッション"; } else if (activeSessions > 1) { x = format("{0}アクティブセッション", activeSessions); }
|
||
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 false;
|
||
var x = '';
|
||
x += addHtmlValue("Eメール", '<input id=dp30email style=width:230px maxlength=32 onchange=p30validateEmail() onkeyup=p30validateEmail() />');
|
||
if (serverinfo.emailcheck) { x += addHtmlValue("状態", '<select id=dp30verified style=width:230px onchange=p30validateEmail()><option value=0>Not verified</option><option value=1>Verified</option></select>'); }
|
||
setDialogMode(2, format("{0}のメールを変更", EscapeHtml(currentUser.name)), 3, p30showUserEmailChangeDialogEx, x);
|
||
Q('dp30email').focus();
|
||
Q('dp30email').value = (currentUser.email?currentUser.email:'');
|
||
if (serverinfo.emailcheck) { Q('dp30verified').value = currentUser.emailVerified?1:0; }
|
||
p30validateEmail();
|
||
return false;
|
||
}
|
||
|
||
// 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', id: currentUser._id, 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(multiFactor) {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
x += addHtmlValue("パスワード", '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||
x += addHtmlValue("パスワード", '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=p30showUserChangePassDialogValidate(1) onkeyup=p30showUserChangePassDialogValidate(1)></input>');
|
||
if (features & 0x00010000) { x += addHtmlValue("パスワードのヒント", '<input id=p4hint type=text style=width:230px maxlength=256></input>'); }
|
||
|
||
if (passRequirements) {
|
||
var r = [], rc = 0;
|
||
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
|
||
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>' + format("要件:{0}。", r.join(', ')) + '</div>'; }
|
||
}
|
||
|
||
x += '<div><label><input id=p4resetNextLogin type=checkbox />' + "次回ログイン時にパスワードを強制的にリセットします。" + '</label></div>';
|
||
if (multiFactor == 1) { x += '<div><label><input id=p4twoFactorRemove type=checkbox />' + "すべての2要素認証を削除します。" + '</label></div>'; }
|
||
setDialogMode(2, format("{0}のパスワードを変更", EscapeHtml(currentUser.name)), 3, p30showUserChangePassDialogEx, x, multiFactor);
|
||
p30showUserChangePassDialogValidate();
|
||
Q('p4pass1').focus();
|
||
if (currentUser.passchange == -1) { Q('p4resetNextLogin').checked = true; }
|
||
}
|
||
|
||
function p30showUserChangePassDialogValidate() {
|
||
var ok = true;
|
||
if ((Q('p4pass1').value != '') || (Q('p4pass2').value != '')) {
|
||
if (Q('p4pass1').value != Q('p4pass2').value) { ok = false; } else {
|
||
if (passRequirements) { if (checkPasswordRequirements(Q('p4pass1').value, passRequirements) == false) { ok = false; } }
|
||
}
|
||
}
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
function p30showUserChangePassDialogEx(b, tag) {
|
||
var removeMultiFactor = false;
|
||
if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; }
|
||
if (Q('p4pass1').value == Q('p4pass2').value) {
|
||
var r = { action: 'changeuserpass', userid: currentUser._id, pass: Q('p4pass1').value, removeMultiFactor: removeMultiFactor, resetNextLogin: Q('p4resetNextLogin').checked };
|
||
if (features & 0x00010000) { r.hint = Q('p4hint').value; }
|
||
meshserver.send(r);
|
||
}
|
||
}
|
||
|
||
function p30showDeleteUserDialog() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, format("ユーザーを削除{0}", EscapeHtml(currentUser.name)), 3, p30showDeleteUserDialogEx, format('Confirm deletion of user {0}?', 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 ' + printTime(new Date(ts)) + ' to ' + printTime(new Date(te)) + '.';
|
||
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> ' + printDate(date) + '<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 userEventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in currentUserEvents) {
|
||
var event = currentUserEvents[i], time = new Date(event.time);
|
||
if (event.msg) {
|
||
if (event.h == null) { event.h = Math.random(); }
|
||
if (printDate(time) != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
dateHeader = printDate(time);
|
||
x += '<table class=p3eventsTable cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + dateHeader + '</td></tr>';
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = EscapeHtml(event.msg).split('(R)').join('®');
|
||
if (event.nodeid) {
|
||
var node = getNodeFromId(event.nodeid);
|
||
if (node != null) {
|
||
icon = 'si' + node.icon;
|
||
msg = '<a href=# onclick=\'gotoDevice("' + event.nodeid + '",10);haltEvent(event);\'>' + EscapeHtml(node.name) + '</a> → ' + msg;
|
||
}
|
||
}
|
||
if (event.username && (event.username != currentUser.name)) {
|
||
if ((userinfo.siteadmin & 2) && (event.userid)) {
|
||
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + EscapeHtml(event.username) + '</a> → ' + msg;
|
||
} else {
|
||
msg = EscapeHtml(event.username) + ' → ' + msg;
|
||
}
|
||
}
|
||
if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16';
|
||
x += '<tr onclick=showEventDetails(' + event.h + ',3) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1> </td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2> </td></tr><tr style=height:2px></tr>';
|
||
}
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = '<br><i>' + "イベントが見つかりません" + '</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 + ' onclick=d3folderset(\"' + encodeURIComponent(f.nx) + '\")></div> <a href=# style=cursor:pointer onclick=\'return d3folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
|
||
} else {
|
||
var link = shortname;
|
||
//if (f.s > 0) { link = "<a rel=\"noreferrer noopener\" 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 + '"> <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(); return false; }
|
||
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 notifySettings = getstore('notifications', 0);
|
||
var r = '';
|
||
if (notifications.length == 0) {
|
||
r = '<div style=margin:5px>' + "現在、通知はありません" + '</div>';
|
||
} else {
|
||
for (var i in notifications) {
|
||
var n = notifications[i], t = '', d = new Date(n.time), icon = 0;
|
||
if (n.title != null) { t = '<b>' + n.title + '</b>: ' }
|
||
if (n.nodeid != null) {
|
||
var node = getNodeFromId(n.nodeid);
|
||
if (node != null) {
|
||
icon = node.icon;
|
||
if (notifySettings & 16) { t = '<b>' + meshes[node.meshid].name + ' / ' + node.name + '</b>: '; } else { t = '<b>' + node.name + '</b>: '; } // Display with or without group name
|
||
}
|
||
}
|
||
|
||
r += '<div title="' + format("{0}で発生しました", printDateTime(d)) + '" id="notifyx' + n.id + '" class=notification style="cursor:pointer;border-top:1px solid ' + ((r == '') ? 'transparent' : 'orange') + '">';
|
||
if (icon) { r += '<div class=j' + icon + ' onclick="notificationSelected(' + n.id + ')" style=margin:5px;float:left></div>'; }
|
||
r += '<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, del) {
|
||
var j = -1;
|
||
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
|
||
if (j != -1) {
|
||
notificationSelectedEx(notifications[j], id);
|
||
if (del && notifications[j]) {
|
||
if (notifications[j].notification) { notifications[j].notification.close(); delete notifications[j].notification; }
|
||
notificationDelete(id);
|
||
}
|
||
}
|
||
}
|
||
|
||
function notificationSelectedEx(n, id) {
|
||
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
|
||
} else {
|
||
if ((n.tag != null) && n.tag.startsWith('meshmessenger/')) {
|
||
window.open('/messenger?id=' + n.tag + '&title=' + encodeURIComponent(n.username), n.tag.split('/')[2]);
|
||
notificationDelete(id);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 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) {
|
||
if (notifications[j].notification) { notifications[j].notification.close(); delete notifications[j].notification; }
|
||
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) {
|
||
// Show notification within the web page.
|
||
if (n.time == null) { n.time = Date.now(); }
|
||
if (n.id == null) { n.id = Math.random(); }
|
||
notifications.unshift(n);
|
||
setNotificationCount(notifications.length);
|
||
clickNotificationIcon(true);
|
||
var notifySettings = getstore('notifications', 0);
|
||
if (notifySettings & 1) { Q('chimes').play(); }
|
||
|
||
// If web notifications are granted, use it.
|
||
var notification = null;
|
||
if (Notification && (Notification.permission == 'granted')) {
|
||
var text = n.text.split('®').join('').split('<b>').join('').split('</b>').join('').split('<br />').join('\r\n'); // Clean up any HTML codes
|
||
if (n.nodeid) {
|
||
var node = getNodeFromId(n.nodeid);
|
||
if (node) {
|
||
if (notifySettings & 16) { // Notify with group name
|
||
notification = new Notification('{{{title}}} - ' + meshes[node.meshid].name + ' - ' + node.name, { tag: n.tag, body: text, icon: '/images/notify/icons128-' + node.icon + '.png' });
|
||
} else {
|
||
notification = new Notification('{{{title}}} - ' + node.name, { tag: n.tag, body: text, icon: '/images/notify/icons128-' + node.icon + '.png' });
|
||
}
|
||
}
|
||
} else {
|
||
if (n.icon == null) { n.icon = 0; }
|
||
var title = n.title;
|
||
if (title == null) { title = ''; } else { title = ' - ' + n.title; }
|
||
notification = new Notification('{{{title}}}' + title, { tag: n.tag, body: text, icon: '/images/notify/icons128-' + n.icon + '.png' });
|
||
}
|
||
notification.id = n.id;
|
||
notification.xtag = n.tag;
|
||
notification.nodeid = n.nodeid;
|
||
notification.username = n.username;
|
||
notification.onclick = function (e) { notificationSelected(e.target.id, true); }
|
||
n.notification = notification;
|
||
}
|
||
}
|
||
|
||
// Remove all notifications
|
||
function deleteAllNotifications() {
|
||
notifications = [];
|
||
setNotificationCount(0);
|
||
drawNotifications();
|
||
QV('notifiyBox', false);
|
||
}
|
||
|
||
//
|
||
// MyServer General
|
||
//
|
||
|
||
function setupGeneralServerStats() {
|
||
window.serverStatCpu = new Chart(document.getElementById('serverCpuChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ["中古", "無料"] },
|
||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||
});
|
||
window.serverStatMemory = new Chart(document.getElementById('serverMemoryChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ["中古", "無料"] },
|
||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||
});
|
||
}
|
||
|
||
var lastServerStats = null;
|
||
function updateGeneralServerStats(message) {
|
||
if (message != null) { lastServerStats = message; } else { message = lastServerStats; }
|
||
if (message == null) return;
|
||
|
||
// Paint the pie graphs
|
||
if (typeof message.cpuavg == 'object') {
|
||
var m = Math.min(message.cpuavg[0], 1);
|
||
window.serverStatCpu.config.data.datasets[0].data = [m, 1 - m];
|
||
QH('serverCpuChartText', '<div style=margin-bottom:5px>CPU Load</div><div><b title=\"' + "直前のCPU負荷" + '\">' + (Math.round(message.cpuavg[0] * 100.0) / 100.0) + '</b>, <b title=\"' + "過去5分間のCPU負荷" + '\">' + (Math.round(message.cpuavg[1] * 100.0) / 100.0) + '</b>, <b title=\"' + "過去15分間のCPU負荷" + '\">' + (Math.round(message.cpuavg[2] * 100.0) / 100.0) + '</b></div>');
|
||
QS('serverCpuChartView')['display'] = 'inline-block';
|
||
window.serverStatCpu.update();
|
||
}
|
||
if ((typeof message.totalmem == 'number') && (typeof message.freemem == 'number')) {
|
||
window.serverStatMemory.config.data.datasets[0].data = [message.totalmem - message.freemem, message.freemem];
|
||
QH('serverMemoryChartText', '<div style=margin-bottom:5px>' + "記憶" + '</div><div><b>' + getNiceSize2(message.freemem) + '</b> ' + "無料" + ', <b>' + getNiceSize2(message.totalmem) + '</b> ' + "合計" + '</div>');
|
||
QS('serverMemoryChartView')['display'] = 'inline-block';
|
||
window.serverStatMemory.update();
|
||
}
|
||
|
||
// Display all of the server values
|
||
var x = '<div style=width:100% cellpadding=0 cellspacing=0>';
|
||
if (typeof message.values == 'object') {
|
||
for (var i in message.values) {
|
||
x += '<div class=userTableHeader style=margin-bottom:4px;width:200px>' + i + '</div>';
|
||
for (var j in message.values[i]) {
|
||
x += '<div style=display:inline-block><table class=serverStateTableCell><tr><td class=h1></td><td><span>' + j + '</span><span style=float:right>' + message.values[i][j] + '</span></td><td class=h2></td></tr></table></div>';
|
||
}
|
||
}
|
||
}
|
||
x += '</div>';
|
||
|
||
QH('serverStatsTable', x);
|
||
}
|
||
|
||
//
|
||
// MyServer Stats
|
||
//
|
||
|
||
var serverTimelineStats = null;
|
||
var serverTimelineConfig = {
|
||
type: 'line',
|
||
data: { labels: [], datasets: [{ label: '', backgroundColor: 'rgba(255, 99, 132, .5)', borderColor: 'rgb(255, 99, 132)', data: [], fill: true }] },
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
elements: { line: { cubicInterpolationMode: 'monotone' } },
|
||
scales: {
|
||
xAxes: [{ type: 'time', time: { tooltipFormat: 'll HH:mm' }, display: true, scaleLabel: { display: false, labelString: '' } }],
|
||
yAxes: [{ type: 'linear', display: true, scaleLabel: { display: true, labelString: '' } }]
|
||
}
|
||
}
|
||
};
|
||
|
||
function refreshServerTimelineStats(stats) { meshserver.send({ action: 'servertimelinestats', hours: 24 * 30 }); }
|
||
function pastDate(hours) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); return t; }
|
||
function setServerTimelineStats(stats) { serverTimelineStats = stats; updateServerTimelineStats(); }
|
||
function addServerTimelineStats(stats) {
|
||
if (serverTimelineStats == null) return;
|
||
serverTimelineStats.push(stats);
|
||
var chartType = Q('p40type').value;
|
||
if (chartType == 0) {
|
||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.conn.ca });
|
||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.conn.cu });
|
||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.conn.us });
|
||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.conn.rs });
|
||
if (stats.conn.am != null) { serverTimelineConfig.data.datasets[4].data.push({ x: stats.time, y: stats.conn.am }); }
|
||
} else if (chartType == 1) {
|
||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.mem.external / (1024 * 1024) });
|
||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.mem.heapUsed / (1024 * 1024) });
|
||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.mem.heapTotal / (1024 * 1024) });
|
||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.mem.rss / (1024 * 1024) });
|
||
} /* else if (chartType == 2) {
|
||
serverTimelineConfig.data.datasets[0].data.push({ x: stats.time, y: stats.db.meshes });
|
||
serverTimelineConfig.data.datasets[1].data.push({ x: stats.time, y: stats.db.nodes });
|
||
serverTimelineConfig.data.datasets[2].data.push({ x: stats.time, y: stats.db.users });
|
||
serverTimelineConfig.data.datasets[3].data.push({ x: stats.time, y: stats.db.total });
|
||
} */
|
||
updateServerTimelineHours();
|
||
}
|
||
function updateServerTimelineHours() {
|
||
serverTimelineConfig.options.scales.yAxes[0].type = (Q('p40log').checked ? 'logarithmic' : 'linear');
|
||
serverTimelineConfig.options.scales.xAxes[0].time = { min: pastDate(Q('p40time').value) };
|
||
window.serverMainStats.update();
|
||
}
|
||
function setupServerTimelineStats() { window.serverMainStats = new Chart(document.getElementById('serverMainStats').getContext('2d'), serverTimelineConfig); }
|
||
|
||
function updateServerTimelineStats() {
|
||
var data, chartType = Q('p40type').value, timeAfter = pastDate(Q('p40time').value);
|
||
serverTimelineConfig.options.scales.xAxes[0].time = { min: timeAfter };
|
||
if (chartType == 0) { // Connections
|
||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = "接続数";
|
||
data = {
|
||
labels: [pastDate(0), timeAfter],
|
||
datasets: [
|
||
{ label: "エージェント", data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||
{ label: "ユーザー", data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||
{ label: "ユーザーセッション", data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||
{ label: "中継セッション", data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true },
|
||
{ label: "Intel AMT", data: [], backgroundColor: 'rgba(134, 16, 158, .1)', borderColor: 'rgb(134, 16, 158)', fill: true }
|
||
]
|
||
};
|
||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||
var t = new Date(serverTimelineStats[i].time);
|
||
if (serverTimelineStats[i].conn) {
|
||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.ca });
|
||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.cu });
|
||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.us });
|
||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.rs });
|
||
if (serverTimelineStats[i].conn.am != null) { data.datasets[4].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].conn.am }); }
|
||
}
|
||
}
|
||
} else if (chartType == 1) { // Memory
|
||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = "メガバイト";
|
||
data = {
|
||
labels: [pastDate(0), timeAfter],
|
||
datasets: [
|
||
{ label: 'External', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||
{ label: 'Heap Used', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||
{ label: 'Heap Total', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||
{ label: 'RSS', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true }
|
||
]
|
||
};
|
||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.external / (1024 * 1024) });
|
||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.heapUsed / (1024 * 1024) });
|
||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.heapTotal / (1024 * 1024) });
|
||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].mem.rss / (1024 * 1024) });
|
||
}
|
||
} /*else if (chartType == 2) { // Database
|
||
serverTimelineConfig.options.scales.yAxes[0].scaleLabel.labelString = 'Records';
|
||
data = {
|
||
labels: [pastDate(0), timeAfter],
|
||
datasets: [
|
||
{ label: 'Groups', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
|
||
{ label: 'Devices', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
|
||
{ label: 'Users', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
|
||
{ label: 'Records', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true }
|
||
]
|
||
};
|
||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||
data.datasets[0].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.meshes });
|
||
data.datasets[1].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.nodes });
|
||
data.datasets[2].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.users });
|
||
data.datasets[3].data.push({ x: serverTimelineStats[i].time, y: serverTimelineStats[i].db.total });
|
||
}
|
||
}*/
|
||
serverTimelineConfig.data = data;
|
||
window.serverMainStats.update();
|
||
}
|
||
|
||
function p40downloadEvents() {
|
||
var csv = "time、conn.agent、conn.users、conn.usersessions、conn.relaysession、conn.intelamt、mem.external、mem.heapused、mem.heaptotal、mem.rss" + '\r\n';
|
||
for (var i = 0; i < serverTimelineStats.length; i++) {
|
||
if (serverTimelineStats[i].conn && serverTimelineStats[i].mem) {
|
||
csv += new Date(serverTimelineStats[i].time) + ', ' + serverTimelineStats[i].conn.ca + ', ' + serverTimelineStats[i].conn.cu + ', ' + serverTimelineStats[i].conn.us + ', ' + serverTimelineStats[i].conn.rs + ', ' + (serverTimelineStats[i].conn.am ? serverTimelineStats[i].conn.am : '') + ', ' + serverTimelineStats[i].mem.external + ', ' + serverTimelineStats[i].mem.heapUsed + ', ' + serverTimelineStats[i].mem.heapTotal + ', ' + serverTimelineStats[i].mem.rss + '\r\n';
|
||
}
|
||
}
|
||
saveAs(new Blob([csv], { type: 'application/octet-stream' }), "ServerStats.csv");
|
||
}
|
||
|
||
//
|
||
// My Server Tracing
|
||
//
|
||
|
||
var serverTrace = [];
|
||
var serverTraceSources = [];
|
||
|
||
function displayServerTrace() {
|
||
var x = '', max = parseInt(Q('p41limitdropdown').value);
|
||
if (serverTrace.length > max) { serverTrace.splice(max); }
|
||
for (var i in serverTrace) { x += '<div class=traceEvent>' + EscapeHtml(new Date(serverTrace[i].time).toLocaleTimeString()) + ' - <b>' + EscapeHtml(serverTrace[i].source.toUpperCase()) + '</b>: ' + EscapeHtml(serverTrace[i].args.join(', ')) + '</div>' }
|
||
QH('p41events', x);
|
||
}
|
||
|
||
function clearServerTracing() { serverTrace = []; displayServerTrace(); }
|
||
|
||
function setServerTracing() {
|
||
var x = '';
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "コアサーバー" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=p41c1 ' + ((serverTraceSources.indexOf('cookie') >= 0) ? 'checked' : '') + '>' + "Cookieエンコーダー" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c2 ' + ((serverTraceSources.indexOf('dispatch') >= 0) ? 'checked' : '') + '>' + "メッセージディスパッチャー" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c3 ' + ((serverTraceSources.indexOf('main') >= 0) ? 'checked' : '') + '>' + "メインサーバーメッセージ" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c4 ' + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + '>' + "MeshCentralサーバーピアリング" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c15 ' + ((serverTraceSources.indexOf('agent') >= 0) ? 'checked' : '') + '>' + "MeshAgentトラフィック" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c14 ' + ((serverTraceSources.indexOf('agentupdate') >= 0) ? 'checked' : '') + '>' + "MeshAgentの更新" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c16 ' + ((serverTraceSources.indexOf('cert') >= 0) ? 'checked' : '') + '>' + "サーバー証明書" + '</label></div>';
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Webサーバー" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=p41c5 ' + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + '>' + "Webサーバー" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c6 ' + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + '>' + "Webサーバーリクエスト" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c7 ' + ((serverTraceSources.indexOf('relay') >= 0) ? 'checked' : '') + '>' + "Webソケットリレー" + '</label></div>';
|
||
//x += '<div><label><input type=checkbox id=p41c8 ' + ((serverTraceSources.indexOf('webrelaydata') >= 0) ? 'checked' : '') + '>' + "Traffic Relay 2 Data" + '</label></div>';
|
||
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>' + "Intel AMT" + '</b></div>';
|
||
x += '<div><label><input type=checkbox id=p41c9 ' + ((serverTraceSources.indexOf('webrelay') >= 0) ? 'checked' : '') + '>' + "接続リレー" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c10 ' + ((serverTraceSources.indexOf('mps') >= 0) ? 'checked' : '') + '>' + "CIRAサーバー" + '</label></div>';
|
||
x += '<div><label><input type=checkbox id=p41c11 ' + ((serverTraceSources.indexOf('mpscmd') >= 0) ? 'checked' : '') + '>' + "CIRAサーバーコマンド" + '</label></div>';
|
||
//x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>Legacy</b></div>';
|
||
//x += '<div><label><input type=checkbox id=p41c12 ' + ((serverTraceSources.indexOf('swarm') >= 0) ? 'checked' : '') + ">' + "Legacy Swarm Server" + '</label></div>";
|
||
//x += '<div><label><input type=checkbox id=p41c13 ' + ((serverTraceSources.indexOf('swarmcmd') >= 0) ? 'checked' : '') + ">' + "Legacy Swarm Server Commands" + '</label></div>";
|
||
setDialogMode(2, "サーバートレース", 7, setServerTracingEx, x);
|
||
}
|
||
|
||
function setServerTracingEx(b) {
|
||
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd', 'agentupdate', 'agent', 'cert'];
|
||
if (b == 1) { for (var i = 1; i < 17; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
|
||
meshserver.send({ action: 'traceinfo', traceSources: sources });
|
||
}
|
||
|
||
function p41downloadServerTrace() {
|
||
var csv = "時間、ソース、メッセージ" + '\r\n';
|
||
for (var i in serverTrace) { csv += '\"' + new Date(serverTrace[i].time).toLocaleTimeString() + '\",\"' + serverTrace[i].source + '\",\"' + serverTrace[i].args.join(', ') + '\"\r\n'; }
|
||
saveAs(new Blob([csv], { type: 'application/octet-stream' }), "servertrace.csv");
|
||
return false;
|
||
}
|
||
|
||
//
|
||
// POPUP DIALOG
|
||
//
|
||
|
||
// null = Hidden, 1 = Generic Message
|
||
var xxdialogMode;
|
||
var xxdialogFunc;
|
||
var xxdialogButtons;
|
||
var xxdialogTag;
|
||
var xxcurrentView = -1;
|
||
|
||
// 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) {
|
||
setSessionActivity();
|
||
QV('uiMenu', false);
|
||
xxdialogMode = x;
|
||
xxdialogFunc = f;
|
||
xxdialogButtons = b;
|
||
xxdialogTag = tag;
|
||
|
||
// Reset dialog size
|
||
QS('dialog').width = QS('dialog').top = QS('dialog').left = QS('dialog').right = QS('dialog').bottom = null;
|
||
|
||
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) {
|
||
setSessionActivity();
|
||
var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
|
||
setDialogMode();
|
||
if (((b & 8) || x) && f) f(x, t);
|
||
}
|
||
|
||
function center() {
|
||
setSessionActivity();
|
||
if (xxcurrentView == 11) { deskAdjust(); }
|
||
else if (xxcurrentView == 10) { masterUpdate(256); }
|
||
else if (xxcurrentView == 1) { masterUpdate(4); }
|
||
}
|
||
function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||
function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||
|
||
function goBack() {
|
||
setSessionActivity();
|
||
if (xxdialogMode || (goBackStack.length == 0)) return;
|
||
if (fullscreen) { deskToggleFull(); }
|
||
go(goBackStack.pop());
|
||
goBackStack.pop();
|
||
}
|
||
|
||
function go(x, event) {
|
||
setSessionActivity();
|
||
if (xxdialogMode) return;
|
||
QV('uiMenu', false);
|
||
|
||
// If "shift" is pressed, open a new tab.
|
||
if (event && (event.shiftKey == true) && (x != 15) && ('{{currentNode}}' == '')) {
|
||
// Open the device in a different tab
|
||
if ((x >= 10) && (x <= 19)) {
|
||
if (currentNode) { window.open(window.location.origin + '?node=' + currentNode._id.split('/')[2] + '&viewmode=' + x + '&hide=16', 'meshcentral:' + currentNode._id); }
|
||
} else if (x < 10) {
|
||
window.open(window.location.origin + '?viewmode=' + x + '&hide=0', 'meshcentral:' + x);
|
||
}
|
||
return;
|
||
}
|
||
|
||
// If we are going to the same place, do nothing.
|
||
if (xxcurrentView == x) return;
|
||
|
||
// Set the goback stack, if going to top-level view, clear the stack.
|
||
if ((xxcurrentView < 0) || (x < 10)) { goBackStack = []; } else {
|
||
// Do not push into the back stack if we are changing tabs at the same level.
|
||
if (Math.floor(xxcurrentView / 10) != Math.floor(x / 10)) { goBackStack.push(xxcurrentView); }
|
||
}
|
||
|
||
// Edit this line when adding a new screen
|
||
for (var i = 0; i < 44; i++) { QV('p' + i, i == x); }
|
||
xxcurrentView = x;
|
||
|
||
// Remove top bar selection
|
||
var mainBarItems = ['MainMenuMyDevices', 'MainMenuMyAccount', 'MainMenuMyEvents', 'MainMenuMyFiles', 'MainMenuMyUsers', 'MainMenuMyServer'];
|
||
for (var i in mainBarItems) {
|
||
QC(mainBarItems[i]).remove('fullselect');
|
||
QC(mainBarItems[i]).remove('semiselect');
|
||
}
|
||
|
||
// Remove left bar selection
|
||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
||
for (var i in leftBarItems) {
|
||
QC(leftBarItems[i]).remove('lbbuttonsel');
|
||
QC(leftBarItems[i]).remove('lbbuttonsel2');
|
||
}
|
||
|
||
// Define class for Menu(s) as fully or semi active.
|
||
var mainMenuActiveClass = (x < 9 ? 'fullselect' : 'semiselect');
|
||
var leftMenuActiveClass = (((x < 9) || (x == 115) || (x == 40) || (x == 41) || (x == 42)) ? 'lbbuttonsel2' : 'lbbuttonsel');
|
||
|
||
var backView = 0;
|
||
if (goBackStack.length > 0) { backView = goBackStack[goBackStack.length - 1]; }
|
||
|
||
// My Devices
|
||
if (x == 1 || (backView == 1) || ((backView == 0) && (x >= 10 && x < 20))) {
|
||
QC('MainMenuMyDevices').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyDevices').add(leftMenuActiveClass);
|
||
} else if (x == 2 || (backView == 2) || ((backView == 0) && (x >= 20 && x < 30))) {
|
||
// My Account
|
||
QC('MainMenuMyAccount').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyAccount').add(leftMenuActiveClass);
|
||
} else if (x == 3) {
|
||
// My Events
|
||
QC('MainMenuMyEvents').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyEvents').add(leftMenuActiveClass);
|
||
} else if (x == 4 || (x >= 30 && x < 40)) {
|
||
// My Users
|
||
QC('MainMenuMyUsers').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyUsers').add(leftMenuActiveClass);
|
||
} else if (x == 5) {
|
||
// My Files
|
||
QC('MainMenuMyFiles').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyFiles').add(leftMenuActiveClass);
|
||
} else if ((x == 6) || (x == 115) || (x >= 40 && x < 50)) {
|
||
// My Server
|
||
QC('MainMenuMyServer').add(mainMenuActiveClass);
|
||
QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||
}
|
||
QV('ServerPlugins', pluginHandler != null);
|
||
|
||
// column_l max-height
|
||
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||
|
||
// If we are going to panel 0 in "full screen mode", hide the left bar.
|
||
QV('topbar', x != 0);
|
||
if ((x == 0) && (webPageFullScreen)) { QC('body').add('arg_hide'); }
|
||
|
||
QV('MainSubMenuSpan', (x >= 10) && (x < 20));
|
||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||
QV('MeshSubMenuSpan', (x >= 20) && (x < 30));
|
||
QV('UserSubMenuSpan', (x >= 30) && (x < 40));
|
||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41 || x == 42 || x == 43);
|
||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 17: 'MainDevInfo', 19: 'MainDevPlugins', 20: 'MeshGeneral', 21: 'MeshSummary', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 42: 'ServerPlugins', 115: 'ServerConsole' };
|
||
for (var i in panels) {
|
||
QC(panels[i]).remove('style3x');
|
||
QC(panels[i]).remove('style3sel');
|
||
QC(panels[i]).add((x == i) ? 'style3sel' : 'style3x');
|
||
}
|
||
|
||
// If going to the remote desktop tab, adjust the tab.
|
||
if (x == 11) { deskAdjust(); }
|
||
|
||
// Panel 115 is weird, it's panel 15 for device console but used as a server console.
|
||
if (x == 115) { QV('p15', true); }
|
||
QV('p15uploadCore', x != 115);
|
||
QV('p15BackButton', x != 115);
|
||
if ((x == 15) || (x == 115)) { setupConsole(); }
|
||
|
||
if (x == 1) masterUpdate(4);
|
||
|
||
// Setup web notifications
|
||
if ((x == 2) && Notification) { QV('accountEnableNotificationsSpan', Notification.permission != 'granted'); }
|
||
|
||
// Fetch the server timeline stats if needed
|
||
if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
|
||
|
||
// MyServer Plugins
|
||
if (x == 42) { refreshPluginLatest(); }
|
||
|
||
// Update Mesh Summary
|
||
if (x == 21) { p21updateMesh(); }
|
||
|
||
// Update the web page title
|
||
if ((currentNode) && (x >= 10) && (x < 20)) {
|
||
document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + meshes[currentNode.meshid].name;
|
||
} else {
|
||
document.title = decodeURIComponent('{{{extitle}}}');
|
||
}
|
||
}
|
||
|
||
//
|
||
// Plugin Management
|
||
//
|
||
|
||
function updatePluginList(versInfo) {
|
||
if (pluginHandler == null) return;
|
||
if (Array.isArray(versInfo)) { versInfo.forEach(function(v) { updatePluginList(v); }); }
|
||
QV('pluginNoneNotice', installedPluginList.length == 0);
|
||
if (installedPluginList.length) {
|
||
if (versInfo != null) {
|
||
if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
|
||
installedPluginList['version_info'][versInfo.id] = versInfo;
|
||
}
|
||
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||
if (tr.length) {
|
||
for (var i in Object.values(tr)) {
|
||
tr[i].parentNode.removeChild(tr[i]);
|
||
}
|
||
}
|
||
var statusMap = {
|
||
0: {
|
||
'text': 'Disabled',
|
||
'color': '858483'
|
||
},
|
||
1: {
|
||
'text': 'Installed',
|
||
'color': '00aa00'
|
||
}
|
||
};
|
||
var statusAvailability = {
|
||
0: {
|
||
'install': 'Install',
|
||
'delete': 'Delete'
|
||
},
|
||
1: {
|
||
'disable': 'Disable',
|
||
'upgrade': 'Upgrade',
|
||
// 'downgrade': 'Downgrade' // disabling until plugins have prior versions available for better testing
|
||
}
|
||
};
|
||
var vers_not_compat = ' [ <span onclick="return setDialogMode(2, \'Compatibility Issue\', 1, null, \'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.\');" title="Version incompatible, please upgrade your MeshCentral installation first" style="cursor: pointer; color:red;"> ! </span> ]';
|
||
|
||
var tbl = Q('p42tbl');
|
||
installedPluginList.forEach(function(p){
|
||
var cant_action = [];
|
||
if (p.hasAdminPanel == true && p.status) {
|
||
p.nameHtml = '<a onclick="return goPlugin(\'' + p.shortName + '\', \'' + p.name.replace(/'/g, "\\'") + '\');">' + p.name + '</a>';
|
||
} else {
|
||
p.nameHtml = p.name;
|
||
}
|
||
p.statusText = statusMap[p.status].text;
|
||
p.statusColor = statusMap[p.status].color;
|
||
|
||
if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
|
||
if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
|
||
p.upgradeAvail = "確認しています...";
|
||
if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
|
||
var vin = installedPluginList['version_info'][p._id];
|
||
if (vin.hasUpdate) {
|
||
p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||
} else {
|
||
cant_action.push('upgrade');
|
||
if (p.status) p.upgradeAvail = "最新の";
|
||
else p.upgradeAvail = '<a title="View Changelog" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
|
||
}
|
||
if (!vin.meshCentralCompat) {
|
||
p.upgradeAvail += vers_not_compat;
|
||
cant_action.push('install');
|
||
cant_action.push('upgrade');
|
||
}
|
||
}
|
||
|
||
p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
|
||
var entries = Object.entries(statusAvailability[p.status]);
|
||
for (var k in entries) {
|
||
if (cant_action.indexOf(entries[k][0]) === -1) {
|
||
p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
|
||
}
|
||
}
|
||
p.actions += '</select>';
|
||
|
||
let tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>' + p.nameHtml + '</td><td class=gradTable2>' + p.description + '</td><td class=gradTable2 style=text-align:center><a href="' + p.homepage + '" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>' + p.version + '</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">' + p.upgradeAvail + '</td><td class=gradTable2 style="text-align:center;color:#' + p.statusColor + '">' + p.statusText + '</td><td class="pluginAction gradTable2" style=text-align:center>' + p.actions + '</td><td class=gradTable3> </td>';
|
||
let tr = tbl.insertRow(-1);
|
||
tr.innerHTML = tpl;
|
||
tr.classList.add('p42tblRow');
|
||
tr.setAttribute('data-id', p._id);
|
||
tr.setAttribute('id', 'pluginRow-' + p._id);
|
||
});
|
||
} else {
|
||
var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
|
||
for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
|
||
}
|
||
if (versInfo == null) refreshPluginLatest();
|
||
}
|
||
|
||
function refreshPluginLatest() {
|
||
if (pluginHandler == null) return;
|
||
meshserver.send({ action: 'pluginLatestCheck' });
|
||
}
|
||
|
||
function distributeCore() {
|
||
if (pluginHandler == null) return;
|
||
meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
|
||
QV('pluginRestartNotice', false);
|
||
}
|
||
|
||
function pluginActionEx() {
|
||
if (pluginHandler == null) return;
|
||
var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;
|
||
|
||
switch(act) {
|
||
case 'upgrade':
|
||
case 'install':
|
||
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
|
||
break;
|
||
case 'downgrade':
|
||
Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
|
||
if (opt.value == pVersUrl) pVers = opt.text;
|
||
});
|
||
meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
|
||
break;
|
||
case 'delete':
|
||
meshserver.send({ 'action': 'removeplugin', 'id': id });
|
||
break;
|
||
case 'disable':
|
||
meshserver.send({ 'action': 'disableplugin', 'id': id });
|
||
break;
|
||
}
|
||
QV('pluginRestartNotice', true);
|
||
}
|
||
|
||
function pluginAction(elem, id) {
|
||
if (pluginHandler == null) return;
|
||
if (elem.value == 'downgrade') {
|
||
meshserver.send({ 'action': 'getpluginversions', 'id': id });
|
||
} else {
|
||
var plugin = null;
|
||
for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
|
||
setDialogMode(2, "プラグインアクション", 3, pluginActionEx, format("プラグインを{0}してもよろしいですか:{1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
|
||
}
|
||
elem.value = '';
|
||
}
|
||
|
||
function goPlugin(pname, title) {
|
||
if (pluginHandler == null) return;
|
||
if (pname == null) { Q('p43iframe').src = ''; } else { QH('p43title', title); Q('p43iframe').src = '/pluginadmin.ashx?pin=' + pname; go(43); }
|
||
}
|
||
|
||
// 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') || (localStorage.getItem(name) == val)) return;
|
||
if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { }
|
||
if (name[0] != '_') {
|
||
var s = {};
|
||
for (var i = 0, len = localStorage.length; i < len; ++i) {
|
||
var k = localStorage.key(i);
|
||
if (k[0] != '_') {
|
||
s[k] = localStorage.getItem(k);
|
||
if ((k != 'desktopsettings') && (typeof s[k] == 'string') && (s[k].length > 64)) { delete s[k]; }
|
||
}
|
||
}
|
||
meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
|
||
}
|
||
}
|
||
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 '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress=\"if (event.key==\'Enter\') {' + f + '} \">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
|
||
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) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||
function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != 'SUCCESS') { messagebox("呼び出しエラー", 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 href=# style=cursor:pointer;color:blue id=morexxx1 onclick=QV(\"morexxx1\",false);QV(\"morexxx2\",true)>▼ ' + "もっと" + '</a><div id=morexxx2 style=display:none><br><hr>'; };
|
||
function MoreEnd() { return '<a href=# style=cursor:pointer;color:blue onclick=QV(\"morexxx2\",false);QV(\"morexxx1\",true)>▲ ' + "もっと少なく" + '</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 addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</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 = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
|
||
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
|
||
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||
function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
|
||
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
|
||
function findOne(arr1, arr2) { if ((arr1 == null) || (arr2 == null)) return false; return arr2.some(function (v) { return arr1.indexOf(v) >= 0; }); };
|
||
function copyTextToClip(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = txt; document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
|
||
function copyTextToClip2(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = decodeURIComponent(txt); document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
|
||
function capitalizeFirstLetter(x) { return x.charAt(0).toUpperCase() + x.slice(1); }
|
||
function printDate(d) { return d.toLocaleDateString(args.locale); }
|
||
function printTime(d) { return d.toLocaleTimeString(args.locale); }
|
||
function printDateTime(d) { return d.toLocaleString(args.locale); }
|
||
function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
|
||
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||
function addTextLink(subtext, text, link) { var i = text.toLowerCase().indexOf(subtext.toLowerCase()); if (i == -1) { return text; } return text.substring(0, i) + '<a href=\"' + link + '\">' + subtext + '</a>' + text.substring(i + subtext.length); }
|
||
function nobreak(x) { return x.split(' ').join(' '); }
|
||
|
||
</script>
|
||
|
||
|
||
</body></html> |