<!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,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><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\'/></filter></svg>#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>✓</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>✗</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"> <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> <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> <span id="DeskToastButton"><img src="images/icon-notify.png" onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span> <!--<input id=DeskToolsButton type=button value=Tools onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()"> --> </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>✓</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>✗</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"> <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">Intel® 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 = ["切断されました", "接続しています...", "セットアップ...", "接続済み", "Intel®接続された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 = color:green> 2段階ログインの有効化に成功</ b>。再度ログインするには、有効なトークンが必要になります。" : "<b style = color:red> 2段階ログインの有効化に失敗しました</ b>。アプリケーションから秘密をクリアして、再試行してください。適切なコードを入力するのに数分しかかかりません。"); break; } case 'otpauth-clear': { if (xxdialogMode) return; setDialogMode(2, "認証アプリ", 1, null, message.success ? "<b style = color:green> 2段階のログインアクティベーションが削除されました</ b>。この機能はいつでも再アクティブ化できます。" : "<b style = color:red> 2段階のログインアクティベーションの削除に失敗しました</ b>。再試行する。"); break; } case 'otpauth-getpasswords': { if (xxdialogMode) return; var x = "ワンタイムトークンは、セカンダリ認証として使用できます。セットを生成して印刷し、安全な場所に保管してください。"; x += '<div style=\'border-radius:6px;border: 2px dashed #888;width:100%;margin-top:8px\'><div style=\'padding:8px;font-family:Arial, Helvetica, sans-serif;font-size:20px;font-weight:bold\'><table 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) + ' ' + p.substring(4); } else { x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + ' ' + p.substring(4); + '</strike>'; } } } else { x += '<tr><td>' + "アクティブなトークンがありません"; } x += '</table></div></div><br />'; x += '<div><input type=button value=\'' + "閉じる" + '\' onclick=setDialogMode(0) style=float:right></input>'; x += '<input type=button value=\'' + "新しいトークン" + '\' onclick=\'account_manageOtp(1);\'></input>'; if (message.passwords != null) { x += '<input type=button value=\'' + "クリア" + '\' onclick=\'account_manageOtp(2);\'></input>'; } x += '</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>' + "Intel® 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>●<span>'; } else { r = '<span style=color:red>●<span>'; } } else { // Password requirements provided, use that var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements); if (passReq == false) { ok = false; r = '<span style=color:red>' + "方針" + '<span>' } } } QH('dxPassWarn', r); //QE('account_dlgOkButton', ok); QE('idx_dlgOkButton', ok); } // Return a password strength score function checkPasswordStrength(password) { var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) } if (!password) return 0; for (var i = 0; i < password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; } for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; } return parseInt(r + (varCount - 1) * 10); } // Check password requirements function checkPasswordRequirements(password, requirements) { if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true; if (requirements.min) { if (password.length < requirements.min) return false; } if (requirements.max) { if (password.length > requirements.max) return false; } var num = 0, lower = 0, upper = 0, nonalpha = 0; for (var i = 0; i < password.length; i++) { if (/\d/.test(password[i])) { num++; } if (/[a-z]/.test(password[i])) { lower++; } if (/[A-Z]/.test(password[i])) { upper++; } if (/\W/.test(password[i])) { nonalpha++; } } if (requirements.num && (num < requirements.num)) return false; if (requirements.lower && (lower < requirements.lower)) return false; if (requirements.upper && (upper < requirements.upper)) return false; if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false; return true; } function updateMeshes() { var r = '', 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) + ' '; } // 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 + '\'> <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 + '\'> <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>' + "、Intel® 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>' + "Intel®なしこのグループの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>' + "Intel® 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 = "Intel®私"; if (typeof node.intelamt.sku == 'number') { if ((node.intelamt.sku & 8) != 0) { meName = "Intel® AMT"; } else if ((node.intelamt.sku & 16) != 0) { meName = "Intel® 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® 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>' + "Intel® AMT CIRA" + '</span>'); else if ((node.conn & 4) != 0) cstate.push('<span>' + "Intel® 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> '; //if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '")>Location</a> '; x += '</div><br>' QH('p10html3', x); // Set the node power state var powerstate = PowerStateStr(node.state); //if (node.state == 0) { powerstate = 'Unknown State'; } if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "メッシュエージェント" + '</span>'; } if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intel®接続されたAMT" + '</span>'; } else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intel® 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> ' + 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を編集® 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 + '\'> <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 + '\'> <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 = "Intel® AMTのみ、エージェントなし"; if (currentMesh.mtype == 2) meshtype = "ソフトウェアエージェントを使用して管理"; var x = ''; x += addHtmlValue("名", addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0)); x += addHtmlValue("説明", addLinkConditional(((currentMesh.desc && currentMesh.desc != '') ? EscapeHtml(currentMesh.desc) : ('<i>' + "なし" + '</i>')), 'p20editmesh(2)', (meshrights & 1) != 0)); 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> ' + 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>' + "Intel®なしAMT" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>' + "メッシュエージェントコンソール" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>' + "サーバーファイル" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>' + "ウェイクデバイス" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "デバイスノートの編集" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "自分のイベントのみを表示" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "チャットと通知" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20uninstall>' + "エージェントのアンインストール" + '</label><br>'; x += '</div>'; 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("Intel®なしAMT"); if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("制限された入力"); if ((meshrights & 8192) != 0) r.push("自己イベントのみ"); if ((meshrights & 16384) != 0) r.push("チャットと通知"); if ((meshrights & 32768) != 0) r.push("アンインストール"); } if (r.length == 0) { r.push("権利なし"); } var 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 + '\'>♦ ' + 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(' '); } </script> </body></html>