MeshCentral/views/translations/default-mobile_ja.handlebars

3391 lines
219 KiB
Handlebars
Raw Normal View History

2019-12-09 19:34:37 -05:00
<!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">
<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/agent-redir-ws-0.1.1.js"></script>
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
<script type="text/javascript" src="scripts/amt-0.2.0.js"></script>
<script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
<script type="text/javascript" src="scripts/amt-desktop-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 keeplink="1" type="text/javascript" src="scripts/filesaver.js"></script>
<title>{{{title}}}</title>
<style>
a {
color: #036;
text-decoration: underline;
}
#footer a {
color: #fff;
text-decoration: underline;
}
#footer a:hover {
color: #fff;
text-decoration: none;
}
.i1 {
background: url(../images/icons50.png) 0px 0px;
height: 50px;
width: 50px;
border: none;
}
.i2 {
background: url(../images/icons50.png) -50px 0px;
height: 50px;
width: 50px;
border: none;
}
.i3 {
background: url(../images/icons50.png) -100px 0px;
height: 50px;
width: 50px;
border: none;
}
.i4 {
background: url(../images/icons50.png) -150px 0px;
height: 50px;
width: 50px;
border: none;
}
.i5 {
background: url(../images/icons50.png) -200px 0px;
height: 50px;
width: 50px;
border: none;
}
.i6 {
background: url(../images/icons50.png) -250px 0px;
height: 50px;
width: 50px;
border: none;
}
.m0 {
background: url(../images/images16.png) -32px 0px;
height: 16px;
width: 16px;
border: none;
float: left;
}
.m1 {
background: url(../images/images16.png) -16px 0px;
height: 16px;
width: 16px;
border: none;
float: left;
}
.m2 {
background: url(../images/images16.png) -96px 0px;
height: 16px;
width: 16px;
border: none;
float: left;
}
.m3 {
background: url(../images/images16.png) -112px 0px;
height: 16px;
width: 16px;
border: none;
float: left;
}
.gray {
/*filter: url("data:image/svg+xml;utf8,&lt;svg xmlns=\'http://www.w3.org/2000/svg\'&gt;&lt;filter id=\'grayscale\'&gt;&lt;feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/&gt;&lt;/filter&gt;&lt;/svg&gt;#grayscale");*/ /* Firefox 10+, Firefox on Android */
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%) opacity(60%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */
}
.DevSt {
padding-left: 5px;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #DDDDDD;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.fileIcon1 {
background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb49Y2Sj9LT2f///yH5BAEAAAMALAAAAAAQABAAAAImnI+py+1vhJwyUYAzHTL4D3qdlJWaIFJqmKod607sDKIiDUP63hQAOw==);
height: 16px;
width: 16px;
cursor: pointer;
border: none;
float: left;
margin-top: 1px;
}
.fileIcon2 {
background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7);
height: 16px;
width: 16px;
cursor: pointer;
border: none;
float: left;
margin-top: 1px;
}
.fileIcon3 {
background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==);
height: 16px;
width: 16px;
cursor: pointer;
border: none;
float: left;
margin-top: 1px;
}
.fileIcon4 {
background: url(../images/meshicon16.png);
height: 16px;
width: 16px;
cursor: pointer;
border: none;
float: left;
margin-top: 1px;
}
.filelist {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
cursor: default;
-khtml-user-drag: element;
background-color: white;
clear: both;
}
</style>
</head>
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
<div id="container">
<div id="mastheadx"></div>
<div id="masthead" style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
<div style="width:calc(100% - 50px);overflow:hidden">
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
</div>
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
</div>
</div>
<img id="topMenuIcon" class="noselect" style="position:absolute;right:0;top:10px;bottom:50px;color:#c8c8c8;font-size:44px;margin-right:8px;cursor:pointer;display:none" onclick="topMenu()" src="/images/3bars-30.png" width="30" height="30">
</div>
<div id="page_content" style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%">
<div id="column_l" style="width:100%;padding:0;position:absolute;bottom:0px;top:0px">
<div id="p0" style="display:none;width:100%;height:100%">
<div style="display:flex;align-items:center;width:100%;height:100%">
<div id="p0message" style="text-align:center;width:100%"><span id="p0span">サーバーが切断されました</span>、 <href onclick="reload()" style="cursor:pointer"><u>クリックして再接続</u></href>。</div>
</div>
</div>
<div id="p1" style="display:none;width:100%;height:100%">
<div style="display:flex;align-items:center;width:100%;height:100%">
<div id="p1message" style="text-align:center;width:100%"></div>
</div>
</div>
<div id="p2" style="display:none">
<div id="xdevices"></div>
</div>
<div id="p3" style="display:none;position:absolute;bottom:0;top:0;width:100%">
<table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
<tbody><tr style="padding:0">
<td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
<div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
<div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
</div>
<div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
</td>
<td>
<img src="/images/user-50.png" width="50" height="50">
</td>
<td>
<div style="margin-left:5px">
<strong style="font-size:large"><span id="p3userName"></span></strong><br>
</div>
</td>
</tr>
</tbody></table>
<div id="p3info" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
<div style="margin-left:8px">
<div id="p3AccountActions">
<p><strong>アカウントのセキュリティ</strong></p>
<div style="margin-left:9px;margin-bottom:8px">
<div id="manageAuthApp" style="margin-top:5px;display:none"><a onclick="account_manageAuthApp()" style="cursor:pointer">認証アプリを管理する</a></div>
<div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">バックアップコードを管理する</a></div>
</div>
<p><strong>アカウントアクション</strong></p>
<div style="margin-left:9px;margin-bottom:8px">
<div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Eメールを確認します</a></span></div>
<div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">メールアドレスを変更する</a></span></div>
<div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">パスワードを変更する</a><span id="p2nextPasswordUpdateTime"></span></div>
<div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">アカウントを削除する</a></div>
</div>
<br style="clear:both">
</div>
<strong>デバイスグループ</strong>
<span id="p3createMeshLink1"> <a onclick="account_createMesh()" style="cursor:pointer"><img src="images/icon-addnew.png" width="12" height="12" border="0"> 新しい</a> </span>
<br><br>
<div id="p3meshes"></div>
<div id="p3noMeshFound" style="margin-left:9px;display:none">デバイスグループはありません。<span id="p3createMeshLink2"> <a onclick="account_createMesh()" style="cursor:pointer"><strong>ここから始めましょう!</strong></a></span></div>
<br style="clear:both">
</div>
</div>
</div>
<div id="p5" style="display:none">
<table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
<tbody><tr style="padding:0">
<td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
<div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
<div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
</div>
<div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
</td>
<td>
<img src="/images/user-50.png" width="50" height="50">
</td>
<td>
<div style="margin-left:5px">
<strong style="font-size:large">私のファイル</strong><br>
</div>
</td>
</tr>
</tbody></table>
<div id="p5myfiles" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
<table id="p5toolbar" style="width:100%;height:78px" cellpadding="0" cellspacing="0">
<tbody><tr>
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom">
<div style="width:100%;text-align:center">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5FolderUp" disabled="disabled" onclick="p5folderup()" value="アップ">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5SelectAllButton" disabled="disabled" onclick="p5selectallfile()" value="すべて選択" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5RenameFileButton" disabled="disabled" value="リネーム" onclick="p5renamefile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5DeleteFileButton" disabled="disabled" value="削除する" onclick="p5deletefile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5NewFolderButton" disabled="disabled" value="フォルダ" onclick="p5createfolder()" onkeypress="return false" onkeydown="return false">
</div>
<div style="width:100%;text-align:center">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5UploadButton" disabled="disabled" value="アップロードする" onclick="p5uploadFile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5CutButton" disabled="disabled" value="カット" onclick="p5copyFile(1)" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5CopyButton" disabled="disabled" value="コピー" onclick="p5copyFile(0)" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5PasteButton" disabled="disabled" value="ペースト" onclick="p5pasteFile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p5RefreshButton" value="リフレッシュ" onclick="p5refreshFiles()" onkeypress="return false" onkeydown="return false">
</div>
</td>
</tr>
<tr>
<td style="background-color:#E4E9E7;height:28px">
<table style="width:100%">
<tbody><tr>
<td id="p5currentpath" style="overflow:hidden;padding-left:4px;padding-top:2px"></td>
<td style="text-align:right;padding-right:4px">
<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>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
<div id="p5filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
<!--
<div id="p5bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
<div id="p5bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
-->
<span id="p5files"></span>
</div>
<table id="p5toolbarBottom" style="width:100%;height:22px;position:absolute;bottom:0px;background-color:#D3D9D6" cellpadding="0" cellspacing="0">
<tbody><tr>
<td style="text-align:left;padding:3px">&nbsp;<span id="p5bottomstatus"></span></td>
<td id="p5rightOfButtons" style="text-align:right;padding:3px"></td>
</tr>
</tbody></table>
</div>
</div>
<div id="p10" style="display:none;position:absolute;bottom:0;top:0;width:100%;overflow:hidden">
<table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;position:absolute;top:0">
<tbody><tr style="padding:0">
<td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
<div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
<div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
</div>
<div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
</td>
<td>
<a id="MainComputerImage" style="cursor:pointer" onclick="p10showiconselector()"></a>
</td>
<td>
<div style="margin-left:5px">
<strong><span id="p10deviceName"></span></strong><br>
<span id="MainComputerState"></span>
</div>
</td>
</tr>
</tbody></table>
<div id="p10general" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
<div id="p10html" style="margin-left:8px;margin-right:8px"></div>
<div id="p10html2"></div>
<div id="p10html3"></div>
</div>
<div id="p10desktop" style="overflow:hidden;position:absolute;top:55px;bottom:0px;width:100%;display:none">
<div id="deskarea1" style="position:absolute;top:0px;width:100%;height:25px">
<div style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<div style="float:right;text-align:right">
<span id="p14power"></span>&nbsp;
<input id="DeskSoftInput" type="text" style="width:25px;display:none;opacity:.2" onblur="toggleSoftKeys(0)" onkeypress="return ondeskkeypress(event)" onkeydown="return ondeskkeydown(event)" onkeyup="return ondeskkeyup(event)">
</div>
<div style="margin-left:3px">
<input type="button" id="connectbutton1" value="つなぐ" onclick="connectDesktop(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled">
<input type="button" id="connectbutton1h" value="HW Connect" onclick="connectDesktop(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled">
<input type="button" id="disconnectbutton1" value="切断する" onclick="connectDesktop(event,0)" onkeypress="return false" onkeydown="return false">
<span id="deskstatus">切断されました</span>
</div>
</div>
</div>
<div id="deskarea3" style="position:absolute;top:25px;width:100%;height:calc(100% - 50px)">
<div id="deskarea3x" style="background:black;text-align:center;height:100%;position:relative">
<div id="DeskParent" style="height:100%">
<canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onmousewheel="dmousewheel(event)"></canvas>
</div>
<div id="DeskTools" style="position:absolute;width:400px;height:100%;background-color:gray;top:0;right:0;border-left:2px solid lightgray;display:none">
<a id="DeskToolsRefreshButton" style="float:right;padding:3px;cursor:pointer" onclick="refreshDeskTools()">リフレッシュ</a>
<div id="DeskToolsBar" style="position:absolute;padding:3px;border-radius: 3px 3px 0px 0px;top:5px;left:4px;bottom:26px;background-color:lightgray;cursor:pointer">プロセス</div>
<div style="position:absolute;top:26px;left:4px;right:4px;bottom:4px;background-color:lightgray;text-align:left">
<div style="border-bottom:1px solid darkgray;padding:3px"><a style="width:50px;padding-right:5px;float:left;cursor:pointer" onclick="sortProcess(0)">PID</a><a style="cursor:pointer" onclick="sortProcess(1)">名</a></div>
<div id="DeskToolsProcesses" style="overflow-y:scroll;position:absolute;top:24px;bottom:0px;width:100%"></div>
</div>
</div>
</div>
</div>
<div id="deskarea4" style="position:absolute;bottom:0px;width:100%;height:25px">
<div style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<div style="float:right;text-align:right">
<select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onclick="deskGetDisplayNumbers(event)"></select>&nbsp;
<span id="DeskToastButton"><img src="images/icon-notify.png" onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span>&nbsp;
<!--<input id=DeskToolsButton type=button value=Tools onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">&nbsp;-->
</div>
<div>
<input id="deskActionsBtn" type="button" style="margin-left:3px" onkeypress="return false" onkeydown="return false" value="行動" onclick="deviceActionFunction()">
<input type="button" value="設定" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()">
<input type="button" onkeypress="return false" onkeydown="return false" value="電源アクション..." onclick="showPowerActionDlg()" style="display:none">
<input id="DeskSpecialKeys" type="button" value="特別なキー" onkeypress="return false" onkeydown="return false" onclick="sendSpecialKeys()">
<input id="DeskSoftKeys" type="button" value="キーボード" onkeypress="return false" onkeydown="return false" onclick="toggleSoftKeys(1)">
<label><span id="DeskControlSpan" style="display:none"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false">入力</span></label>
</div>
</div>
</div>
</div>
<div id="p10files" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%;display:none">
<table id="p13toolbar" style="width:100%;height:111px" cellpadding="0" cellspacing="0">
<tbody><tr>
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
<div style="float:right;text-align:right">
<input id="filesActionsBtn" type="button" onkeypress="return false" onkeydown="return false" value="行動" onclick="deviceActionFunction()" style="margin-right:2px">
</div>
<div style="margin-left:2px">
<input id="p13AutoConnect" value="自動接続" onclick="autoConnectFiles(event)" onkeypress="return false" onkeydown="return false" type="button" style="display:none">
<input id="p13Connect" value="つなぐ" onclick="connectFiles(event)" onkeypress="return false" onkeydown="return false" type="button">
<span id="p13Status">切断されました</span>
</div>
</td>
</tr>
<tr>
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom">
<div style="width:100%;text-align:center">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="アップ">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="すべて選択" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13RenameFileButton" disabled="disabled" value="リネーム" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13DeleteFileButton" disabled="disabled" value="削除する" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13NewFolderButton" disabled="disabled" value="フォルダ" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false">
</div>
<div style="width:100%;text-align:center">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13UploadButton" disabled="disabled" value="アップロードする" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13CutButton" disabled="disabled" value="カット" onclick="p13copyFile(1)" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13CopyButton" disabled="disabled" value="コピー" onclick="p13copyFile(0)" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13PasteButton" disabled="disabled" value="ペースト" onclick="p13pasteFile()" onkeypress="return false" onkeydown="return false">
<input type="button" style="width:calc(100%/5 - 5px)" id="p13RefreshButton" disabled="disabled" value="リフレッシュ" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false">
</div>
</td>
</tr>
<tr>
<td style="background-color:#E4E9E7;height:28px">
<table style="width:100%">
<tbody><tr>
<td id="p13currentpath" style="overflow:hidden;padding-left:4px;padding-top:2px"></td>
<td style="text-align:right;padding-right:4px">
<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>
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
<div id="p13filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
<!--
<div id="p13bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
<div id="p13bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
-->
<span id="p13files"></span>
</div>
<table id="p13toolbarBottom" style="width:100%;height:22px;position:absolute;bottom:0px" cellpadding="0" cellspacing="0">
<tbody><tr><td style="text-align:left;padding:3px;text-align:center;background-color:#D3D9D6">&nbsp;<span id="p13bottomstatus"></span></td></tr>
</tbody></table>
</div>
</div>
<div id="p20" style="display:none;position:absolute;bottom:0;top:0;width:100%">
<table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
<tbody><tr style="padding:0">
<td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
<div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
<div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
</div>
<div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
</td>
<td onclick="p20editmesh(1)">
<img src="/images/meshicon50.png" width="50" height="50">
</td>
<td onclick="p20editmesh(1)">
<div style="margin-left:5px">
<strong style="font-size:large"><span id="p20meshName"></span></strong><br>
</div>
</td>
</tr>
</tbody></table>
<div id="p20info" style="margin-left:8px;margin-right:8px"></div>
</div>
</div>
</div>
<div id="footer" style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
<table id="footerMenu" cellpadding="0" cellspacing="0" style="height:32px;width:100%;color:white;cursor:pointer;table-layout:fixed"></table>
</div>
</div>
<div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:90px;width:300px;display:none">
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
<div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>バツ</b></div>
<div id="id_dialogtitle" style="padding:5px"></div>
<div style="width:100%;margin:6px"></div>
</div>
<div style="margin-right:16px;margin-left:8px">
<div id="dialog1" style="margin:auto;text-align:center;margin:3px">
<div id="id_dialogMessage" style="padding:10px"></div>
</div>
<div id="dialog2" style="margin:auto;margin:3px">
<div id="id_dialogOptions"></div>
</div>
<div id="dialog3" style="margin:auto;margin:3px">
<select id="deskkeys" style="width:100%">
<option value="10">Ctrl + Alt + Del</option>
<option value="11">タブ</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>
</select>
</div>
<div id="dialog7" style="margin:auto;margin:3px">
<div id="d7meshkvm">
<h4 style="width:100%;border-bottom:1px solid gray">エージェントリモートデスクトップ</h4>
<div style="margin:3px 0 3px 0">
<select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
<div style="height:20px">品質</div>
</div>
<div style="margin:3px 0 3px 0">
<select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
<option selected="selected" value="1024">100</option>
<option value="896">87.5</option>
<option value="768">75</option>
<option value="640">62.5</option>
<option value="512">50</option>
<option value="384">37.5</option>
<option value="256">25</option>
<option value="128">12.5</option>
</select>
<div style="height:20px">スケーリング</div>
</div>
<div style="margin:3px 0 3px 0">
<select id="d7framelimiter" style="float:right;width:200px;height:20px" dir="rtl">
<option selected="selected" value="50">速い</option>
<option value="100">中</option>
<option value="400">スロー</option>
<option value="1000">非常に遅い</option>
</select>
<div style="height:20px">レート</div>
</div>
</div>
<div id="d7amtkvm">
<h4 style="width:100%;border-bottom:1px solid gray">インテル®AMTハードウェアKVM</h4>
<div style="height:26px">
<select id="d7desktopmode" style="float:right;width:200px">
<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 style="height:60px">
<div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
<label><input type="checkbox" id="d7showfocus">フォーカスツールを表示</label><br>
<label><input type="checkbox" id="d7showcursor">ローカルマウスカーソルを表示</label><br>
</div>
<div>その他</div>
</div>
</div>
</div>
</div>
<div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
<input id="idx_dlgCancelButton" type="button" value="キャンセル" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
<input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
</div>
</div>
<div id="topMenu" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:0px 0px 5px 5px;position:fixed;top:50px;right:5px;width:170px;display:none">
<div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick="topMenu(2)">私のファイル</div>
<div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick="topMenu(1)">マイアカウント</div>
<div id="logoutMenuOption"><a href="/logout"><div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer">ログアウト</div></a></div>
</div>
<iframe name="fileUploadFrame" style="display:none"></iframe>
<script>
'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 = parseUriArgs();
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 authCookieRenewTimer = null;
var meshserver = null;
var xdr = null;
var serverinfo = null;
var nodes = [];
var meshes = {};
var filetree = {};
var userinfo = null;
var serverinfo = null;
var users = null;
var nodeShortIdent = 0;
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
var debugmode = false;
var attemptWebRTC = ((features & 128) != 0);
var StatusStrs = ["切断されました", "接続しています...", "セットアップ...", "接続済み", "Intelreg;接続されたAMT"];
var files;
var passRequirements = '{{{passRequirements}}}';
if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
var sessionActivity = Date.now();
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; }
}
if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
window.onresize = center;
center();
QV('changeEmailId', (features & 0x200000) == 0);
QH('p1message', "接続しています...");
go(1);
// Connect to the mesh server
meshserver = MeshServerCreateControl(domainUrl, authCookie);
meshserver.onStateChanged = onStateChanged;
meshserver.onMessage = onMessage;
meshserver.Start();
// Load desktop settings
var t = localStorage.getItem('desktopsettings');
if (t != null) { desktopsettings = JSON.parse(t); }
applyDesktopSettings();
}
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
if (errorCode == 'noauth') { QH('p0span', "認証を実行できません"); return; }
if (prevState == 2) { setTimeout(serverPoll, 5000); } else { QH('p0span', "Webソケットに接続できません"); }
// Clean up here
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' });
meshserver.send({ action: 'files' });
if (xxcurrentView < 2) { go(2); }
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
}
QV('topMenuIcon', state == 2);
}
// Poll the server, if it responds, refresh the page.
function serverPoll() {
xdr = null;
try { xdr = new XDomainRequest(); } catch (e) { }
if (!xdr) xdr = new XMLHttpRequest();
xdr.open('HEAD', window.location.href);
xdr.timeout = 15000;
xdr.onload = function () { reload(); };
xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
xdr.send();
}
function updateSelf() {
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('manageAuthApp', features & 4096);
QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
// On the mobile app, don't allow group creation (for now).
QV('p3createMeshLink1', false);
QV('p3createMeshLink2', false);
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(); }
function checkIdleSessionTimeout() { var delta = (Date.now() - sessionActivity); if (delta > serverinfo.timeout) { window.location.href = 'logout'; } }
function onMessage(server, message) {
switch (message.action) {
case 'serverinfo': {
serverinfo = message.serverinfo;
if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
QV('p3AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
QV('logoutMenuOption', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide logout if in single user mode or domain authentication
break;
}
case 'authcookie': {
// Got an authentication cookie refresh
authCookie = message.cookie;
authRelayCookie = message.rcookie;
break;
}
case 'userinfo': {
userinfo = message.userinfo;
QH('p3userName', userinfo.name);
//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]; }
updateMeshes();
updateDevices();
break;
}
case 'files': {
filetree = setupBackPointers(message.filetree);
updateFiles();
//d3updatefiles();
break;
}
case 'nodes': {
nodes = [];
for (var m in message.nodes) {
for (var n in message.nodes[m]) {
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
if (message.nodes[m][n].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;
if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
message.nodes[m][n].ident = ++nodeShortIdent;
nodes.push(message.nodes[m][n]);
}
}
//onSortSelectChange();
//onSearchInputChanged();
updateDevices();
//refreshMap(false, true);
if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(2); } }
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
if (currentNode._id == message.nodeid) { drawDeviceTimeline(); }
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', "インストール<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 /><div style=width:100%;text-align:center><tt id=d2optsecret secret=\"' + message.secret + '\" style=font-size:15px>' + secret + '</tt><br /><br />Token: <input type=text onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></div>');
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 = colorgreen> 2段階ログインの有効化に成功</ b>。再度ログインするには、有効なトークンが必要になります。" : "<b style = colorred> 2段階ログインの有効化に失敗しました</ b>。アプリケーションから秘密をクリアして、再試行してください。適切なコードを入力するのに数分しかかかりません。");
break;
}
case 'otpauth-clear': {
if (xxdialogMode) return;
setDialogMode(2, "認証アプリ", 1, null, message.success ? "<b style = colorgreen> 2段階のログインアクティベーションが削除されました</ b>。この機能はいつでも再アクティブ化できます。" : "<b style = colorred> 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 style=width:100%;text-align:center>';
if (message.passwords) {
var j = 0;
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) + '&nbsp;' + p.substring(4); } else { x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + '&nbsp;' + 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 += '</div><br />';
setDialogMode(2, "バックアップコードの管理", 8, null, x, 'otpauth-manage');
break;
}
case 'event': {
/*
if (!message.event.nolog) {
events.unshift(message.event);
var eventLimit = parseInt(p3limitdropdown.value);
while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
events_update();
}
*/
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 webstate = JSON.parse(message.event.state);
for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
// Update the web page
if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) {
if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; }
updateDevices();
updateMeshes();
}
}
break;
}
case 'accountchange': {
// An account was created or changed
if (userinfo.name == message.event.account.name) {
var newsiteadmin = message.event.account.siteadmin ? message.event.account.siteadmin : 0;
var oldsiteadmin = userinfo.siteadmin ? userinfo.siteadmin : 0;
if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
userinfo = message.event.account;
if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
updateSelf();
}
break;
}
case 'createmesh': {
// A new mesh was created
if (message.event.links[userinfo._id] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
updateMeshes();
updateDevices();
meshserver.send({ action: 'files' });
}
break;
}
case 'meshchange': {
// Update mesh information
if (meshes[message.event.meshid] == null) {
// This is a new mesh for us
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
} else {
// This is an existing mesh
if (meshes[message.event.meshid].name != message.event.name) {
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(); } }
}
meshes[message.event.meshid].desc = message.event.desc;
meshes[message.event.meshid].links = message.event.links;
// Check if we lost rights to this mesh in this change.
if (meshes[message.event.meshid].links[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(2); }
}
}
updateMeshes();
updateDevices();
meshserver.send({ action: 'files' });
// If we are looking at a mesh that is now deleted, move back to "My Account"
if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { p20updateMesh(); }
break;
}
case 'deletemesh': {
// Delete the mesh
if (meshes[message.event.meshid]) {
delete meshes[message.event.meshid];
updateMeshes();
meshserver.send({ action: 'files' });
}
// Delete all nodes in that mesh
var newnodes = [];
for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
nodes = newnodes;
updateDevices();
// If we are looking at a mesh that is now deleted, move back to "My Account"
if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
// If we are looking at a node in the deleted mesh, move back to "My Devices"
if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(2); }
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;
nodes.push(node);
//onSortSelectChange();
//onSearchInputChanged();
updateDevices();
//updateMapMarkers();
break;
}
case 'removenode': {
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
if (currentNode == node) {
if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(2); }
currentNode = null;
// TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
}
nodes.splice(index, 1);
updateDevices();
//updateMapMarkers();
}
break;
}
case 'changenode': {
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
// Change the node
node.name = message.event.node.name;
node.rname = message.event.node.rname;
node.host = message.event.node.host;
node.desc = message.event.node.desc;
node.publicip = message.event.node.publicip;
node.iploc = message.event.node.iploc;
node.wifiloc = message.event.node.wifiloc;
node.gpsloc = message.event.node.gpsloc;
node.tags = message.event.node.tags;
node.userloc = message.event.node.userloc;
if (message.event.node.agent != null) {
if (node.agent == null) node.agent = {};
if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
node.agent.tag = message.event.node.agent.tag;
}
if (message.event.node.intelamt != null) {
if (node.intelamt == null) node.intelamt = {};
if (message.event.node.intelamt.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; }
}
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; }
//onSortSelectChange(true);
//drawNotifications();
refreshDevice(node._id);
//updateMapMarkers();
updateDevices();
//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(2); } currentNode = null; }
nodes.splice(index, 1);
} else {
// We see the new mesh, move this device
node.meshid = message.event.newMeshId;
node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
}
updateDevices();
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);
updateDevices();
}
break;
}
case 'nodeconnect': {
// Indicated a node has changed connectivity state
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
// Change the node connection state
node.conn = message.event.conn;
node.pwr = message.event.pwr;
updateDevices();
//updateMapMarkers();
//refreshDevice(node._id);
}
break;
}
case 'login': {
// Update the last login time
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = message.event.time; }
break;
}
case 'notify': {
//var n = { text: message.event.value };
//if (message.event.tag != null) { n.tag = message.event.tag; }
//addNotification(n);
break;
}
case 'stopped': { // Server is stopping.
// TODO: Disconnect
break;
}
default:
//console.log('Unknown message.event.action', message.event.action);
break;
}
break;
}
default:
//console.log('Unknown message.action', message.action);
break;
}
}
//
// Menu System
//
function topMenu(select) {
if ((xxdialogMode != null) && (xxdialogMode != 0) && (xxdialogMode != 999)) return;
if (select === undefined) {
var x = (QS('topMenu').display == 'none');
if (x == true) { if ((xxdialogMode == 0) || (xxdialogMode == null)) { QV('topMenu', true); xxdialogMode = 999; } } else { QV('topMenu', false); xxdialogMode = 0; }
} else {
QV('topMenu', false);
xxdialogMode = 0;
if ((select == 1) && (xxcurrentView != 3)) { goForward('account'); } // My Account
if ((select == 2) && (xxcurrentView != 5)) { goForward('files'); } // My Files
}
}
var backStack = [];
function goBack() { if (xxdialogMode) return; if (backStack.length > 0) { backStack.pop(); } goStack(); }
function goForward(id) { if (xxdialogMode) return; backStack.push(id); goStack(); }
function goStack() {
if (backStack.length == 0) { go(2); return; }
var id = backStack[backStack.length - 1], idtype = id.split('/')[0];
if (idtype == 'node') { setupDeviceMenu(0); gotoDevice(id); }
if (idtype == 'mesh') { gotoMesh(id); }
if (idtype == 'account') { go(3); }
if (idtype == 'devices') { go(2); }
if (idtype == 'files') { go(5); }
}
function updateFooterMenu(options) {
while (options != null && options.length < 3) { options.push({ n: '' }); }
var x = '', prev = '';
if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
QH('footerMenu', '<tr>' + x);
}
//
// MY ACCOUNT
//
function account_manageAuthApp() {
if (xxdialogMode || ((features & 4096) == 0)) return;
if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
}
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 || (userinfo.otpsecret != 1) || ((features & 4096) == 0)) return;
meshserver.send({ action: 'otpauth-getpasswords', subaction: action });
}
function account_showVerifyEmail() {
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
var x = "[OK]をクリックして確認メールを送信します:" + '<br /><div style=padding:8px><b>' + EscapeHtml(userinfo.email) + '</b></div>' + "確認を受けるまで数分お待ちください。";
setDialogMode(2, "メール確認", 3, account_showVerifyEmailEx, x);
}
function account_showVerifyEmailEx() {
meshserver.send({ action: 'verifyemail', email: userinfo.email });
}
function account_showChangeEmail() {
if (xxdialogMode) return;
var x = addHtmlValue("Eメール", '<input id=dp3email style=width:170px maxlength=256 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
setDialogMode(2, "メールアドレスの変更", 3, account_changeEmail, x);
if (userinfo.email != null) { Q('dp3email').value = userinfo.email; }
account_validateEmail();
Q('dp3email').focus();
}
function account_validateEmail(e, email) {
QE('idx_dlgOkButton', validateEmail(Q('dp3email').value) && (Q('dp3email').value != userinfo.email));
if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
}
function account_changeEmail() {
meshserver.send({ action: 'changeemail', email: Q('dp3email').value });
}
function account_showDeleteAccount() {
if (xxdialogMode) return;
var x = '<form method=post><table style=margin-left:10px><input type=hidden name=action value=deleteaccount /><input type=hidden name=authcookie value=' + authCookie + ' /><tr>';
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><div style=padding:10px;margin-bottom:4px>';
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 /></form>';
setDialogMode(2, "アカウントを削除する", 0, null, x);
account_validateDeleteAccount();
Q('apassword1').focus();
}
function account_showChangePassword() {
if (xxdialogMode) return false;
var x = '<table style=margin-left:10px>';
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>' + format("要件:{0}。", r.join(', ')) + '</span>'; }
}
x += '<br />';
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;
// Check if we are disallowed from creating a device group
if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "新しいデバイスグループ", 1, null, "このアカウントには、新しいデバイスグループを作成する権限がありません。"); return; }
// 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; }
// We are allowed, let's prompt to information
var x = addHtmlValue("名", '<input id=dp3meshname style=width:170px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
x += addHtmlValue("タイプ", '<div style=width:170px;margin:0;padding:0><select id=dp3meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>' + "ソフトウェアエージェントグループ" + '</option><option value=1>' + "Intelreg; AMTのみ" + '</option></select></div>');
x += addHtmlValue("説明", '<div style=width:170px;margin:0;padding:0><textarea id=dp3meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
setDialogMode(2, "デバイスグループを作成する", 3, account_createMeshEx, x);
account_validateMeshCreate();
Q('dp3meshname').focus();
}
function account_validateMeshCreate() {
QE('idx_dlgOkButton', Q('dp3meshname').value.length > 0);
}
function account_createMeshEx(button, tag) {
meshserver.send({ action: 'createmesh', meshname: Q('dp3meshname').value, meshtype: Q('dp3meshtype').value, desc: Q('dp3meshdesc').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>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>&#9679;<span>'; } else { r = '<span style=color:red>&#9679;<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 = '', count = 0;
for (i in meshes) {
count++;
// Mesh rights
var meshrights = meshes[i].links[userinfo._id].rights;
var rights = "部分的権利";
if (meshrights == 0xFFFFFFFF) rights = "完全な管理者"; else if (meshrights == 0) rights = "権利なし";
// Print the mesh information
r += '<div style=cursor:pointer onclick=goForward(\'' + i + '\')>';
r += '<div style="float:left;margin-left:4px"><img src="/images/meshicon50.png" width=50 height=50 /></div>';
r += '<div style="width:auto;height:40px;background-color:lightgray;margin-top:5px;margin-bottom:5px;margin-left:60px;padding-top:5px;padding-bottom:5px;border-radius:8px 0px 0px 8px">';
r += '<div><div style=padding-left:12px;padding-top:2px><b>' + EscapeHtml(meshes[i].name) + '</b></div><div style=padding-left:12px;padding-top:3px;color:gray>' + rights + '</div></div>';
r += '</div></div>';
}
QH('p3meshes', r);
QV('p3noMeshFound', count == 0);
}
function gotoMesh(meshid) {
currentMesh = meshes[meshid];
if (currentMesh == null) { goBack(); }
p20updateMesh();
go(20);
}
//
// MY FILES
//
var filetreelinkpath;
var filetreelocation = [];
function p5refreshFiles() { meshserver.send({ action: 'files' }); }
function updateFiles() {
QV('MainMenuMyFiles', ((features & 8) == 0));
if ((features & 8) != 0) return; // If running on a server without files, exit now.
var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p5folderup(0)>' + "ルート" + '</a>', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1;
// Navigate to path location, build the paths at the same time
var filetreelocation2 = [], oldlinkpath = filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
filetreelinkpath = '';
for (var i in filetreelocation) {
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) {
filetreelocation2.push(filetreelocation[i]);
fullPath += ' / ' + filetreelocation[i];
if ((folderdepth == 1)) {
var sp = filetreelocation[i].split('/');
publicPath = window.location + sp[0] + 'files/' + sp[2];
//if (filetreelocation[i] === userinfo._id) { filetreelinkpath += 'self'; } else { filetreelinkpath += (sp[0] + '/' + sp[2]); }
filetreelinkpath += filetreelocation[i];
} else {
if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
}
filetreex = filetreex.f[filetreelocation[i]];
displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null ? filetreex.n : filetreelocation[i]) + '</a>';
folderdepth++;
} else {
break;
}
}
filetreelocation = filetreelocation2; // In case we could not go down the full path, we set the new path location here.
var publicfolder = fullPath.toLowerCase().startsWith('root / ' + userinfo._id + ' / public');
// Sort the files
var filetreexx = p5sort_files(filetreex.f);
// Display all files and folders at this location
for (var i in filetreexx) {
// Figure out the name and shortname
var f = filetreexx[i], name = f.n, shortname;
shortname = name;
if (name.length > 40) { shortname = EscapeHtml(name.substring(0, 40)) + "..."; } else { shortname = EscapeHtml(name); }
name = EscapeHtml(name);
// Figure out the date
//var fdatestr = '';
//if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + '/' + (fdate.getDate()) + '/' + fdate.getFullYear() + ' ' + printTime(fdate) + '&nbsp;'; }
// 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) : '';
h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right;padding-right:4px>' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")>' + shortname + '</a></span></div>';
} else {
var link = shortname;
var publiclink = '';
if (publicfolder) { publiclink = ' (<a style=cursor:pointer onclick=\'p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "リンク" + '</a>)'; }
if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right;padding-right:4px>' + 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} b残り", bytes);
if (bytes < 2097152) return format("{0} k残り", Math.round(bytes / 1024));
if (bytes < 2147483648) return format("残り{0} m", Math.round(bytes / 1024 / 1024));
return format("{0} g残り", 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 '';
return getNiceSize(f.maxbytes - f.s) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' />';
}
function p5showPublicLink(u) { setDialogMode(2, "公開リンク", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
var sortorder;
function p5sort_filename(a, b) { if (a.ln > b.ln) return (1 * sortorder); if (a.ln < b.ln) return (-1 * sortorder); return 0; }
function p5sort_timestamp(a, b) { if (a.d > b.d) return (1 * sortorder); if (a.d < b.d) return (-1 * sortorder); return 0; }
function p5sort_bysize(a, b) { if (a.s == b.s) return p5sort_filename(a, b); return (((a.s - b.s)) * sortorder); }
function p5sort_files(files) {
var r = [], sortselection = Q('p5sortdropdown').value;
for (var i in files) { files[i].nx = i; if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
sortorder = 1;
if (sortselection > 3) { sortorder = -1; sortselection -= 3; }
if (sortselection == 1) { r.sort(p5sort_filename); }
else if (sortselection == 2) { r.sort(p5sort_bysize); }
else if (sortselection == 3) { r.sort(p5sort_timestamp); }
return r;
}
function p5setActions() {
var cc = getFileSelCount(), tc = getFileCount(), sfc = getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
QE('p5DeleteFileButton', (cc > 0) && (filetreelocation.length > 0));
QE('p5NewFolderButton', filetreelocation.length > 0);
QE('p5UploadButton', filetreelocation.length > 0);
QE('p5RenameFileButton', (cc == 1) && (filetreelocation.length > 0));
QE('p5SelectAllButton', tc > 0);
Q('p5SelectAllButton').value = (cc > 0 ? "なし" : "すべて");
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="updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 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) {
haltEvent(e);
QV('bigfail', false);
QV('bigok', false);
//QV('p5fileCatchAllInput', false);
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length;
for (var i = 0; i < e.dataTransfer.files.length; i++) {
var reader = new FileReader(), file = e.dataTransfer.files[i];
names.push(file.name);
sizes.push(file.size);
types.push(file.type);
reader.onload = function (event) {
datas.push(event.target.result);
if (--readercount == 0) {
Q('p5fileDragName').value = names.join('*');
Q('p5fileDragSize').value = sizes.join('*');
Q('p5fileDragType').value = types.join('*');
Q('p5fileDragData').value = datas.join('*');
Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
Q('p5loginSubmit2').click();
}
}
reader.readAsDataURL(file);
}
}
var p5dragtimer = null;
function p5fileDragOver(e) {
haltEvent(e);
if (p5dragtimer != null) { clearTimeout(p5dragtimer); p5dragtimer = null; }
var ac = true; // TODO: Set to true if we can accept the file
if (filetreelocation.length == 0) { ac = false; }
QV('bigok', ac);
QV('bigfail', !ac);
//QV('p5fileCatchAllInput', ac);
}
function p5fileDragLeave(e) {
haltEvent(e);
if (e.target.id != 'p5filetable') {
QV('bigfail', false);
QV('bigok', false);
//QV('p5fileCatchAllInput', false);
} else {
p5dragtimer = setTimeout('QV(\'bigfail\',false);QV(\'bigok\',false);p5dragtimer=null;', 200);
}
}
//
// MY DEVICES
//
function ondeskkeypress(e) {
toggleSoftKeys(0);
Q('DeskSoftInput').value = '';
setSessionActivity();
if (desktop && !xxdialogMode && xxcurrentView == 10) {
// 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);
}
}
function ondeskkeydown(e) {
toggleSoftKeys(0);
Q('DeskSoftInput').value = '';
setSessionActivity();
if (desktop && !xxdialogMode && xxcurrentView == 10) {
// 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);
}
}
function ondeskkeyup(e) {
toggleSoftKeys(0);
Q('DeskSoftInput').value = '';
setSessionActivity();
if (desktop && !xxdialogMode && xxcurrentView == 10) {
// 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);
}
}
// Since the update device call can be quite frequent, we can moderate it and only call it at most 5 times a second.
var updateDevicesTimer = null;
function updateDevices() { if (updateDevicesTimer != null) return; updateDevicesTimer = setTimeout(updateDevicesEx, 200); }
var sort = 0;
var deviceHeaderId = 0;
var deviceHeaderCount;
var deviceHeaders = {};
var showRealNames = false;
var deviceHeaderTotal = 0;
var deviceHeaders = {};
var deviceHeadersTitles = {};
function updateDevicesEx() {
if (updateDevicesTimer != null) { clearTimeout(updateDevicesTimer); updateDevicesTimer = null; }
var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, groups = {}, groupCount = {};
// 3 wide, list view or desktop view
deviceHeaderId = 0;
deviceHeaderCount = {};
deviceHeaderTotal = 0;
deviceHeaders = {};
deviceHeadersTitles = {};
var current;
// 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); } }
// Go thru the list of nodes and display them
for (var i in nodes) {
if (nodes[i].v == false) continue;
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links[userinfo._id];
if (meshlinks == null) continue;
var meshrights = meshlinks.rights;
if (sort == 0) {
// Mesh header
nodes.sort(meshSort);
if (nodes[i].meshid != current) {
deviceHeaderSet();
var extra = '';
if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span style=color:lightgray>' + "、Intelreg; AMTのみ" + '</span>'; }
if (current != null) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
r += '<div class=DevSt style=padding-top:4px><span style=float:right>';
//r += getMeshActions(mesh2, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' style=color:lightgray></span></div>';
current = nodes[i].meshid;
displayedMeshes[current] = 1;
c = 0;
}
} else if (sort == 1) {
// Power header
if (nodes[i].pwr !== current) {
deviceHeaderSet();
if (current !== null) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' style=color:lightgray></span></div>';
current = nodes[i].pwr;
c = 0;
}
} else if (sort == 2) {
// Device header
if (current == null) { current = '1'; }
}
count++;
var title = EscapeHtml(nodes[i].name);
if (title.length == 0) { title = '<i>' + "なし" + '</i>'; }
if ((nodes[i].rname != null) && (nodes[i].rname.length > 0)) { title += " /" + EscapeHtml(nodes[i].rname); }
var name = EscapeHtml(nodes[i].name);
if (showRealNames == true && nodes[i].rname != null) name = EscapeHtml(nodes[i].rname);
if (name.length == 0) { name = '<i>' + "なし" + '</i>'; }
// Node
var icon = nodes[i].icon, nodestate = NodeStateStr(nodes[i]);
if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
r += '<div style=cursor:pointer onclick=goForward(\'' + nodes[i]._id + '\')>';
r += '<div class="i' + icon + '" style="float:left;margin-left:4px"></div>';
r += '<div style="width:auto;height:40px;background-color:lightgray;margin-top:5px;margin-bottom:5px;margin-left:60px;padding-top:5px;padding-bottom:5px;border-radius:8px 0px 0px 8px">';
r += '<div><div style=padding-left:12px;padding-top:2px><b>' + name + '</b></div><div style=padding-left:12px;padding-top:3px;color:gray>' + nodestate + '</div></div>';
r += '</div></div>';
// If we are displaying devices by group, put the device in the right group.
/*
if ((sort == 3) && (r != '')) {
if (nodes[i].tags) {
for (var j in nodes[i].tags) {
var tag = nodes[i].tags[j];
if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
if (view == 3) break;
}
}
r = '';
}
*/
deviceHeaderTotal++;
if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
}
// Display all empty meshes, we need to do this because users can add devices to these at any time.
if (sort == 0) {
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 += '<div><div colspan=3 class=DevSt><span style=float:right>';
//r += getMeshActions(mesh, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></div>';
if (mesh.mtype == 1) { r += '<div style=padding:10px><i>' + "Intelreg;なしこのグループのAMTデバイス"; }
if (mesh.mtype == 2) { r += '<div style=padding:10px><i>' + "このグループにデバイスはありません"; }
r += '.</i></div></div>';
current = mesh._id;
count++;
}
}
}
}
if (count == 0) {
QH('xdevices', '<div style="margin-top:50px;text-align:center"><span style="font-size:30px">' + "デバイスなし" + '</span><br /><br />' + "このWebサイトのデスクトップバージョンを使用して、デバイスを追加します。" + '</div>');
} else {
QH('xdevices', r);
}
deviceHeaderSet();
for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
}
var powerStatetable = ['', "パワード", "睡眠", "睡眠", "睡眠", "冬眠", "電源を切る", "プレゼント"];
var powerStateStrings = ['', "パワード", "睡眠", "睡眠", "深い眠り", "冬眠", "ソフトオフ", "プレゼント"];
var powerStateStrings2 = ['', "デバイスに電源が入っています", "デバイスはスリープ状態ですS1", "デバイスはスリープ状態ですS2", "デバイスはディープスリープ状態ですS3", "デバイスは休止状態ですS4", "デバイスはソフトオフ状態ですS5", "デバイスは存在しますが、電源状態を判別できません"];
var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
function NodeStateStr(node) {
var states = [];
if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
if (node.conn) {
if ((node.conn & 1) != 0) { states.push('<span>' + "エージェント" + '</span>'); }
if ((node.conn & 2) != 0) { states.push('<span>' + "CIRA" + '</span>'); }
else if ((node.conn & 4) != 0) { states.push('<span>' + "Intelreg; AMT" + '</span>'); }
if ((node.conn & 8) != 0) { states.push('<span>' + "リレー" + '</span>'); }
if ((node.conn & 16) != 0) { states.push('<span>' + "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 onSortSelectChange(skipsave) {
sort = document.getElementById('sortselect').selectedIndex;
if (!skipsave) { putstore('sort', sort); }
updateDevicesEx();
}
function deviceHeaderSet() {
if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
deviceHeaders['DevxHeader' + deviceHeaderId] = ', ' + deviceHeaderTotal + ((deviceHeaderTotal == 1) ? " ノード" : " ノード");
var title = '';
for (var x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
deviceHeadersTitles['DevxHeader' + deviceHeaderId] = title;
deviceHeaderId++;
deviceHeaderCount = {};
deviceHeaderTotal = 0;
}
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) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } if (ap > bp) return 1; if (ap < bp) return -1; return 0; }
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; }
//
// 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 currentDevicePanel = 0;
var currentNode;
var powerTimelineNode = null;
var powerTimelineReq = null;
var powerTimelineUpdate = null;
var powerTimeline = null;
function getCurrentNode() { return currentNode; };
function gotoDevice(nodeid, panel, refresh) {
// 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; }
var node = getNodeFromId(nodeid);
if (node == null) { goBack(); return; }
var mesh = meshes[node.meshid];
if (mesh == null) { goBack(); return; }
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) { nname = '<span onclick=showEditNodeValueDialog(0) style=cursor:pointer>' + nname + '</span>'; }
QH('p10deviceName', nname);
// Node attributes
var x = '<table style=width:100%>';
// Attribute: Mesh
x += addDeviceAttribute('<span>' + "グループ" + '</span>', '<a onclick=goForward("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
// Attribute: Name
if (node.rname != null) { x += addDeviceAttribute('<span>' + "名" + '</span>', '<span>' + EscapeHtml(node.rname) + '</span>'); }
// Attribute: Host
if ((mesh.mtype == 1) || (node.name != node.host)) {
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 + '</span>');
} else {
x += addDeviceAttribute("説明", description);
}
// Attribute: Mesh Agent
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"];
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>' + nobreak("不明な状態") + '</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.flags) { if (node.intelamt.flags & 2) { str = ' <span>' + "CCM" + '</span>'; } else if (node.intelamt.flags & 4) { str = ' <span>' + "ACM" + '</span>'; } }
str += (', v' + node.intelamt.ver);
}
if (node.intelamt.tls == 1) { str += ', <span>' + "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 onclick=editDeviceAmtSettings("' + node._id + '")>' + nobreak("資格情報なし") + '</i>';
} else {
str += ', <i style=color:#FF0000>' + "資格情報なし" + '</i>';
}
}
str += ' ';
if ((meshrights & 4) != 0) {
str += '<img src=images/link4.png height=10 width=10 style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
}
}
var meName = "Intelreg;私";
if (typeof node.intelamt.sku == 'number') {
if ((node.intelamt.sku & 8) != 0) { meName = "Intelreg; AMT"; }
else if ((node.intelamt.sku & 16) != 0) { meName = "Intelreg; SM"; }
}
x += addDeviceAttribute(meName, str);
}
// Attribute: Mesh Agent Tag
if ((node.agent != null) && (node.agent.tag != null) && (node.agent.tag != 'mailto:')) {
var tag = EscapeHtml(node.agent.tag);
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
x += addDeviceAttribute("エージェントタグ", tag);
}
// Attribute: Intel AMT
//if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
// Attribute: Connectivity (Only show this if more than just the agent is connected).
var connectivity = node.conn;
if (connectivity && connectivity > 1) {
var cstate = [];
if ((node.conn & 1) != 0) cstate.push('<span>' + "エージェント" + '</span>');
if ((node.conn & 2) != 0) cstate.push('<span>' + "Intelreg; AMT CIRA" + '</span>');
else if ((node.conn & 4) != 0) cstate.push('<span>' + "Intelreg; AMT" + '</span>');
if ((node.conn & 8) != 0) cstate.push('<span>' + "エージェントリレー" + '</span>');
if ((node.conn & 16) != 0) cstate.push('<span>' + "MQTT" + '</span>');
x += addDeviceAttribute("接続性", cstate.join(', '));
}
// Node tags
var groupingTags = '<i>' + "なし" + '</i>';
if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span style="background-color:lightgray;padding:3px;margin-right:4px;border-radius:5px">' + node.tags[i] + '</span>'; } }
if ((meshrights & 4) != 0) {
x += addDeviceAttribute("タグ", '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + '</span>');
} else {
x += addDeviceAttribute("タグ", 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=Actions onclick=deviceActionFunction() />'; }
//x += '<input type=button value=Notes onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast onclick=deviceToastFunction() />'; }
QH('p10html', x);
// Show node last 7 days timeline
//drawDeviceTimeline();
setupFiles();
// Show bottom buttons
x = '<div style=float:right;font-size:x-small;margin-right:10px>';
if ((meshrights & 4) != 0) x += '<a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '")>' + "デバイスを削除" + '</a>';
x += '</div><div style=font-size:x-small>';
//if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '")>Interfaces</a>&nbsp;';
//if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '")>Location</a>&nbsp;';
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 += ', '; } powerstate += '<span style=font-size:10px>' + "メッシュエージェント" + '</span>'; }
if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intelreg;接続されたAMT" + '</span>'; }
else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intelreg; AMTが検出されました" + '</span>'; }
if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px>' + "MQTTチャネルが接続されました" + '</span>'; }
QH('MainComputerState', powerstate);
// Set the node icon
QH('MainComputerImage', '<div class="i' + node.icon + '"></div>');
// Request the power timeline
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { QH('p10html2', ''); powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
}
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);
// Update the footer menu
setupDeviceMenu();
}
function deviceToastFunction() {
if (xxdialogMode) return;
setDialogMode(2, "デバイストースト", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
}
function deviceToastFunctionEx() {
meshserver.send({ action: 'toast', nodeids: [currentNode._id], title: 'MeshCentral', msg: Q('d2devToast').value });
}
function setupDeviceMenu(op, obj) {
var meshrights = 0;
if (currentNode) { meshrights = meshes[currentNode.meshid].links[userinfo._id].rights; }
if (op != null) { currentDevicePanel = op; }
QV('p10general', currentDevicePanel == 0);
QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
QV('p10files', currentDevicePanel == 2);
var menus = [];
if (currentDevicePanel != 0) { menus.push({ n: 'General', f: 'setupDeviceMenu(0)' }); }
if ((currentDevicePanel != 1) &&
(currentNode != null) &&
((meshrights & 8) || (meshrights & 256)) &&
(((meshes[currentNode.meshid].mtype == 1) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 1)))
) { menus.push({ n: 'Desktop', f: 'setupDeviceMenu(1)' }); }
if ((currentDevicePanel != 2) && (currentNode != null) && (meshrights & 8) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0)) && ((currentNode.mtype == 2) && (currentNode.agent.caps & 4))) { menus.push({ n: 'Files', f: 'setupDeviceMenu(2)' }); }
updateFooterMenu(menus);
}
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:170px>';
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
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 {
// Power operation
meshserver.send({ action: 'poweraction', nodeids: [currentNode._id], actiontype: op });
}
}
// Look to see if we need to update the device timeline
function updateDeviceTimeline() {
if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) { powerTimelineUpdate = null; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
}
// Draw device power bars. The bars are 766px wide.
function drawDeviceTimeline() {
var timeline = null, now = Date.now();
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
// Calculate when the timeline starts
var d = new Date();
d.setHours(0, 0, 0, 0);
d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
var timelineStart = d.getTime();
// De-compact the timeline
var timeline2 = [];
if (timeline != null && timeline.length > 1) {
timeline2.push([0, timeline[1], timeline[0]]); // Start, End, Power
var ct = timeline[1];
for (var i = 2; i < timeline.length; i += 2) {
var power = timeline[i], dt = now;
if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
timeline2.push([ct, ct + dt, power]); // Start, End, Power
ct = ct + dt;
}
}
// Draw the timeline
var x = '', count = 1, date = new Date();
var totalWidth = Q('masthead').offsetWidth - (90 + 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) { datavalue += '<div style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>'; }
}
}
x += '<tr style=' + (((count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><div>&nbsp;' + 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 style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse;width:calc(100% - 18px);margin:9px" border=0 cellpadding=2 cellspacing=0><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:center;width:90px>Day</th><th scope=col style=text-align:center>Power State</th></tr>' + x + '</tbody></table>');
}
// Return a color for the given power state
function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'yellow'; }
// Return true if the time block is visible within the start/end period
function isTimeBlockInside(start, end, blockStart, blockEnd) {
if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
if ((blockStart > start) && (blockStart < end)) return true;
if ((blockEnd > start) && (blockEnd < end)) return true;
return false;
}
function addDeviceAttribute(name, value) {
return '<tr><td style=width:100px;color:gray>' + name + '</td><td style=overflow:hidden>' + value + '</td></tr>';
}
function editDeviceAmtSettings(nodeid, func) {
if (xxdialogMode) return;
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
if ((meshrights & 4) == 0) return;
x += addHtmlValue("ユーザー名", '<input id=dp10username style=width:170px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
x += addHtmlValue("パスワード", '<input id=dp10password type=password style=width:170px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
x += addHtmlValue("セキュリティ", '<select id=dp10tls style=width:176px><option value=0>' + "TLSセキュリティなし" + '</option><option value=1>' + "TLSセキュリティが必要" + '</option></select>');
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
setDialogMode(2, "Intelを編集reg; AMTクレデンシャル", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
Q('dp10tls').value = node.intelamt.tls;
validateDeviceAmtSettings();
}
function validateDeviceAmtSettings() {
QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
}
function editDeviceAmtSettingsEx(button, tag) {
if (button == 2) {
// Delete button pressed, remove credentials
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
} else {
// Change Intel AMT credentials
var amtuser = Q('dp10username').value;
if (amtuser == '') amtuser = 'admin';
var amtpass = Q('dp10password').value;
if (amtpass == '') amtuser = '';
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
tag.node.intelamt.user = amtuser;
tag.node.intelamt.tls = Q('dp10tls').value;
if (tag.func) { setTimeout(tag.func, 300); }
}
}
function p10showDeleteNodeDialog(nodeid) {
if (xxdialogMode) return;
setDialogMode(2, "ノードを削除", 3, p10showDeleteNodeDialogEx, format("{0}を削除しますか?", EscapeHtml(currentNode.name)) + '<br /><br /><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "確認する", nodeid);
p10validateDeleteNodeDialog();
}
function p10validateDeleteNodeDialog() {
QE('idx_dlgOkButton', Q('p10check').checked);
}
function p10showDeleteNodeDialogEx(buttons, nodeid) {
meshserver.send({ action: 'removedevices', nodeids: [nodeid] });
}
function p10showiconselector() {
if (xxdialogMode) return;
var mesh = meshes[currentNode.meshid];
var meshrights = mesh.links[userinfo._id].rights;
if ((meshrights & 4) == 0) return;
var x = '<table align=center><td>';
x += '<div style=display:inline-block class=i1 onclick=p10setIcon(1)></div>';
x += '<div style=display:inline-block class=i2 onclick=p10setIcon(2)></div>';
x += '<div style=display:inline-block class=i3 onclick=p10setIcon(3)></div><br>';
x += '<div style=display:inline-block class=i4 onclick=p10setIcon(4)></div>';
x += '<div style=display:inline-block class=i5 onclick=p10setIcon(5)></div>';
x += '<div style=display:inline-block class=i6 onclick=p10setIcon(6)></div></table>';
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 = ['', '', '', "Group1、Group2、Group3"];
function showEditNodeValueDialog(mode) {
if (xxdialogMode) return;
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:170px maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
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 desktop;
var desktopNode;
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50 };
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)) {
// Device is not already connected, just setup a blank canvas
QH('DeskParent', '<canvas id=Desk width=640 height=200 style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
desktopNode = currentNode;
// Setup the mouse wheel
Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
}
desktopNode = currentNode;
updateDesktopButtons();
// On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
}
// Show and enable the right buttons
function updateDesktopButtons() {
var mesh = meshes[currentNode.meshid];
var deskState = 0;
if (desktop != null) { deskState = desktop.State; }
var meshrights = mesh.links[userinfo._id].rights;
// Show the right buttons
QV('disconnectbutton1', (deskState != 0));
QV('connectbutton1', (deskState == 0) && (mesh.mtype == 2) && ((meshrights & 8) || (meshrights & 256)));
QV('connectbutton1h',
(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', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
// Enable buttons
var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
QE('connectbutton1', online);
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton1h', hwonline);
//QE('deskSaveBtn', deskState == 3);
//QV('DeskCAD', meshrights & 8);
//QE('DeskCAD', deskState == 3);
//QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
//QE('DeskWD', deskState == 3);
//QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
//QE('deskkeys', deskState == 3);
//QE('DeskToolsButton', online);
QV('DeskToastButton', ((meshrights & 16384) != 0) && (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
//QE('DeskToastButton', online);
QV('deskActionsBtn', meshrights & 8);
Q('DeskControl').checked = ((meshrights & 8) != 0);
if (online == false) QV('DeskTools', false);
}
function connectDesktop(e, contype) {
setSessionActivity();
if (desktop == null) {
desktopNode = currentNode;
if (contype == 2) {
// Setup the Intel AMT remote desktop
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), 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.showmouse = desktopsettings.showmouse;
desktop.m.onScreenSizeChange = deskAdjust;
desktop.Start(desktopNode._id, 16994, '*', '*', 0);
desktop.contype = 2;
} else {
// Setup the Mesh Agent remote desktop
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
desktop.debugmode = debugmode;
desktop.m.debugmode = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
desktop.onStateChanged = onDesktopStateChange;
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
desktop.m.ScalingLevel = desktopsettings.scaling;
desktop.m.FrameRateTimer = desktopsettings.framerate;
desktop.m.onDisplayinfo = deskDisplayInfo;
desktop.m.onScreenSizeChange = deskAdjust;
desktop.Start(desktopNode._id);
desktop.contype = 1;
}
} else {
// Disconnect and clean up the remote desktop
desktop.Stop();
desktopNode = desktop = null;
}
}
function onDesktopStateChange(xdesktop, state) {
var xstate = state;
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
var str = StatusStrs[xstate];
if ((desktop != null) && (desktop.webRtcActive == true)) { str += "、WebRTC"; }
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
QH('deskstatus', str);
switch (state) {
case 0:
// Disconnect and clean up the remote desktop
desktop.Stop();
desktopNode = desktop = null;
QV('termdisplays', false);
if (fullscreen == true) { deskToggleFull(); }
break;
case 2:
break;
default:
//console.log('Unknown onDesktopStateChange state', state);
break;
}
updateDesktopButtons();
deskAdjust();
setTimeout(deskAdjust, 50);
}
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;
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 (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
}
}
}
function applyDesktopSettings() {
var r = '', ops = (features & 512) ? [90, 70, 50, 40, 30, 20, 10, 5, 1] : [50, 40, 30, 20, 10, 5, 1];
for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
QH('d7bitmapquality', r);
d7desktopmode.value = desktopsettings.encoding;
d7showfocus.checked = desktopsettings.showfocus;
d7showcursor.checked = desktopsettings.showmouse;
d7bitmapquality.value = 40; // Default value
if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
d7bitmapscaling.value = desktopsettings.scaling;
if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
}
var fullscreen = false;
/*
function deskToggleFull() {
fullscreen = !fullscreen;
QV('mastheadx', !fullscreen);
QV('masthead', !fullscreen);
QV('topbar', !fullscreen);
QV('p11deviceNameHeader', !fullscreen);
QV('footer', !fullscreen);
QV('column_l_bottomgap', !fullscreen);
QV('idx_deskFullBtn2', fullscreen);
QV('deskFullBtn', !fullscreen);
if (fullscreen) {
QS('container').width = '100%';
QS('container')['border-right'] = '0';
QS('container')['border-left'] = '0';
QS('column_l').padding = '0';
QS('column_l').width = '100%';
} else {
QS('container').width = '960px';
QS('container')['border-right'] = '1px solid #b7b7b7';
QS('container')['border-left'] = '1px solid #b7b7b7';
QS('column_l').padding = '0 15px';
QS('column_l').width = '930px';
toggleFullScreen();
}
deskAdjust();
}
*/
function deskAdjust() {
var x = (Q('DeskParent').clientHeight - Q('Desk').clientHeight) / 2;
if (x < 0) {
var mh = Q('DeskParent').clientHeight, mw = 9999;
if (desktop) { mw = (desktop.m.width / desktop.m.height) * mh; }
QS('Desk')['max-height'] = mh + 'px';
QS('Desk')['max-width'] = mw + 'px';
x = 0;
} else {
QS('Desk')['max-height'] = null;
QS('Desk')['max-width'] = null;
}
QS('Desk')['margin-top'] = x + 'px';
QS('Desk')['margin-bottom'] = x + 'px';
}
// 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) { // TAB
if (desktop.contype == 2) {
desktop.m.sendkey([[0xff09, 1], [0xff09, 0]]); // Intel AMT: 'TAB' press, 'TAB' release
} else {
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9]]); // MeshAgent: 'TAB' press, 'TAB' release
}
}
}
function sendSpecialKeys() {
if (xxdialogMode || desktop == null || desktop.State != 3) return;
setDialogMode(3, "特別なキー", 3, deskSendKeys);
}
// Send CTRL-ALT-DEL
/*
function sendCAD() {
if (xxdialogMode || desktop == null || desktop.State != 3) return;
desktop.m.sendcad();
}
*/
// Toggle soft keyboard
function toggleSoftKeys(x) {
QV('DeskSoftInput', x == 1);
if (x == 1) { Q('DeskSoftInput').focus(); }
}
// Show process dialogs
function toggleDeskTools() {
setSessionActivity();
if (xxdialogMode) return;
if (QS('DeskTools').display == 'none') {
QV('DeskTools', true);
Q('DeskTools').nodeid = currentNode._id;
refreshDeskTools();
} else {
QV('DeskTools', false);
}
}
// Refresh all of the desktop tool panels
function refreshDeskTools() {
setSessionActivity();
QV('DeskToolsRefreshButton', false);
setTimeout(refreshDeskToolsEx, 500);
meshserver.send({ action: 'msg', type: 'ps', nodeid: currentNode._id });
}
function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
var deskTools = { sort: 1, msg: null };
function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return 0; }
function sortProcessName(a, b) { if (a.d > b.d) return 1; if (a.d < b.d) return (-1); return 0; }
function showDeskToolsProcesses(message) {
deskTools.msg = message;
if (message == null) { QH('DeskToolsProcesses', ''); return; }
if (Q('DeskTools').nodeid != message.nodeid) return;
var p = [], processes = null;
try { processes = JSON.parse(message.value); } catch (e) { }
console.log(processes);
if (processes != null) {
for (var pid in processes) { p.push({ p: parseInt(pid), c: processes[pid].cmd, d: processes[pid].cmd.toLowerCase(), u: processes[pid].user }); }
if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
var x = '';
for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u ? p[i].u : '') + '</div><div>' + p[i].c + '</div></div>'; } }
QH('DeskToolsProcesses', x);
}
}
// Save the desktop image to file
function deskSaveImage() {
setSessionActivity();
if (xxdialogMode || desktop == null || desktop.State != 3) return;
var d = new Date(), n = 'Desktop-' + currentNode.name + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + "-" + ("0" + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
Q('Desk')['toBlob'](function (blob) { saveAs(blob, n + '.jpg'); });
}
function deskDisplayInfo(sender, info, selDisplay, selItem) {
var txt = Q('termdisplays').value;
if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x]) ? ' selected' : '') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
QV('termdisplays', info.length > 0);
}
function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
function deskSetDisplay(e) {
setSessionActivity();
var display = 0, txt = Q('termdisplays').value;
if (txt == "すべてのディスプレイ") display = 65535; else display = parseInt(txt.substring(8));
desktop.m.SetDisplay(display);
}
function dmousedown(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mousedown(e) }
function dmouseup(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mouseup(e) }
function dmousemove(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mousemove(e) }
function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && 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); }
//
// 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) {
setSessionActivity();
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);
p13setActions();
if (files != null) { files.Stop(); files = null; }
break;
case 3:
p13targetpath = '';
files.sendText({ action: 'ls', reqid: 1, path: '' });
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) {
if (!files) {
// Setup a mesh agent files
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
files.attemptWebRTC = attemptWebRTC;
files.onStateChanged = onFilesStateChange;
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) {
setSessionActivity();
//console.log('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 style=cursor:pointer onclick=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 style=cursor:pointer onclick=p13folderup(' + (parseInt(i) + 1) + ')>' + p13filetreelocation[i] + '</a>' } // Setup the path we display
var newlinkpath = p13filetreelocation.join('/');
// Sort the files
var filetreexx = p13sort_files(p13filetree.dir);
// Display all files and folders at this location
for (var i in filetreexx) {
// Figure out the name and shortname
var f = filetreexx[i], name = f.n, shortname;
shortname = name;
if (name.length > 70) { shortname = EscapeHtml(name.substring(0, 70)) + "..."; } 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 right = '';
h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right>' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p13folderset(\"' + encodeURIComponent(f.nx) + '\")>' + shortname + '</a></span></div>';
} else {
var link = shortname;
if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\"p13downloadfile(\'' + encodeURIComponent(newlinkpath + '/' + name) + '\',\'' + encodeURIComponent(name) + '\',' + f.s + ')\">' + shortname + '</a>'; }
h = '<div class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right;padding-right:4px>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
}
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 });
}
var p13sortorder;
function p13sort_filename(a, b) { if (a.ln > b.ln) return (1 * p13sortorder); if (a.ln < b.ln) return (-1 * p13sortorder); return 0; }
function p13sort_timestamp(a, b) { if (a.d > b.d) return (1 * p13sortorder); if (a.d < b.d) return (-1 * p13sortorder); return 0; }
function p13sort_bysize(a, b) { if (a.s == b.s) return p13sort_filename(a, b); return (((a.s - b.s)) * p13sortorder); }
function p13sort_files(files) {
var r = [], sortselection = Q('p13sortdropdown').value;
for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
p13sortorder = 1;
if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
if (sortselection == 1) { r.sort(p13sort_filename); }
else if (sortselection == 2) { r.sort(p13sort_bysize); }
else if (sortselection == 3) { r.sort(p13sort_timestamp); }
return r;
}
function p13setActions() {
if (p13filetree == null) {
QE('p13DeleteFileButton', false);
QE('p13NewFolderButton', false);
QE('p13UploadButton', false);
QE('p13RenameFileButton', false);
QE('p13SelectAllButton', false);
Q('p13SelectAllButton').value = "すべて";
QE('p13RefreshButton', false);
QE('p13CutButton', false);
QE('p13CopyButton', false);
QE('p13PasteButton', false);
} else {
var cc = p13getFileSelCount(), tc = p13getFileCount(), sfc = p13getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13NewFolderButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13RenameFileButton', (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13SelectAllButton', tc > 0);
Q('p13SelectAllButton').value = (cc > 0 ? "なし" : "すべて");
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 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 updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
function getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
//
// FILES DOWNLOAD
//
var downloadFile; // Global state for file download
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
if (xxdialogMode || downloadFile || !files) return;
downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random() }
//console.log('p13downloadFileCancel', downloadFile);
files.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
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 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;
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:
p13folderup(9999);
break;
case 3:
p13uploadNextFile();
break;
default:
console.log('Unknown onFileUploadStateChange state', state);
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;
uploadFile.xreader = new FileReader();
uploadFile.xreader.onload = function () {
uploadFile.xdata = uploadFile.xreader.result;
uploadFile.ws.sendText({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength });
};
uploadFile.xreader.readAsArrayBuffer(file);
} else {
p13uploadFileCancel();
}
}
// Used to cancel the entire transfer.
function p13uploadFileCancel(button, tag) {
if (uploadFile != null) {
if (uploadFile.ws != null) {
uploadFile.ws.Stop();
uploadFile.ws = null;
}
uploadFile = null;
}
setDialogMode(0); // Close any dialog boxes if present
}
// Receive upload ack from the mesh agent, use this to keep sending more data
function p13gotUploadData(data) {
var cmd = JSON.parse(data);
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
if (cmd.action == 'uploadstart') {
p13uploadNextPart(false);
for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
} else if (cmd.action == 'uploadack') {
p13uploadNextPart(false);
} else if (cmd.action == 'uploaderror') {
p13uploadFileCancel();
}
}
// Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
function p13uploadNextPart(dataPriming) {
var data = uploadFile.xdata;
var start = uploadFile.xptr;
var end = uploadFile.xptr + 4096;
if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
if (start == data.byteLength) {
if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
} else {
var datapart = data.slice(start, end);
uploadFile.ws.send(datapart);
uploadFile.xptr = end;
Q('d2progressBar').value = end;
}
}
//
// MY MESHS
//
var currentMesh;
function p20updateMesh() {
if (currentMesh == null) return;
QH('p20meshName', EscapeHtml(currentMesh.name));
var meshtype = format("不明な#{0}", currentMesh.mtype);
var meshrights = currentMesh.links[userinfo._id].rights;
if (currentMesh.mtype == 1) meshtype = "Intelreg; 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));
x += addHtmlValue("タイプ", meshtype);
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
//x += '<br><input type=button value=Notes 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 += '<div style=margin-bottom:6px><a onclick=p20showAddMeshUserDialog() style=cursor:pointer><img src=images/icon-addnew.png border=0 height=12 width=12>' + " ユーザーを追加する" + '</a></div>'; }
/*
if ((meshrights & 4) != 0) {
if (currentMesh.mtype == 1) {
x += '<a onclick=addCiraDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-installmesh.png border=0 height=12 width=12> Install CIRA</a>';
x += '<a onclick=addDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-installmesh.png border=0 height=12 width=12> Install local</a>';
}
if (currentMesh.mtype == 2) {
x += '<a onclick=addAgentToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Install</a>';
}
}
*/
/*
function getMeshActions(mesh, meshrights) {
if ((meshrights & 4) == 0) return '';
var r = '';
if (mesh.mtype == 1) {
r += ' <a style=cursor:pointer;font-size:10px onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
r += ' <a style=cursor:pointer;font-size:10px onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
}
if (mesh.mtype == 2) {
r += ' <a style=cursor:pointer;font-size:10px onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
}
return r;
}
*/
x += '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:left;width:430px>' + "ユーザー認証" + '</th></tr>';
// Sort the users for this mesh
var count = 1, sortedusers = [];
for (var i in currentMesh.links) { sortedusers.push({ id: i, name: i.split('/')[2], 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 ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=height:32px;cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td>';
x += '<div style=float:right>' + trash + '</div><div style=float:right;padding-right:4px>' + rights + '</div><div class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div>';
x += '</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:small;text-align:right;margin-top:6px><span><a onclick=p20showDeleteMeshDialog() style=cursor:pointer>' + "グループを削除" + '</a></span></div>'; }
QH('p20info', x);
}
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:170px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
x += addHtmlValue("説明", '<input id=dp20meshdesc style=width:170px maxlength=1024 onkeyup=p20editmeshValidate() />');
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() {
QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
}
function p20showAddMeshUserDialog() {
if (xxdialogMode) return;
var x = addHtmlValue('User', '<input id=dp20username style=width:170px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
x += '<div style="border:2px groove gray;background-color:white;max-height:120px;overflow-y:scroll">';
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>' + "Intelreg;なし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>';
setDialogMode(2, "メッシュにユーザーを追加", 3, p20showAddMeshUserDialogEx, x);
p20validateAddMeshUserDialog();
Q('dp20username').focus();
}
function p20validateAddMeshUserDialog() {
var meshrights = currentMesh.links[userinfo._id].rights;
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() {
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;
}
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 });
}
function p20viewuser(userid) {
if (xxdialogMode) return;
userid = decodeURIComponent(userid);
var r = [], cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
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 & 256) != 0) r.push("リモートビューのみ");
if ((meshrights & 512) != 0) r.push("ターミナルなし");
if ((meshrights & 1024) != 0) r.push("ファイルなし");
if ((meshrights & 2048) != 0) r.push("Intelreg;なし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 buttons = 1, x = addHtmlValue("ユーザー", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
x += addHtmlValue("許可", r.join("、"));
if (((userinfo._id) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
setDialogMode(2, "デバイスグループユーザー", buttons, p20viewuserEx, x, userid);
}
function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "リモートメッシュユーザー", 3, p20viewuserEx2, format("ユーザー{0}の削除を確認しますか?", userid.split('/')[2]), userid); }
function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); }
//
// PANELS
//
var xxcurrentView = -1;
function go(x) {
setSessionActivity();
if (xxdialogMode || xxcurrentView == x) return;
updateFooterMenu();
setDialogMode(0);
// Edit this line when adding a new screen
for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
xxcurrentView = x;
}
//
// POPUP DIALOG
//
// undefined = Hidden, 1 = Generic Message
var xxdialogMode;
var xxdialogFunc;
var xxdialogButtons;
var xxdialogTag;
// 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();
xxdialogMode = x;
xxdialogFunc = f;
xxdialogButtons = b;
xxdialogTag = tag;
QE('idx_dlgOkButton', true);
QV('idx_dlgOkButton', b & 1);
QV('idx_dlgCancelButton', b & 2);
QV('id_dialogclose', (b & 2) || (b & 8));
QV('idx_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;
var b = xxdialogButtons;
var t = xxdialogTag;
setDialogMode();
if (((b & 8) || x) && f) f(x, t);
}
function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } }
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 center() { QS('dialog').left = ((((getDocWidth() - 300) / 2)) + 'px'); deskAdjust(); deskAdjust(); /*drawDeviceTimeline();*/ }
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
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); }
function reload() { window.location.href = window.location.href; }
function getNodeFromId(id) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } return null; }
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 addLink(x, f) { return '<a style=cursor:pointer;color:darkblue;text-decoration:none onclick=\'' + f + '\'>&diams; ' + x + '</a>'; }
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
function getFileSizeStr(size) { if (size == 1) return "1バイト"; return format('{0} bytes', size); }
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 focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
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 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 printDate(d) { return d.toLocaleDateString(args.locale); }
function printTime(d) { return d.toLocaleTimeString(args.locale); }
function printDateTime(d) { return d.toLocaleString(args.locale); }
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 nobreak(x) { return x.split(' ').join('&nbsp;'); }
</script>
</body></html>