mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-26 23:25:53 -05:00
13940 lines
850 KiB
Handlebars
13940 lines
850 KiB
Handlebars
<!DOCTYPE html> <html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <style>body{margin:0;padding:0;border:0;color:black;font-size:13px;font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;background-color:#d3d9d6;}#container{background-color:#fff;width:960px;min-width:960px;margin:0 auto;border-top:0;border-right:1px solid #b7b7b7;border-bottom:0;border-left:1px solid #b7b7b7;padding:0;}#masthead{width:auto;margin:0;padding:0;overflow:auto;text-align:right;background-color:#036;width:960px;}#column_l{position:relative;float:left;width:930px;margin:0;padding:0 15px;background-color:#fff;}#footer{clear:both;overflow:auto;width:100%;text-align:center;background-color:#113962;padding-top:5px;padding-bottom:5px;}#masthead img{float:left;}#masthead p{font-size:11px;color:#fff;margin:10px 10px 0;}#footer a{color:#fff;text-decoration:underline;}#footer a:hover{color:#fff;text-decoration:none;}a{color:#036;text-decoration:underline;}.i1{background:url(../images/icons50.png) 0px 0px;height:50px;width:50px;cursor:pointer;border:none;}.i2{background:url(../images/icons50.png) -50px 0px;height:50px;width:50px;cursor:pointer;border:none;}.i3{background:url(../images/icons50.png) -100px 0px;height:50px;width:50px;cursor:pointer;border:none;}.i4{background:url(../images/icons50.png) -150px 0px;height:50px;width:50px;cursor:pointer;border:none;}.i5{background:url(../images/icons50.png) -200px 0px;height:50px;width:50px;cursor:pointer;border:none;}.i6{background:url(../images/icons50.png) -250px 0px;height:50px;width:50px;cursor:pointer;border:none;}.j1{background:url(../images/icons16.png) 0px 0px;height:16px;width:16px;cursor:pointer;border:none;}.j2{background:url(../images/icons16.png) -16px 0px;height:16px;width:16px;cursor:pointer;border:none;}.j3{background:url(../images/icons16.png) -32px 0px;height:16px;width:16px;cursor:pointer;border:none;}.j4{background:url(../images/icons16.png) -48px 0px;height:16px;width:16px;cursor:pointer;border:none;}.j5{background:url(../images/icons16.png) -64px 0px;height:16px;width:16px;cursor:pointer;border:none;}.j6{background:url(../images/icons16.png) -80px 0px;height:16px;width:16px;cursor:pointer;border:none;}.lbbutton{width:74px;height:74px;border-radius:5px;background-color:white;margin-left:8px;margin-top:8px;position:relative;cursor:pointer;opacity:0.5;}.lbbutton:hover{opacity:1;}.lbbuttonsel{opacity:0.9;}.lbbuttonsel2{width:82px;border-radius:5px 0px 0px 5px;opacity:1;}.lb1{background:url(../images/leftbar-62.jpg) -0px 0px;height:62px;width:62px;cursor:pointer;border:none;}.lb2{background:url(../images/leftbar-62.jpg) -75px 0px;height:62px;width:62px;cursor:pointer;border:none;}.lb3{background:url(../images/leftbar-62.jpg) -150px 0px;height:62px;width:62px;cursor:pointer;border:none;}.lb4{background:url(../images/leftbar-62.jpg) -225px 0px;height:62px;width:62px;cursor:pointer;border:none;}.lb5{background:url(../images/leftbar-62.jpg) -294px 0px;height:62px;width:62px;cursor:pointer;border:none;}.lb6{background:url(../images/leftbar-62.jpg) -360px 0px;height:62px;width:62px;cursor:pointer;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 }.si0{background :url(../images/icons16.png) 0px 0px;height :16px;width :16px;border:none;float:left }.si1{background :url(../images/icons16.png) -16px 0px;height :16px;width :16px;border:none;float:left }.si2{background :url(../images/icons16.png) -32px 0px;height :16px;width :16px;border:none;float:left }.si3{background :url(../images/icons16.png) -48px 0px;height :16px;width :16px;border:none;float:left }.si4{background :url(../images/icons16.png) -64px 0px;height :16px;width :16px;border:none;float:left }.mi{background :url(../images/meshicon50.png) 0px 0px;height:50px;width:50px;cursor:pointer;border:none }#floatframe{position:fixed;top:200px;height:300px;z-index:200;display:none;}.style1{text-align:center;}.style2{text-align:center;background-color:#808080;font-weight:bold;}.style3{text-align:center;color:white;background-color:#808080;font-weight:bold;}.style3x{text-align:center;color:white;background-color:#808080;font-weight:bold;}.style3x:hover{background-color:#606060;}.style3sel{text-align:center;color:white;background-color:#003366;font-weight:bold;}.style4{color:white;text-decoration:none;}.style5{text-align:center;background-color:#808080;font-weight:normal;}.style6{text-align:center;background-color:#D3D9D6;}.style7{font-size:large;background-color:#FFFFFF;}.style10{background-color:#C9C9C9;}.style11{font-size:large;background-color:#C9C9C9;}.style14{text-align:left;background-color:#D3D9D6;}.auto-style1{text-align:right;background-color:#D3D9D6;}.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;}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.fsize{float:right;text-align:right;width:180px;}.g1{background-position:0% 0%;width:14px;height:100%;float:left; background-image:linear-gradient(to right, #ffffff 0%, #c9c9c9 100%);background-color:#c9c9c9;background-repeat:repeat;background-attachment:scroll;}.g1s{background-image:linear-gradient(to right, #ffffff 0%, #b9b9b9 100%);}.g2{background-position:0% 0%;width:14px;height:100%;float:right; background-image:linear-gradient(to right, #c9c9c9 0%, #ffffff 100%);background-color:#c9c9c9;background-repeat:repeat;background-attachment:scroll;}.g2s{background-image:linear-gradient(to right, #b9b9b9 0%, #ffffff 100%);}.h1{background-position:0% 0%;width:14px;height:100%; background-image:linear-gradient(to right, #ffffff 0%, #d3d9d6 100%);background-color:#d3d9d6;background-repeat:repeat;background-attachment:scroll;}.h2{background-position:0% 0%;width:14px;height:100%; background-image:linear-gradient(to right, #d3d9d6 0%, #ffffff 100%);background-color:#d3d9d6;background-repeat:repeat;background-attachment:scroll;}.e1{font-size:large;margin-top:4px;margin-bottom:3px;overflow:hidden;word-wrap:hyphenate;white-space:nowrap;text-overflow:ellipsis;}.e2{float:left;height:100%;background-color:#c9c9c9;}.e2s{background-color:#b9b9b9;}.bar{font-size:large;background-color:#C9C9C9;height:24px;float:left;margin-bottom:2px;}.bar2{font-size:large;height:24px;float:left;margin-bottom:2px;}.bar18{font-size:large;background-color:#C9C9C9;height:18px;float:left;margin-bottom:2px;}.bar182{font-size:large;height:18px;float:left;margin-bottom:2px;}.devHeaderx{color:lightgray;}.DevSt{border-bottom-style:solid;border-bottom-width:1px;border-bottom-color:#DDDDDD;}.contextMenu{background:#F9F9F9;box-shadow:0 0 12px rgba( 0, 0, 0, .3 );border:1px solid #ccc; display:none;position:absolute;top:0;left:0;list-style:none;margin:0;padding:5px;min-width:100px;max-width:150px;z-index:500;}.cmtext{color:#444;display:inline-block;padding-left:8px;padding-right:8px;padding-top:5px;padding-bottom:5px;text-decoration:none;width:85%;cursor:default;overflow:hidden;position:relative;}.cmtext:hover{color:#f9f9f9;background:#444;}.gray{ filter:gray; -webkit-filter:grayscale(100%) opacity(60%); }.unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.notifiyBox{position:absolute;z-index:1000;top:50px;right:26px;width:300px;text-align:left;background-color:#F0ECCD;border:4px solid #666;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;-webkit-box-shadow:2px 2px 4px #888;-moz-box-shadow:2px 2px 4px #888;box-shadow:2px 2px 4px #888;max-height:200px;}.notifiyBox:before{content:' ';position:absolute;width:0;height:0;right:5px;top:-30px;border:15px solid;border-color:transparent #666 #666 transparent;}.notifiyBox:after{content:' ';position:absolute;width:0;height:0;right:7px;top:-24px;border:12px solid;border-color:transparent #F0ECCD #F0ECCD transparent;}.notification{width:100%;min-height:30px;}.notification:hover{background-color:#EFE8B6;}.deskToolsBar{padding:3px;}.deskToolsBar:hover{background-color:#EFE8B6;}.userTableHeader{border-bottom:1pt solid lightgray;padding-top:4px;padding-bottom:4px;}.viewSelector{width:32px;height:32px;background-color:#DDD;border-radius:3px;float:left;margin-left:5px;cursor:pointer;opacity:0.3;}.viewSelectorSel{background-color:#BBB;opacity:0.8;}.viewSelector:hover{opacity:0.5;background-color:#AAA;}.viewSelector1{margin-left:2px;margin-top:2px;background:url(../images/views.png) -0px 0px;height:28px;width:28px;}.viewSelector2{margin-left:2px;margin-top:2px;background:url(../images/views.png) -28px 0px;height:28px;width:28px;}.viewSelector3{margin-left:2px;margin-top:2px;background:url(../images/views.png) -56px 0px;height:28px;width:28px;}.viewSelector4{margin-left:2px;margin-top:2px;background:url(../images/views.png) -84px 0px;height:28px;width:28px;}.viewSelector5{margin-left:2px;margin-top:2px;background:url(../images/views.png) -112px 0px;height:28px;width:28px;}.backButtonEx{margin-left:2px;margin-top:2px;background:url(../images/views.png) -140px 0px;height:28px;width:28px;}.backButton{width:32px;height:32px;background-color:#DDD;border-radius:3px;float:left;margin-right:5px;cursor:pointer;opacity:0.3;}.backButton:hover{opacity:0.5;background-color:#AAA;}.hoverButton{opacity:0.5;}.hoverButton:hover{opacity:1;}</style> <style>.ol-box{box-sizing:border-box;border-radius:2px;border:2px solid #00f;}.ol-mouse-position{top:8px;right:8px;position:absolute;}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute;}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;}.ol-overlay-container{will-change:left,right,top,bottom;}.ol-unsupported{display:none;}.ol-unselectable, .ol-viewport{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto;}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing;}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab;}.ol-control{position:absolute;background-color:rgba(255,255,255,.4);border-radius:4px;padding:2px;}.ol-control:hover{background-color:rgba(255,255,255,.6);}.ol-zoom{top:.5em;right:.5em;}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear;}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s;}.ol-zoom-extent{top:4.643em;left:.5em;}.ol-full-screen{right:.5em;top:.5em;}@media print{.ol-control{display:none;}}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-size:1.14em;font-weight:700;text-decoration:none;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:rgba(0,60,136,.5);border:none;border-radius:2px;}.ol-control button::-moz-focus-inner{border:none;padding:0;}.ol-zoom-extent button{line-height:1.4em;}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform;}.ol-touch .ol-control button{font-size:1.5em;}.ol-touch .ol-zoom-extent{top:5.5em;}.ol-control button:focus, .ol-control button:hover{text-decoration:none;background-color:rgba(0,60,136,.7);}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0;}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px;}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em);}.ol-attribution ul{margin:0;padding:0 .5em;font-size:.7rem;line-height:1.375em;color:#000;text-shadow:0 0 2px #fff;}.ol-attribution li{display:inline;list-style:none;line-height:inherit;}.ol-attribution li:not(:last-child):after{content:" ";}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle;}.ol-attribution button, .ol-attribution ul{display:inline-block;}.ol-attribution.ol-collapsed ul{display:none;}.ol-attribution.ol-logo-only ul{display:block;}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8);}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0;height:1.1em;line-height:1em;}.ol-attribution.ol-logo-only{background:0 0;bottom:.4em;height:1.1em;line-height:1em;}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em;}.ol-attribution.ol-logo-only button, .ol-attribution.ol-uncollapsible button{display:none;}.ol-zoomslider{top:4.5em;left:.5em;height:200px;}.ol-zoomslider button{position:relative;height:10px;}.ol-touch .ol-zoomslider{top:5.5em;}.ol-overviewmap{left:.5em;bottom:.5em;}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0;}.ol-overviewmap .ol-overviewmap-map, .ol-overviewmap button{display:inline-block;}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px;}.ol-overviewmap:not(.ol-collapsed) button{bottom:1px;left:2px;position:absolute;}.ol-overviewmap.ol-collapsed .ol-overviewmap-map, .ol-overviewmap.ol-uncollapsible button{display:none;}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8);}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7);}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move;}</style> <style> .ol-ctx-menu-container{position:absolute;padding:8px;background:#fff;color:#222;font-size:13px;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,.2);box-sizing:border-box}.ol-ctx-menu-container a,.ol-ctx-menu-container div,.ol-ctx-menu-container img,.ol-ctx-menu-container li,.ol-ctx-menu-container span,.ol-ctx-menu-container ul{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}.ol-ctx-menu-container a img{border:none}.ol-ctx-menu-container *,.ol-ctx-menu-container :after,.ol-ctx-menu-container :before{box-sizing:inherit}.ol-ctx-menu-container.ol-ctx-menu-hidden{opacity:0;visibility:hidden;-webkit-transition:visibility 0s linear .3s,opacity .3s;transition:visibility 0s linear .3s,opacity .3s}.ol-ctx-menu-container ul{list-style:none}.ol-ctx-menu-container li{position:relative;line-height:20px;padding:2px 5px}.ol-ctx-menu-container li:not(.ol-ctx-menu-separator):hover{cursor:pointer;background-color:#333;color:#eee}.ol-ctx-menu-container li.ol-ctx-menu-submenu .ol-ctx-menu-container{border:1px solid #eee;padding:8px;top:0;opacity:0;visibility:hidden;-webkit-transition:visibility 0s linear .3s,opacity .3s;transition:visibility 0s linear .3s,opacity .3s}.ol-ctx-menu-container li.ol-ctx-menu-submenu:hover .ol-ctx-menu-container{opacity:1;visibility:visible;-webkit-transition-delay:0s;transition-delay:0s}.ol-ctx-menu-container li.ol-ctx-menu-submenu:after{position:absolute;top:7px;right:10px;content:"";display:inline-block;width:.6em;height:.6em;border-right:.3em solid #222;border-top:.3em solid #222;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.ol-ctx-menu-container li.ol-ctx-menu-submenu:hover:after{border-color:#eee}.ol-ctx-menu-container li.ol-ctx-menu-separator{padding:0}.ol-ctx-menu-container li.ol-ctx-menu-separator hr{border:0;height:1px;background-image:-webkit-linear-gradient(right,transparent,rgba(0,0,0,.75),transparent);background-image:linear-gradient(270deg,transparent,rgba(0,0,0,.75),transparent)}.ol-ctx-menu-icon{text-indent:20px;background-size:20px auto;background-repeat:no-repeat;background-position:0}.ol-ctx-menu-zoom-in{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABaUlEQVQ4T72U7VHCQBCGn90GtAMuNGCswFiBWIFQgWMFxg6wArECsQKhArEBiB1Qwa1zgQn5IAYcxv13k71n3919L8KJQ07M47+BzgG9TRfZ/JBuWhS6BJFHRJICYrZGZIz3z5Ct2+B7gG6I6kt+wewdkQVwjtkAkR5mC8yu26A1oItR/cTsOweQBdgutD8G7jGm2PJ2n8oqUKIpIjd4HxTM8gvaT/F+AlmWnyWaIXKF95eNguFzTYFhNsdWu9kFgFlaFMANUH3D8wDLoLgSTSD2il8NCe2ZXQBxWDGwxmyUzzOMBZ7wy7Qb2K0wQfXjMOBuhlFpZtNty5sFaTQBuTusZdymeqs1SpYKcO9HkE3KbTd9WFijMHJQ5hBNEAYNq5Qd0dhyke0GiE4QzjqfW23mHT8Hl4DG4Lce3FPE7AtbBSdsbNqpoJLgYkRnNeUV+xwJDHTnUEkxHGbhBXUs5TjJjew/KPy94g+NRaIVRYmMXwAAAABJRU5ErkJggg==")}.ol-ctx-menu-container li:hover.ol-ctx-menu-zoom-in{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABc0lEQVQ4T71U21ECQRDsJgGdvQDECMQIxAjECMQILCPwzAAjECIQI0AiEDPQAPaWCBhrcKHuCUcV5f7dY3v6tUscefHIePhfwBBCF8CZqRCReRs1tQxDCH1VfQLQz4EsSY4AvIjIsgm8AhhCGKrqa9zwrqoLAKckB5HtguR1E2gBMITQU9VPAD8GICIGtl3e+xHJBwBT59xtHcsCYJZlUwA3kcGHbfDep51OZywi3/acZZm9vyJ5WR5o38uACmDunNt6ZwAkUxFZDwghDFT1jeSjiJinhVUBVNVJkiTDKO8CQA+AsbNQ7s1Ps0VVn5MkSfcCtmBoDZi1Bdx4eJ7zbBolrwPy3o9J3rWSHPs3A1BbjVKlYBaIyDgvu9LDXDU2RTZmXVW1oKyLxRD+OrkOrJLy5mVM0iaftDhuhVbsvBzMglzKUNW6IV/OOWtCM8MmVvEkmbwt83LaB19fdgOtVquUZJeknaDdobTwbOcvBzPcN/AXH1DFFWP7u9oAAAAASUVORK5CYII=")}.ol-ctx-menu-zoom-out{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABU0lEQVQ4T72U7VECMRRFz3sNaAdkacC1AtcKxApcKnCsQOwAK3CtQKxAqEBsANYOqCDPyTIC+8WCw5jfybn33dxEOPGSE/P4b6BzQG89RT47ZJoWhy5B5BGRZAMxWyEyxvtnyFdt8AagS1F9KQ6YvSMyB84xGyDSw2yO2XUbtAJ0MaqfmH0XAPIA2y7tj4F7jAm2uG1yWQZKNEHkBu+Dg2njWBJNEbnC+8uaIFRuWfuG2QxbbrOrUd0A1Tc8D7AIjkur7DAAsVf8MiWMZ3ZR2m02LPIMscATfjHqBnY7TFD9OAy4zTCCPG/MUKMM5O6wkXFr9dZq7FQqqHk/hDzbFa73cFONTZFDdRyiCcKg5rrSiLaXkiI6RjjrfG6VzDs+B5eAxuDXeYpmNRGzL2wZ/wof+du4GNFpBVqqz5HA4MM5VEYYDrOs+1I6Q9u/4Q8O9wN/AGgWjBVqQjjgAAAAAElFTkSuQmCC")}.ol-ctx-menu-container li:hover.ol-ctx-menu-zoom-out{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABYklEQVQ4T72U4VHCQBCF36tA91KAWIFYgViBWIFYgWMFYgdYgVCBWAFSgdiBFpAsFWSdxcDkQoBkhnF/ZjbfvX377ogjF4/Mw/8CVbUD4MynEJF5k2lqFapqz8yeAPRKkCXJEYAXEVnugm8BVXVgZq/FD+9mtgBwSrJfqF2QvN4FjYCq2jWzTwA/DhARh20qTdMRyQcA0xDCbZ3KCJhl2RTATaHgo+6HLMv8+xXJy+qB3l8FGoB5CKHsXcRV1b6ZvZF8FBH3NKotoJlNkiQZFONdlLtJ3rufbouZPSdJMjwIbKDQEzBrClx7eC4i33Uepmk6JnnXaOQifzMAtdGoRApugYiMI1uqKkrRWAfZo9MxM1+UZzFewl8mN4nYdVM83L7BkwbXLUrF3sfBLQDQBbDy08x8vOohXyEE71lVq9emuEk+3gZa3XYroCvwFyjP8yHJDsnxwaU08GxvS2uFhw78BbzWrxXgMbsHAAAAAElFTkSuQmCC")}</style> <script type="text/javascript" src="scripts/charts.js"></script> <script type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script> <script type="text/javascript" src="scripts/ol.js"></script> <script type="text/javascript" src="scripts/ol3-contextmenu.js"></script> <title>MeshCentral</title> </head> <body id="body" onload="if (typeof(startup) !== 'undefined') startup();" oncontextmenu="handleContextMenu(event)" style="display:none"> <div id="contextMenu" class="contextMenu noselect" style="display:none"> <div id="cxinfo" class="cmtext" onclick="cmaction(1,event)"><b>Information</b></div> <div id="cxdesktop" class="cmtext" onclick="cmaction(3,event)">Desktop</div> <div id="cxterminal" class="cmtext" onclick="cmaction(2,event)">Terminal</div> <div id="cxfiles" class="cmtext" onclick="cmaction(4,event)">Files</div> <div id="cxevents" class="cmtext" onclick="cmaction(5,event)">Events</div> <div id="cxconsole" class="cmtext" onclick="cmaction(6,event)">Console</div> <hr id="cxmgroupsplit"> <div id="cxmdesktop" class="cmtext" onclick="cmaction(7,event)" style="display:none">Multi-Desktop</div> </div> <div id="meshContextMenu" class="contextMenu,noselect" style="display:none;min-width:0px"> <div id="cxselectall" class="cmtext" onclick="cmmeshaction(1,event)">Select All</div> <div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2,event)">Select None</div> <hr id="cxmgroupsplit2" style="display:none"> <div id="cxmmdesktop" class="cmtext" style="display:none" onclick="cmmeshaction(3,event)">Multi-Desktop</div> </div> <div id="container" style="max-height:100vh;position:relative"> <div id="notifiyBox" class="notifiyBox" style="display:none"></div> <div id="mastheadx"></div> <div id="masthead" class="noselect" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden"> <div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px"> <strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong> </div> <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px"> <strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong> </div> <div style="float:right"> <div id="notificationCount" onclick="clickNotificationIcon()" class="unselectable" style="display:none;min-width:28px;font-size:20px;border-radius:5px;background-color:lightblue;text-align:center;margin:8px;cursor:pointer;padding:4px" title="Click to view current notifications">0</div> </div> <p id="logoutControl">{{{logoutControl}}}</p> </div> <div id="page_leftbar" style="height:calc(100vh - 66px);width:90px;position:absolute;z-index:1000;background:#113962;background:linear-gradient(to bottom, #104893 0%,#113962 100%);color:white;display:none"> <div style="height:16px"></div> <div id="LeftMenuMyDevices" class="lbbutton lbbuttonsel" title="My Devices" onclick="go(1)"> <div class="lb2" style="position:absolute;top:6px;left:6px"></div> </div> <div id="LeftMenuMyAccount" class="lbbutton" title="My Account" onclick="go(2)"> <div class="lb1" style="position:absolute;top:6px;left:6px"></div> </div> <div id="LeftMenuMyEvents" class="lbbutton" title="My Events" onclick="go(3)"> <div class="lb3" style="position:absolute;top:6px;left:6px"></div> </div> <div id="LeftMenuMyFiles" class="lbbutton" title="My Files" onclick="go(5)"> <div class="lb4" style="position:absolute;top:6px;left:6px"></div> </div> <div id="LeftMenuMyUsers" class="lbbutton" title="My Users" onclick="go(4)"> <div class="lb5" style="position:absolute;top:6px;left:6px"></div> </div> <div id="LeftMenuMyServer" class="lbbutton" title="My Server" onclick="go(6)" style="display:none"> <div class="lb6" style="position:absolute;top:6px;left:6px"></div> </div> </div> <div id="page_content" style="max-height:calc(100vh - 130px)"> <div id="topbarmaster"> <div id="topbar" class="noselect"> <div> <div style="position:relative"> <div style="position:absolute;top:3px;right:6px"> <span title="Toggle full width" style="cursor:pointer;color:white" onclick="toggleFullScreen(1)">↔</span> </div> <table id="MainMenuSpan" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr> <td id="MainMenuMyDevices" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(1)">My Devices</td> <td id="MainMenuMyAccount" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(2)">My Account</td> <td id="MainMenuMyEvents" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(3)">My Events</td> <td id="MainMenuMyFiles" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(5)">My Files</td> <td id="MainMenuMyUsers" style="width:100px;height:24px;cursor:pointer;display:none" class="style3x" onclick="go(4)">My Users</td> <td id="MainMenuMyServer" style="width:100px;height:24px;cursor:pointer;display:none" class="style3x" onclick="go(6)">My Server</td> <td class="style3" style="text-align:right;height:24px"> </td> </tr> </table> <div id="MainSubMenuSpan" style="display:none"> <table id="MainSubMenu" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr> <td id="MainDev" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(10)">General</td> <td id="MainDevDesktop" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(11)">Desktop</td> <td id="MainDevTerminal" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(12)">Terminal</td> <td id="MainDevFiles" style="width:100px;height:24px;cursor:pointer;display:none" class="style3x" onclick="go(13)">Files</td> <td id="MainDevEvents" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(16)">Events</td> <td id="MainDevAmt" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(14)">Intel® AMT</td> <td id="MainDevConsole" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(15)">Console</td> <td class="style3" style="height:24px"> </td> </tr> </table> </div> <div id="MeshSubMenuSpan" style="display:none"> <table id="MeshSubMenu" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr> <td id="MeshGeneral" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(20)">General</td> <td class="style3" style="height:24px"> </td> </tr> </table> </div> <div id="UserSubMenuSpan" style="display:none"> <table id="UserSubMenu" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr> <td id="UserGeneral" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(30)">General</td> <td id="UserEvents" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(31)">Events</td> <td class="style3" style="height:24px"> </td> </tr> </table> </div> <div id="ServerSubMenuSpan" style="display:none"> <table id="ServerSubMenu" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr> <td id="ServerGeneral" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(6)">General</td> <td id="ServerConsole" style="width:100px;height:24px;cursor:pointer" class="style3x" onclick="go(115)">Console</td> <td class="style3" style="height:24px"> </td> </tr> </table> </div> <div id="UserDummyMenuSpan"> <table id="UserDummyMenu" style="width:100%;height:22px" cellpadding="0" cellspacing="0" class="style1"> <tr><td class="style3" style="text-align:right;height:24px"> </td></tr> </table> </div> </div> </div> </div> </div> <div id="column_l"> <div id="p0" style="display:none"> <div id="p0message" style="margin:50px;text-align:center"><span id="p0span">Server disconnected</span>, <href onclick="reload()" style="cursor:pointer"><u>click to reconnect</u></href>.</div> </div> <div id="p1" style="display:none"> <div style="float:right;display:none" id="devListToolbarViewIcons"> <div id="devViewButton1" class="viewSelector" onclick="onDeviceViewChange(1)" title="Columns"><div class="viewSelector2"></div></div> <div id="devViewButton2" class="viewSelector" onclick="onDeviceViewChange(2)" title="List"><div class="viewSelector1"></div></div> <div id="devViewButton3" class="viewSelector" onclick="onDeviceViewChange(3)" title="Desktops"><div class="viewSelector3"></div></div> <div id="devViewButton4" class="viewSelector" onclick="onDeviceViewChange(4)" title="Map"><div class="viewSelector4"></div></div> </div><div><h1>My Devices</h1></div> <table class="noselect" style="width:100%;height:24px;background-color:#d3d9d6;vertical-align:middle;border-spacing:0"> <tr> <td class="h1"></td> <td id="devListToolbar" class="style14" style="display:none"> <input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All"> <input type="button" id="GroupActionButton" disabled="disabled" value="Group Action" onclick="groupActionFunction()"> <input id="SearchInput" type="text" style="width:120px" placeholder="Filter" onchange="masterUpdate(5)" onkeyup="masterUpdate(5)" autocomplete="off" onfocus="onSearchFocus(1)" onblur="onSearchFocus(0)"> <label><input type="checkbox" id="RealNameCheckBox" onclick="onRealNameCheckBox()"><span title="Show devices operating system name">OS Name</span></label> </td> <td id="kvmListToolbar" class="style14" style="height:100%;display:none"> <input type="button" onclick="connectAllKvmFunction()" value="Connect All"> <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All"> <label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect">Auto </label> <input type="button" onclick="showMultiDesktopSettings()" value="Settings"> </td> <td id="devMapToolbar" class="style14" style="height:100%;display:none"> <input type="text" id="mapSearchLocation" placeholder="Search Location" onfocus="onMapSearchFocus(1)" onblur="onMapSearchFocus(0)"> <input type="button" value="Search" title="Search for location" onclick="getSearchLocation()"> <input type="button" id="refreshmap" title="Reset map view" value="Reset" style="margin-left:5px" onclick="refreshMap(false,true)"> </td> <td class="auto-style1" style="height:100%"> <div style="float:right;display:none" id="devListToolbarView"> View <select id="viewselect" onchange="onDeviceViewChange()"> <option value="1">Columns <option value="2">List <option value="3">Desktops <option id="viewselectmapoption" value="4">Map </select> </div> <div style="float:right;display:none" id="devListToolbarSort"> Sort <select id="sortselect" onchange="masterUpdate(6)"> <option>Group <option>Power <option>Device <option>Tags </select> </div> <div style="float:right;display:none" id="devListToolbarSize"> Size <select id="sizeselect" onchange="onDeviceViewChange()"> <option value="0">Small <option value="1">Medium <option value="2">Large </select> </div> </td> <td class="h2"></td> </tr> </table> <div id="NoMeshesPanel" style="display:none"> <table style="width:100%;padding:20px"> <tr> <td valign="top" style="width:50px"> <img src="images/info.png" height="48" width="47"> </td> <td> To get started, <a onclick="account_createMesh()" style="cursor:pointer"><strong>click here to create a device group</strong></a>. </td> </tr> </table> </div> <div id="xdevices" class="noselect" style="max-height:calc(100vh - 239px);overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;display:none"></div> <div id="xdevicesmap" style="height:calc(100vh - 239px);width:100%;overflow:hidden;position:relative;display:none"> <div id="xmapSearchResultsDlg" style="position:absolute;display:none;max-height:280px;left:5px;top:5px;max-width:250px;z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666"> <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0"> <div id="xmapSearchClose" style="float:right;padding:5px;cursor:pointer" onclick="mapCloseSearchWindow()"><b>X</b></div> <div style="padding:5px">Location Results</div> <div style="width:100%;margin:6px"></div> </div> <div id="xmapSearchResults" style="margin:6px"></div> </div> </div> <div id="xmap-info-window" style="text-shadow:0px 0px 15px #FFF"></div> </div> <div id="p2" style="display:none"> <h1>My Account</h1> <img id="p2AccountImage" alt="" width="150" height="103" src="images/mainaccount.jpg" style="margin-bottom:10px;margin-right:20px;float:right"> <div id="p2AccountSecurity" style="display:none"> <p><strong>Account security</strong></p> <div style="margin-left:25px"> <div id="manageAuthApp"><div style="width:15px;display:inline-block"><span id="authAppSetupCheck" style="color:green;font-size:10px"><strong>✓</strong></span></div><span><a onclick="account_manageAuthApp()" style="cursor:pointer">Manage authenticator app</a><br></span></div> <div id="manageHardwareOtp"><div style="width:15px;display:inline-block"><span id="authKeySetupCheck" style="color:green;font-size:10px"><strong>✓</strong></span></div><span><a onclick="account_manageHardwareOtp(0)" style="cursor:pointer">Manage security keys</a><br></span></div> <div id="manageOtp"><div style="width:15px;display:inline-block"><span id="authCodesSetupCheck" style="color:green;font-size:10px"><strong>✓</strong></span></div><span><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a><br></span></div> </div> </div> <div id="p2AccountActions"> <p><strong>Account actions</strong></p> <p style="margin-left:40px"> <span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br></span> <a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br> <a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span><br> <a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br> </p> <br style="clear:both"> </div> <strong>Device Groups</strong> ( <a onclick="account_createMesh()" style="cursor:pointer"><img height="12" src="images/icon-addnew.png" width="12" border="0"> New</a> ) <br><br> <div id="p2meshes"></div> <div id="p2noMeshFound" style="margin-left:40px;display:none">No device groups. <a onclick="account_createMesh()" style="cursor:pointer"><strong>Get started here!</strong></a></div> <br style="clear:both"> </div> <div id="p3" style="display:none"> <h1>My Events</h1> <table style="width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px;vertical-align:middle;border-spacing:0"> <tr> <td class="h1"></td> <td> <input id="p2deleteall" type="button" onclick="showDeleteAllEventsDialog()" style="display:none" value="Delete All..."></td> <td class="auto-style1"> Show <select id="p3limitdropdown" onchange="refreshEvents()"> <option value="60">Last 60 <option value="120">Last 120 <option value="250">Last 250 <option value="500">Last 500 <option value="1000">Last 1000 </select> </td> <td class="h2"></td> </tr> </table> <div id="p3events" style="height:calc(100vh - 243px);overflow-y:scroll"></div> </div> <div id="p4" style="display:none"> <h1>My Users</h1> <table style="width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px;vertical-align:middle;border-spacing:0"> <tr> <td class="h1"></td> <td class="style14"> <div style="float:right"> <input type="button" onclick="showUserBroadcastDialog()" style="margin-right:6px" value="Broadcast"> </div> <div> <input id="UserNewAccountButton" type="button" style="margin-left:6px" onclick="showCreateNewAccountDialog()" value="New Account..."> <input id="UserSearchInput" type="text" style="width:120px;margin-left:6px" placeholder="Filter" onchange="onUserSearchInputChanged()" onkeyup="onUserSearchInputChanged()" autocomplete="off" onfocus="onUserSearchFocus(1)" onblur="onUserSearchFocus(0)"> </div> </td> <td class="h2"></td> </tr> </table> <div id="p3users" style="max-height:calc(100vh - 243px);overflow-y:auto"></div> </div> <div id="p5" style="display:none"> <h1>My Files</h1> <table id="p5toolbar" style="width:100%" cellpadding="0" cellspacing="0"> <tr> <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom"> <div id="p5rightOfButtons" style="float:right;margin-top:3px"></div> <div> <input type="button" id="p5FolderUp" disabled="disabled" onclick="p5folderup();" value="Up"> <input type="button" id="p5SelectAllButton" disabled="disabled" onclick="p5selectallfile();" value="Select All" onkeypress="return false;" onkeydown="return false;"> <input type="button" id="p5RenameFileButton" disabled="disabled" value="Rename" onclick="p5renamefile();" onkeypress="return false;" onkeydown="return false;"> <input type="button" id="p5DeleteFileButton" disabled="disabled" value="Delete" onclick="p5deletefile();" onkeypress="return false;" onkeydown="return false;"> <input type="button" id="p5NewFolderButton" disabled="disabled" value="New Folder" onclick="p5createfolder();" onkeypress="return false;" onkeydown="return false;"> <input type="button" id="p5UploadButton" disabled="disabled" value="Upload" onclick="p5uploadFile()" onkeypress="return false;" onkeydown="return false;"> <input type="button" id="p5CutButton" disabled="disabled" value="Cut" onclick="p5copyFile(1)" onkeypress="return false" onkeydown="return false"> <input type="button" id="p5CopyButton" disabled="disabled" value="Copy" onclick="p5copyFile(0)" onkeypress="return false" onkeydown="return false"> <input type="button" id="p5PasteButton" disabled="disabled" value="Paste" onclick="p5pasteFile()" onkeypress="return false" onkeydown="return false"> </div> </td> </tr> <tr> <td style="background-color:#E4E9E7;height:28px"> <div style="float:right"> <select id="p5sortdropdown" onchange="updateFiles()"> <option value="1" selected="selected">Sort by name <option value="2">Sort by size <option value="3">Sort by date <option value="4">Descend by name <option value="5">Descend by size <option value="6">Descend by date </select> </div> <div> <span id="p5currentpath"></span></div> </td> </tr> </table> <div id="p5filetable" style="width:100%;height:calc(100vh - 294px);overflow:auto;-webkit-user-select:none;position:relative"> <div id="p5PublicShare" style="display:none;width:100%;overflow:auto;-webkit-user-select:none;background-color:lightsteelblue"><div style="padding:4px">These files are shared publicly, click "link" to get public url.</div></div> <div id="bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✓</b></div> <div id="bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✗</b></div> <span id="p5files"></span> </div> <table id="p5toolbarBottom" style="width:100%" cellpadding="0" cellspacing="0"> <tr><td class="style6" style="text-align:left;padding:3px"> <span id="p5bottomstatus"></span></td></tr> </table> </div> <div id="p6" style="display:none"> <img id="MainMeshImage" src="serverpic.ashx" style="border-width:0px;height:200px;width:200px;float:right"> <h1>My Server</h1> <p id="p2ServerActions"><strong>Server actions</strong></p> <p style="margin-left:40px"> <div id="p2ServerActionsBackup" style="margin-left:40px"><a href="/backup.zip" rel="noreferrer noopener" target="_blank" style="cursor:pointer">Download server backup</a></div> <div id="p2ServerActionsRestore" style="margin-left:40px"><a onclick="server_showRestoreDlg()" style="cursor:pointer">Restore server with backup</a></div> <div id="p2ServerActionsVersion" style="margin-left:40px"><a onclick="server_showVersionDlg()" style="cursor:pointer">Check server version</a></div> <div id="p2ServerActionsErrors" style="margin-left:40px"><a onclick="server_showErrorsDlg()" style="cursor:pointer">Show server error log</a></div> </p> <br><strong>Server Statistics</strong><br><br> <div id="serverStats" style="margin-left:40px"> <div id="serverCpuChartView" style="display:none"> <div style="width:60px;display:inline-block"><canvas id="serverCpuChart" style="width:60px;height:60px"></canvas></div> <div style="width:160px;display:inline-block" id="serverCpuChartText"></div> </div> <div id="serverMemoryChartView" style="display:none"> <div style="width:60px;display:inline-block"><canvas id="serverMemoryChart" style="width:60px;height:60px"></canvas></div> <div style="width:160px;display:inline-block" id="serverMemoryChartText"></div> </div><br><br> <div id="serverStatsTable"></div> </div> </div> <div id="p10" style="display:none"> <table style="width:100%" cellpadding="0" cellspacing="0"> <tr> <td style="width:auto" valign="top"> <div id="p10title"> <div id="p10BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>General - <span id="p10deviceName"></span></h1> </div> <div id="p10html"></div> </td> <td style="width:20px"></td> <td style="width:200px"> <a style="cursor:pointer" onclick="p10showiconselector()"><img id="MainComputerImage" style="border-width:0px;height:200px;width:200px"></a> <div style="width:100%;text-align:center"><strong><span id="MainComputerState"></span></strong></div> </td> </tr> </table><br> <div id="p10html2"></div> <div id="p10html3"></div> </div> <div id="p11" class="noselect" style="display:none"> <div id="p11title"> <div id="p11deviceNameHeader"> <div id="p11BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <div style="float:right" id="devListToolbarViewIcons"><div class="viewSelector" onclick="deskToggleFull(event)" title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div> <h1>Desktop - <span id="p11deviceName"></span></h1> </div> </div> <div id="p14warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()"> <div class="icon2" style="float:left;margin:7px"></div> <div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div> </div> <div id="p14warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()"> <div class="icon2" style="float:left;margin:7px"></div> <div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div> </div> <table id="deskarea0" cellpadding="0" cellspacing="0" style="width:100%;padding:0px;padding:0px;margin-top:0px"> <tr id="deskarea1"> <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0"> <div style="float:right;text-align:right"> <span id="p14power"></span> <div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Left" onclick="drotate(-1)">↺</div> <div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Right" onclick="drotate(1)">↻</div> <input id="deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px;display:none"> <input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick="deskSaveImage()" style="margin-right:3px"> <input id="deskActionsBtn" type="button" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()" style="margin-right:3px"> <input id="deskActionsSettings" type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="margin-right:3px"> <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px;display:none"> </div> <div> <div id="idx_deskFullBtn2" onclick="deskToggleFull(event)" style="float:left;font-size:large;cursor:pointer;display:none"> ✖</div> <input type="button" id="autoconnectbutton1" value="AutoConnect" onclick="autoConnectDesktop(event)" onkeypress="return false" onkeydown="return false" style="display:none"> <span id="connectbutton1span"> <input type="button" id="connectbutton1" value="Connect" onclick="connectDesktop(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span> <span id="connectbutton1hspan"> <input type="button" id="connectbutton1h" value="HW Connect" onclick="connectDesktop(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span> <span id="disconnectbutton1span"> <input type="button" id="disconnectbutton1" value="Disconnect" onclick="connectDesktop(event,0)" onkeypress="return false" onkeydown="return false"></span> <span id="deskstatus">Disconnected</span> </div> </td> </tr> <tr id="deskarea2"> <td> <div style="background-color:gray"><div id="progressbar" style="height:2px;width:0%;background-color:red"></div></div> </td> </tr> <tr id="deskarea3"> <td id="deskarea3x" style="background:black;text-align:center;position:relative;overflow:hidden"> <div id="DeskFocus" style="overflow:hidden;color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div> <div id="DeskParent" style="overflow:hidden"> <canvas id="Desk" width="640" height="480" style="overflow:hidden;width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onmousewheel="dmousewheel(event)"></canvas> </div> <div id="DeskTools" style="position:absolute;width:400px;height:100%;background-color:gray;top:0;right:0;border-left:2px solid lightgray;display:none"> <a id="DeskToolsRefreshButton" style="float:right;padding:3px;cursor:pointer" onclick="refreshDeskTools()">Refresh</a> <div id="DeskToolsBar" style="position:absolute;padding:3px;border-radius:3px 3px 0px 0px;top:5px;left:4px;bottom:26px;background-color:lightgray;cursor:pointer">Processes</div> <div style="position:absolute;top:26px;left:4px;right:4px;bottom:4px;background-color:lightgray;text-align:left"> <div style="border-bottom:1px solid darkgray;padding:3px"><a style="width:50px;padding-right:5px;float:left;cursor:pointer" title="Sort by process id" onclick="sortProcess(0)">PID</a><a style="cursor:pointer" title="Sort by name" onclick="sortProcess(1)">Name</a></div> <div id="DeskToolsProcesses" style="overflow-y:scroll;position:absolute;top:24px;bottom:0px;width:100%"></div> </div> </div> </td> </tr> <tr id="deskarea4"> <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0"> <div style="float:right;text-align:right"> <select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onclick="deskGetDisplayNumbers(event)"></select> <input id="DeskToolsButton" type="button" value="Tools" title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()"> <span id="DeskChatButton" style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Open chat window to this computer"><img src='images/icon-chat.png' onclick="deviceChat()" height="16" width="16" style="padding-top:2px"></span> <span id="DeskNotifyButton" style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Display a notification on the remote computer"><img src='images/icon-notify.png' onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span> <span id="DeskOpenWebButton" style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Open a web address on remote computer"><img src='images/icon-url2.png' onclick="deviceUrlFunction()" height="16" width="16" style="padding-top:2px"></span> </div> <div> <select style="margin-left:6px" id="deskkeys"> <option value="5">Win <option value="0">Win+Down <option value="1">Win+Up <option value="2">Win+L <option value="3">Win+M <option value="4">Shift+Win+M <option value="6">Win+R </select> <input id="DeskWD" type="button" value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()"> <input id="DeskClip" style="margin-left:6px;display:none" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()"> <input id="DeskCAD" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()"> <label><span id="DeskControlSpan" style="margin-left:6px" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span></label> </div> </td> </tr> </table> </div> <div id="p12" style="display:none"> <div id="p12title"> <div id="p12BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>Terminal - <span id="p12deviceName"></span></h1> </div> <div id="p12warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()"> <div class="icon2" style="float:left;margin:7px"></div> <div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div> </div> <div id="p12warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()"> <div class="icon2" style="float:left;margin:7px"></div> <div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div> </div> <table cellpadding="0" cellspacing="0" style="width:100%;padding:0px;padding:0px;margin-top:0px"> <tr> <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0"> <div style="float:right;text-align:right"> <input id="termActionsBtn" type="button" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()" style="margin-right:3px"> </div> <div> <input type="button" id="autoconnectbutton2" value="AutoConnect" onclick="autoConnectTerminal(event)" onkeypress="return false" onkeydown="return false" style="display:none"> <span id="connectbutton2span"> <input type="button" id="connectbutton2" value="Connect" onclick="connectTerminal(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span> <span id="connectbutton2hspan"> <input type="button" id="connectbutton2h" value="HW Connect" onclick="connectTerminal(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span> <span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick="connectTerminal(event,0)" onkeypress="return false" onkeydown="return false"></span> <span id="termstatus">Disconnected</span> </div> </td> </tr> <tr> <td> <div style="background-color:gray"><div id="termprogressbar" style="height:2px;width:0%;background-color:red"></div></div> </td> </tr> <tr> <td style="background:black;text-align:center;height:500px;position:relative"> <pre id="Term" style="background:black;margin:0;padding:0"></pre> </td> </tr> <tr> <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0"> <div style="float:right;text-align:right"> <span id="terminalSettingsButtons" style="display:none"> <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()"> <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()"> <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()"> </span> <select id="specialkeylist" onkeypress="return false" style="margin-left:5px"></select> <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()"> </div> <div> <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')"> <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')"> <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')"> <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')"> <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()"> </div> </td> </tr> </table> </div> <div id="p13" style="display:none"> <div id="p13title"> <div id="p13BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>Files - <span id="p13deviceName"></span></h1> </div> <table id="p13toolbar" style="width:100%" cellpadding="0" cellspacing="0"> <tr> <td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px"> <div style="float:right;text-align:right"> <input id="filesActionsBtn" type="button" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()" style="margin-right:3px"> </div> <div> <input id="p13AutoConnect" value="AutoConnect" onclick="autoConnectFiles(event)" onkeypress="return false" onkeydown="return false" type="button" style="display:none"> <input id="p13Connect" value="Connect" onclick="connectFiles(event)" onkeypress="return false" onkeydown="return false" type="button"> <span id="p13Status">Disconnected</span> </div> </td> </tr> <tr> <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom"> <div id="p13rightOfButtons" style="float:right;margin-top:3px"></div> <div> <input type="button" id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="Up"> <input type="button" id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13RenameFileButton" disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13DeleteFileButton" disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13NewFolderButton" disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13UploadButton" disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13CutButton" disabled="disabled" value="Cut" onclick="p13copyFile(1)" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13CopyButton" disabled="disabled" value="Copy" onclick="p13copyFile(0)" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13PasteButton" disabled="disabled" value="Paste" onclick="p13pasteFile()" onkeypress="return false" onkeydown="return false"> <input type="button" id="p13RefreshButton" disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false"> </div> </td> </tr> <tr> <td style="background-color:#E4E9E7;height:28px"> <div style="float:right"> <select id="p13sortdropdown" onchange="p13updateFiles()"> <option value="1" selected="selected">Sort by name <option value="2">Sort by size <option value="3">Sort by date <option value="4">Descend by name <option value="5">Descend by size <option value="6">Descend by date </select> </div> <div> <span id="p13currentpath"></span></div> </td> </tr> </table> <div id="p13filetable" style="width:100%;height:calc(100vh - 346px);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%" cellpadding="0" cellspacing="0"> <tr><td class="style6" style="text-align:left;padding:3px"> <span id="p13bottomstatus"></span></td></tr> </table> </div> <div id="p14" style="display:none"> <div id="p14title"> <div id="p14BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>Intel® AMT - <span id="p14deviceName"></span></h1> </div> <iframe id="p14iframe" style="width:100%;height:calc(100vh - 242px);border:0;overflow:hidden" src="/commander.htm"></iframe> </div> <div id="p15" style="display:none"> <div id="p15title"> <div id="p15BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1><span id="p15deviceName"></span></h1> </div> <table cellpadding="0" cellspacing="0" style="width:100%;padding:0px;padding:0px;margin-top:0px"> <tr> <td style="background:#C0C0C0"> <div style="float:right;padding-right:4px"> <div style="padding:4px;display:inline-block" id="p15coreName" title="Information about current core running on this agent"></div> <input type="button" id="p15uploadCore" value="Agent Action" onclick="p15uploadCore(event)" title="Change the agent Java Script code module"> </div> <div id="p15statetext" style="padding:4px"></div> </td> </tr> <tr> <td> <div style="background-color:gray"><div id="consoleprogressbar" style="height:2px;width:0%;background-color:red"></div></div> </td> </tr> <tr> <td id="p15agentConsole" style="background:black;margin:0;padding:0;color:lightgray;width:100%;height:calc(100vh - 296px);max-height:500px;position:relative"> <pre id="p15agentConsoleText" style="position:absolute;margin:0;padding:0;top:0;bottom:0;left:0;right:0;overflow-y:scroll;overflow-x:auto"></pre> </td> </tr> <tr> <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0"> <table style="width:100%"> <tr> <td style="width:99%"> <input id="p15consoleText" style="width:100%" onkeyup="p15consoleSend(event)" onfocus="onConsoleFocus(1)" onblur="onConsoleFocus(0)"> </td> <td> </td> <td style="width:1%"><input id="id_p15consoleClear" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td> </tr> </table> </td> </tr> </table> </div> <div id="p16" style="display:none"> <div id="p16title"> <div id="p16BackButton" style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>Events - <span id="p16deviceName"></span></h1> </div> <div style="width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px"> <div class="style7" style="width:16px;height:100%;float:left"> </div> <div class="h1" style="height:100%;float:left"> </div> <div class="style14" style="height:100%;float:left"> <input type="button" value="Refresh" onclick="refreshDeviceEvents()"> </div> <div class="auto-style1" style="height:100%;float:right"> Show <select id="p16limitdropdown" onchange="refreshDeviceEvents()"> <option value="60">Last 60 <option value="120">Last 120 <option value="250">Last 250 <option value="500">Last 500 <option value="1000">Last 1000 </select> <div style="height:100%;width:20px;float:right;background-color:#ffffff"></div> <div class="h2" style="height:100%;float:right"> </div> </div> </div> <div id="p16events" style="max-height:calc(100vh - 267px);overflow-y:auto"></div> </div> <div id="p20" style="display:none"> <picture id="MainMeshImage" style="border-width:0px;height:200px;width:200px;float:right"> <source type="image/webp" width="200" height="200" srcset="images/webp/mesh-200.webp"> <img alt="" width="200" height="200" src="images/mesh-200.jpg"> </source></picture> <div style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>General - <span id="p20meshName"></span></h1> <p id="p20info"> </div> <div id="p30" style="display:none"> <table style="width:100%" cellpadding="0" cellspacing="0"> <tr> <td style="width:auto" valign="top"> <div id="p30title"> <div style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>General - <span id="p30userName"></span></h1> </div> <div id="p30html"></div> </td> <td style="width:20px"></td> <td style="width:200px"> <picture id="MainUserImage" style="border-width:0px;height:200px;width:200px;float:right"> <source type="image/webp" width="200" height="200" srcset="images/webp/user-200.webp"> <img alt="" width="200" height="200" src="images/user-200.jpg"> </source></picture> <div style="width:100%;text-align:center"><strong><span id="MainUserState"></span></strong></div> </td> </tr> </table><br> <div id="p30html2"></div> <div id="p30html3"></div> </div> <div id="p31" style="display:none"> <div style="float:left"><div class="backButton" onclick="goBack()" title="Back"><div class="backButtonEx"></div></div></div> <h1>Events - <span id="p31userName"></span></h1> <div style="width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px"> <div class="style7" style="width:16px;height:100%;float:left"> </div> <div class="h1" style="height:100%;float:left"> </div> <div class="style14" style="height:100%;float:left"> <input type="button" value="Refresh" onclick="refreshUsersEvents()"> </div> <div class="auto-style1" style="height:100%;float:right"> Show <select id="p31limitdropdown" onchange="refreshUsersEvents()"> <option value="60">Last 60 <option value="120">Last 120 <option value="250">Last 250 <option value="500">Last 500 <option value="1000">Last 1000 </select> <div style="height:100%;width:20px;float:right;background-color:#ffffff"></div> <div class="h2" style="height:100%;float:right;"> </div> </div> </div> <div id="p31events" style="max-height:calc(100vh - 267px);overflow-y:scroll"></div> </div> <br id="column_l_bottomgap"> </div> <div id="footer" class="noselect"> <table cellpadding="0" cellspacing="10" style="width:100%"> <tr> <td style="text-align:left;color:white"> {{{footer}}} </td> <td style="text-align:right"> <a id="verifyEmailId2" style="color:yellow;margin-left:3px;cursor:pointer;display:none" onclick="account_showVerifyEmail()">Verify Email</a> <a style="margin-left:3px" href="terms">Terms & Privacy</a> </td> </tr> </table> </div> <div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:160px;width:400px;left:calc((100% / 2) - 200px);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:3px;margin-right:3px;cursor:pointer" onclick="setDialogMode()">✖</div> <div id="id_dialogtitle" style="padding:5px"></div> <div style="width:100%;margin:6px"></div> </div> <div style="margin-right:16px;margin-left:8px"> <div id="dialog1" style="margin:auto;text-align:center;margin:3px"> <div id="id_dialogMessage" style="padding:10px"></div> </div> <div id="dialog2" style="margin:auto;margin:3px"> <div id="id_dialogOptions"></div> </div> <div id="dialog3" style="margin:auto;margin:3px"> <div style="height:26px"> <select id="d3uploadMode" style="float:right;width:260px" onchange="d3modechange()"> <option value="1">Local file upload <option value="2">Server file selection </select> <div>File Selection</div> </div> <div id="d3localmode" style="height:26px;display:none"> <form id="d3localmodeform" method="post" enctype="multipart/form-data" action="uploadfile.ashx" target="fileUploadFrame"> <input type="text" id="d3attrib" name="attrib" style="display:none"> <input type="file" id="d3localFile" name="files" style="float:right;width:260px" onchange="d3setActions()"> <input type="submit" id="d3submit" style="display:none"> </form> <div>Upload File</div> </div> <div id="d3servermode"> <div style="width:100%;background-color:#d3d9d6;text-align:left;padding:3px" valign="bottom"> <input type="button" id="p3FolderUp" disabled="disabled" onclick="d3folderup()" value="Up"> </div> <div id="d3serverfiles" style="width:100%;height:150px;background-color:white;padding:2px;border:1px solid gray;overflow-y:scroll"></div> </div> </div> <div id="dialog7" style="margin:auto;margin:3px"> <div id="d7meshkvm"> <h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4> <div style="margin:3px 0 3px 0"> <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select> <div style="height:20px">Quality</div> </div> <div style="margin:3px 0 3px 0"> <select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl"> <option selected="selected" value="1024">100% <option value="896">87.5% <option value="768">75% <option value="640">62.5% <option value="512">50% <option value="384">37.5% <option value="256">25% <option value="128">12.5% </select> <div style="height:20px">Scaling</div> </div> <div style="margin:3px 0 3px 0"> <select id="d7framelimiter" style="float:right;width:200px;height:20px" dir="rtl"> <option selected="selected" value="50">Fast <option value="100">Medium <option value="400">Slow <option value="1000">Very slow </select> <div style="height:20px">Frame rate</div> </div> </div> <div id="d7amtkvm"> <h4 style="width:100%;border-bottom:1px solid gray">Intel® AMT Hardware KVM</h4> <div style='height:26px'> <select id="d7desktopmode" style="float:right;width:200px"> <option value="1">RLE8, Fastest <option value="2">RLE16, Recommended <option value="3">RAW8, Slow <option value="4">RAW16, Very Slow </select> <div>Image Encoding</div> </div> <div style="height:60px"> <div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white"> <label><input type="checkbox" id='d7showfocus'>Show Focus Tool<br></label> <label><input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br></label> <label><input type="checkbox" id='d7localKeyMap'>Local Keyboard Map<br></label> </div> <div>Other Settings</div> </div> </div> </div> </div> <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:4px"> <input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)"> <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)"> <div style="height:25px"><input id="idx_dlgDeleteButton" type="button" value="Delete" style="width:80px;display:none" onclick="dialogclose(2)"></div> </div> </div> <iframe name="fileUploadFrame" style="display:none"></iframe> <form style="display:none" method="post" action="uploadfile.ashx" enctype="multipart/form-data" target="fileUploadFrame"><input id="p5fileDragName" name="name"><input id="p5fileDragSize" name="size"><input id="p5fileDragType" name="type"><input id="p5fileDragData" name="data"><input id="p5fileDragLink" name="link"><input type="submit" id="p5loginSubmit2" style="display:none"></form> <form style="display:none" method="post" action="uploadnodefile.ashx" enctype="multipart/form-data" target="fileUploadFrame"><input id="p13fileDragName" name="name"><input id="p13fileDragSize" name="size"><input id="p13fileDragType" name="type"><input id="p13fileDragData" name="data"><input id="p13fileDragLink" name="link"><input type="submit" id="p13loginSubmit2" style="display:none"></form> <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></source></audio> </div> </div> <script>/**
|
||
* @description Set of short commonly used methods for handling HTML elements
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.1b
|
||
*/
|
||
|
||
// Add startsWith for IE browser
|
||
if (!String.prototype.startsWith) { String.prototype.startsWith = function (str) { return this.lastIndexOf(str, 0) === 0; }; }
|
||
if (!String.prototype.endsWith) { String.prototype.endsWith = function (str) { return this.indexOf(str, this.length - str.length) !== -1; }; }
|
||
|
||
// Quick UI functions, a bit of a replacement for jQuery
|
||
//function Q(x) { if (document.getElementById(x) == null) { console.log('Invalid element: ' + x); } return document.getElementById(x); } // "Q"
|
||
function Q(x) { return document.getElementById(x); } // "Q"
|
||
function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style
|
||
function QE(x, y) { try { Q(x).disabled = !y; } catch (x) { } } // "Q" enable
|
||
function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (x) { } } // "Q" visible
|
||
function QA(x, y) { Q(x).innerHTML += y; } // "Q" append
|
||
function QH(x, y) { Q(x).innerHTML = y; } // "Q" html
|
||
|
||
// Move cursor to end of input box
|
||
function inputBoxFocus(x) { Q(x).focus(); var v = Q(x).value; Q(x).value = ''; Q(x).value = v; }
|
||
|
||
// Binary encoding and decoding functions
|
||
function ReadShort(v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); }
|
||
function ReadShortX(v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
|
||
function ReadInt(v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
|
||
function ReadSInt(v, p) { return (v.charCodeAt(p) << 24) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }
|
||
function ReadIntX(v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
|
||
function ShortToStr(v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); }
|
||
function ShortToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
|
||
function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
|
||
function IntToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
|
||
function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
|
||
function SplitArray(v) { return v.split(','); }
|
||
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
|
||
function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||
function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||
|
||
// Move an element from one position in an array to a new position
|
||
function ArrayElementMove(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
|
||
|
||
// Print object for HTML
|
||
function ObjectToStringEx(x, c) {
|
||
var r = "";
|
||
if (x != 0 && (!x || x == null)) return "(Null)";
|
||
if (x instanceof Array) { for (var i in x) { r += '<br />' + gap(c) + "Item #" + i + ": " + ObjectToStringEx(x[i], c + 1); } }
|
||
else if (x instanceof Object) { for (var i in x) { r += '<br />' + gap(c) + i + " = " + ObjectToStringEx(x[i], c + 1); } }
|
||
else { r += EscapeHtml(x); }
|
||
return r;
|
||
}
|
||
|
||
// Print object for console
|
||
function ObjectToStringEx2(x, c) {
|
||
var r = "";
|
||
if (x != 0 && (!x || x == null)) return "(Null)";
|
||
if (x instanceof Array) { for (var i in x) { r += '\r\n' + gap2(c) + "Item #" + i + ": " + ObjectToStringEx2(x[i], c + 1); } }
|
||
else if (x instanceof Object) { for (var i in x) { r += '\r\n' + gap2(c) + i + " = " + ObjectToStringEx2(x[i], c + 1); } }
|
||
else { r += EscapeHtml(x); }
|
||
return r;
|
||
}
|
||
|
||
// Create an ident gap
|
||
function gap(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += ' '; } return x; }
|
||
function gap2(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += ' '; } return x; }
|
||
|
||
// Print an object in html
|
||
function ObjectToString(x) { return ObjectToStringEx(x, 0); }
|
||
function ObjectToString2(x) { return ObjectToStringEx2(x, 0); }
|
||
|
||
// Convert a hex string to a raw string
|
||
function hex2rstr(d) {
|
||
if (typeof d != "string" || d.length == 0) return '';
|
||
var r = '', m = ('' + d).match(/../g), t;
|
||
while (t = m.shift()) r += String.fromCharCode('0x' + t);
|
||
return r
|
||
}
|
||
|
||
// Convert decimal to hex
|
||
function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
|
||
|
||
// Convert a raw string to a hex string
|
||
function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }
|
||
|
||
// UTF-8 encoding & decoding functions
|
||
function encode_utf8(s) { return unescape(encodeURIComponent(s)); }
|
||
function decode_utf8(s) { return decodeURIComponent(escape(s)); }
|
||
|
||
// Convert a string into a blob
|
||
function data2blob(data) {
|
||
var bytes = new Array(data.length);
|
||
for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
|
||
var blob = new Blob([new Uint8Array(bytes)]);
|
||
return blob;
|
||
}
|
||
|
||
// Generate random numbers
|
||
function random(max) { return Math.floor(Math.random() * max); }
|
||
|
||
// Trademarks
|
||
function trademarks(x) { return x.replace(/\(R\)/g, '®').replace(/\(TM\)/g, '™'); }
|
||
/**
|
||
* @fileoverview Meshcentral.js
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.1
|
||
*/
|
||
|
||
var MeshServerCreateControl = function (domain, authCookie) {
|
||
var obj = {};
|
||
obj.State = 0;
|
||
obj.connectstate = 0;
|
||
obj.pingTimer = null;
|
||
obj.authCookie = authCookie;
|
||
|
||
obj.xxStateChange = function (newstate, errCode) {
|
||
if (obj.State == newstate) return;
|
||
var previousState = obj.State;
|
||
obj.State = newstate;
|
||
if (obj.onStateChanged) obj.onStateChanged(obj, obj.State, previousState, errCode);
|
||
}
|
||
|
||
obj.Start = function () {
|
||
if (obj.connectstate != 0) return;
|
||
obj.connectstate = 0;
|
||
var url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + domain + "control.ashx";
|
||
if (obj.authCookie && (obj.authCookie != '')) { url += '?auth=' + obj.authCookie; }
|
||
obj.socket = new WebSocket(url);
|
||
obj.socket.onopen = function (e) { obj.connectstate = 1; }
|
||
obj.socket.onmessage = obj.xxOnMessage;
|
||
obj.socket.onclose = function(e) { obj.Stop(e.code); }
|
||
obj.xxStateChange(1, 0);
|
||
if (obj.pingTimer != null) { clearInterval(obj.pingTimer); }
|
||
obj.pingTimer = setInterval(function () { obj.send({ action: 'ping' }); }, 29000); // Ping the server every 29 seconds, stops corporate proxies from disconnecting.
|
||
}
|
||
|
||
obj.Stop = function (errCode) {
|
||
obj.connectstate = 0;
|
||
if (obj.socket) { obj.socket.close(); delete obj.socket; }
|
||
if (obj.pingTimer != null) { clearInterval(obj.pingTimer); obj.pingTimer = null; }
|
||
obj.xxStateChange(0, errCode);
|
||
}
|
||
|
||
obj.xxOnMessage = function (e) {
|
||
if (obj.State == 1) { obj.xxStateChange(2); }
|
||
//console.log('xxOnMessage', e.data);
|
||
var message;
|
||
try { message = JSON.parse(e.data); } catch (e) { return; }
|
||
if ((typeof message != 'object') || (message.action == 'pong')) { return; }
|
||
if (message.action == 'close') { if (message.msg) { console.log(message.msg); } obj.Stop(message.cause); return; }
|
||
if (obj.onMessage) obj.onMessage(obj, message);
|
||
};
|
||
|
||
obj.send = function (x) { if (obj.socket != null && obj.connectstate == 1) { obj.socket.send(JSON.stringify(x)); } }
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @fileoverview Intel(r) AMT Communication Stack
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.2.0b
|
||
*/
|
||
|
||
/**
|
||
* Construct a AmtStackCreateService object, this ia the main Intel AMT communication stack.
|
||
* @constructor
|
||
*/
|
||
function AmtStackCreateService(wsmanStack) {
|
||
var obj = new Object();
|
||
obj.wsman = wsmanStack;
|
||
obj.pfx = ["http://intel.com/wbem/wscim/1/amt-schema/1/", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/", "http://intel.com/wbem/wscim/1/ips-schema/1/"];
|
||
obj.PendingEnums = [];
|
||
obj.PendingBatchOperations = 0;
|
||
obj.ActiveEnumsCount = 0;
|
||
obj.MaxActiveEnumsCount = 1; // Maximum number of enumerations that can be done at the same time.
|
||
obj.onProcessChanged = null;
|
||
var _MaxProcess = 0;
|
||
var _LastProcess = 0;
|
||
|
||
// Return the number of pending actions
|
||
obj.GetPendingActions = function () { return (obj.PendingEnums.length * 2) + (obj.ActiveEnumsCount) + obj.wsman.comm.PendingAjax.length + obj.wsman.comm.ActiveAjaxCount + obj.PendingBatchOperations; }
|
||
|
||
// Private Method, Update the current processing status, this gives the application an idea of what progress is being done by the WSMAN stack
|
||
function _up() {
|
||
var x = obj.GetPendingActions();
|
||
if (_MaxProcess < x) _MaxProcess = x;
|
||
if (obj.onProcessChanged != null && _LastProcess != x) {
|
||
//console.log("Process Old=" + _LastProcess + ", New=" + x + ", PEnums=" + obj.PendingEnums.length + ", AEnums=" + obj.ActiveEnumsCount + ", PAjax=" + obj.wsman.comm.PendingAjax.length + ", AAjax=" + obj.wsman.comm.ActiveAjaxCount + ", PBatch=" + obj.PendingBatchOperations);
|
||
_LastProcess = x;
|
||
obj.onProcessChanged(x, _MaxProcess);
|
||
}
|
||
if (x == 0) _MaxProcess = 0;
|
||
}
|
||
|
||
// Perform a WSMAN "SUBSCRIBE" operation.
|
||
obj.Subscribe = function (name, delivery, url, callback, tag, pri, selectors, opaque, user, pass) { obj.wsman.ExecSubscribe(obj.CompleteName(name), delivery, url, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors, opaque, user, pass); _up(); }
|
||
|
||
// Perform a WSMAN "UNSUBSCRIBE" operation.
|
||
obj.UnSubscribe = function (name, callback, tag, pri, selectors) { obj.wsman.ExecUnSubscribe(obj.CompleteName(name), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors); _up(); }
|
||
|
||
// Perform a WSMAN "GET" operation.
|
||
obj.Get = function (name, callback, tag, pri) { obj.wsman.ExecGet(obj.CompleteName(name), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
|
||
|
||
// Perform a WSMAN "PUT" operation.
|
||
obj.Put = function (name, putobj, callback, tag, pri, selectors) { obj.wsman.ExecPut(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors); _up(); }
|
||
|
||
// Perform a WSMAN "CREATE" operation.
|
||
obj.Create = function (name, putobj, callback, tag, pri) { obj.wsman.ExecCreate(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
|
||
|
||
// Perform a WSMAN "DELETE" operation.
|
||
obj.Delete = function (name, putobj, callback, tag, pri) { obj.wsman.ExecDelete(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
|
||
|
||
// Perform a WSMAN method call operation.
|
||
obj.Exec = function (name, method, args, callback, tag, pri, selectors) { obj.wsman.ExecMethod(obj.CompleteName(name), method, args, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, obj.CompleteExecResponse(response), xstatus, tag); }, 0, pri, selectors); _up(); }
|
||
|
||
// Perform a WSMAN method call operation.
|
||
obj.ExecWithXml = function (name, method, args, callback, tag, pri, selectors) { obj.wsman.ExecMethodXml(obj.CompleteName(name), method, execArgumentsToXml(args), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, obj.CompleteExecResponse(response), xstatus, tag); }, 0, pri, selectors); _up(); }
|
||
|
||
// Perform a WSMAN "ENUMERATE" operation.
|
||
obj.Enum = function (name, callback, tag, pri) {
|
||
if (obj.ActiveEnumsCount < obj.MaxActiveEnumsCount) {
|
||
obj.ActiveEnumsCount++; obj.wsman.ExecEnum(obj.CompleteName(name), function (ws, resuri, response, xstatus, tag0) { _up(); _EnumStartSink(name, response, callback, resuri, xstatus, tag0); }, tag, pri);
|
||
} else {
|
||
obj.PendingEnums.push([name, callback, tag, pri]);
|
||
}
|
||
_up();
|
||
}
|
||
|
||
// Private method
|
||
function _EnumStartSink(name, response, callback, resuri, status, tag, pri) {
|
||
if (status != 200) { callback(obj, name, null, status, tag); _EnumDoNext(1); return; }
|
||
if (response == null || response.Header["Method"] != "EnumerateResponse" || !response.Body["EnumerationContext"]) { callback(obj, name, null, 603, tag); _EnumDoNext(1); return; }
|
||
var enumctx = response.Body["EnumerationContext"];
|
||
obj.wsman.ExecPull(resuri, enumctx, function (ws, resuri, response, xstatus) { _EnumContinueSink(name, response, callback, resuri, [], xstatus, tag, pri); });
|
||
}
|
||
|
||
// Private method
|
||
function _EnumContinueSink(name, response, callback, resuri, items, status, tag, pri) {
|
||
if (status != 200) { callback(obj, name, null, status, tag); _EnumDoNext(1); return; }
|
||
if (response == null || response.Header["Method"] != "PullResponse") { callback(obj, name, null, 604, tag); _EnumDoNext(1); return; }
|
||
for (var i in response.Body["Items"]) {
|
||
if (response.Body["Items"][i] instanceof Array) {
|
||
for (var j in response.Body["Items"][i]) { items.push(response.Body["Items"][i][j]); }
|
||
} else {
|
||
items.push(response.Body["Items"][i]);
|
||
}
|
||
}
|
||
if (response.Body["EnumerationContext"]) {
|
||
var enumctx = response.Body["EnumerationContext"];
|
||
obj.wsman.ExecPull(resuri, enumctx, function (ws, resuri, response, xstatus) { _EnumContinueSink(name, response, callback, resuri, items, xstatus, tag, 1); });
|
||
} else {
|
||
_EnumDoNext(1);
|
||
callback(obj, name, items, status, tag);
|
||
_up();
|
||
}
|
||
}
|
||
|
||
// Private method
|
||
function _EnumDoNext(dec) {
|
||
obj.ActiveEnumsCount -= dec;
|
||
if (obj.ActiveEnumsCount >= obj.MaxActiveEnumsCount || obj.PendingEnums.length == 0) return;
|
||
var x = obj.PendingEnums.shift();
|
||
obj.Enum(x[0], x[1], x[2]);
|
||
_EnumDoNext(0);
|
||
}
|
||
|
||
// Perform a batch of WSMAN "ENUM" operations.
|
||
obj.BatchEnum = function (batchname, names, callback, tag, continueOnError, pri) {
|
||
obj.PendingBatchOperations += (names.length * 2);
|
||
_BatchNextEnum(batchname, Clone(names), callback, tag, {}, continueOnError, pri); _up();
|
||
}
|
||
|
||
// Request each enum in the batch, stopping if something does not return status 200
|
||
function _BatchNextEnum(batchname, names, callback, tag, results, continueOnError, pri) {
|
||
obj.PendingBatchOperations -= 2;
|
||
var n = names.shift(), f = obj.Enum;
|
||
if (n[0] == '*') { f = obj.Get; n = n.substring(1); } // If the name starts with a star, do a GET instead of an ENUM. This will reduce round trips.
|
||
//console.log((f == obj.Get?'Get ':'Enum ') + n);
|
||
// Perform a GET/ENUM action
|
||
f(n, function (stack, name, responses, status, tag0) {
|
||
tag0[2][name] = { response: (responses==null?null:responses.Body), responses: responses, status: status };
|
||
if (tag0[1].length == 0 || status == 401 || (continueOnError != true && status != 200 && status != 400)) { obj.PendingBatchOperations -= (names.length * 2); _up(); callback(obj, batchname, tag0[2], status, tag); }
|
||
else { _up(); _BatchNextEnum(batchname, names, callback, tag, tag0[2], pri); }
|
||
}, [batchname, names, results], pri);
|
||
_up();
|
||
}
|
||
|
||
// Perform a batch of WSMAN "GET" operations.
|
||
obj.BatchGet = function (batchname, names, callback, tag, pri) {
|
||
_FetchNext({ name: batchname, names: names, callback: callback, current: 0, responses: {}, tag: tag, pri: pri }); _up();
|
||
}
|
||
|
||
// Private method
|
||
function _FetchNext(batch) {
|
||
if (batch.names.length <= batch.current) {
|
||
batch.callback(obj, batch.name, batch.responses, 200, batch.tag);
|
||
} else {
|
||
obj.wsman.ExecGet(obj.CompleteName(batch.names[batch.current]), function (ws, resuri, response, xstatus) { _Fetched(batch, response, xstatus); }, batch.pri);
|
||
batch.current++;
|
||
}
|
||
_up();
|
||
}
|
||
|
||
// Private method
|
||
function _Fetched(batch, response, status) {
|
||
if (response == null || status != 200) {
|
||
batch.callback(obj, batch.name, null, status, batch.tag);
|
||
} else {
|
||
batch.responses[response.Header["Method"]] = response;
|
||
_FetchNext(batch);
|
||
}
|
||
}
|
||
|
||
// Private method
|
||
obj.CompleteName = function(name) {
|
||
if (name.indexOf("AMT_") == 0) return obj.pfx[0] + name;
|
||
if (name.indexOf("CIM_") == 0) return obj.pfx[1] + name;
|
||
if (name.indexOf("IPS_") == 0) return obj.pfx[2] + name;
|
||
}
|
||
|
||
obj.CompleteExecResponse = function (resp) {
|
||
if (resp && resp != null && resp.Body && resp.Body["ReturnValue"]) resp.Body.ReturnValueStr = obj.AmtStatusToStr(resp.Body["ReturnValue"]);
|
||
return resp;
|
||
}
|
||
|
||
obj.RequestPowerStateChange = function (PowerState, callback_func) {
|
||
obj.CIM_PowerManagementService_RequestPowerStateChange(PowerState, "<Address xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><ResourceURI xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</ResourceURI><SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\"><Selector Name=\"CreationClassName\">CIM_ComputerSystem</Selector><Selector Name=\"Name\">ManagedSystem</Selector></SelectorSet></ReferenceParameters>", null, null, callback_func);
|
||
}
|
||
|
||
obj.SetBootConfigRole = function (Role, callback_func) {
|
||
obj.CIM_BootService_SetBootConfigRole("<Address xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><ResourceURI xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootConfigSetting</ResourceURI><SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\"><Selector Name=\"InstanceID\">Intel(r) AMT: Boot Configuration 0</Selector></SelectorSet></ReferenceParameters>", Role, callback_func);
|
||
}
|
||
|
||
// Cancel all pending queries with given status
|
||
obj.CancelAllQueries = function (s) {
|
||
obj.wsman.CancelAllQueries(s);
|
||
}
|
||
|
||
// Auto generated methods
|
||
obj.AMT_AgentPresenceWatchdog_RegisterAgent = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "RegisterAgent", {}, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdog_AssertPresence = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertPresence", { "SequenceNumber": SequenceNumber }, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdog_AssertShutdown = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertShutdown", { "SequenceNumber": SequenceNumber }, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdog_AddAction = function (OldState, NewState, EventOnTransition, ActionSd, ActionEac, callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "AddAction", { "OldState": OldState, "NewState": NewState, "EventOnTransition": EventOnTransition, "ActionSd": ActionSd, "ActionEac": ActionEac }, callback_func, tag, pri, selectors); }
|
||
obj.AMT_AgentPresenceWatchdog_DeleteAllActions = function (callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "DeleteAllActions", {}, callback_func, tag, pri, selectors); }
|
||
obj.AMT_AgentPresenceWatchdogAction_GetActionEac = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdogAction", "GetActionEac", {}, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdogVA_RegisterAgent = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "RegisterAgent", {}, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdogVA_AssertPresence = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AssertPresence", { "SequenceNumber": SequenceNumber }, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdogVA_AssertShutdown = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AssertShutdown", { "SequenceNumber": SequenceNumber }, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdogVA_AddAction = function (OldState, NewState, EventOnTransition, ActionSd, ActionEac, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AddAction", { "OldState": OldState, "NewState": NewState, "EventOnTransition": EventOnTransition, "ActionSd": ActionSd, "ActionEac": ActionEac }, callback_func); }
|
||
obj.AMT_AgentPresenceWatchdogVA_DeleteAllActions = function (_method_dummy, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "DeleteAllActions", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_AuditLog_ClearLog = function (callback_func) { obj.Exec("AMT_AuditLog", "ClearLog", {}, callback_func); }
|
||
obj.AMT_AuditLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_AuditLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.AMT_AuditLog_ReadRecords = function (StartIndex, callback_func, tag) { obj.Exec("AMT_AuditLog", "ReadRecords", { "StartIndex": StartIndex }, callback_func, tag); }
|
||
obj.AMT_AuditLog_SetAuditLock = function (LockTimeoutInSeconds, Flag, Handle, callback_func) { obj.Exec("AMT_AuditLog", "SetAuditLock", { "LockTimeoutInSeconds": LockTimeoutInSeconds, "Flag": Flag, "Handle": Handle }, callback_func); }
|
||
obj.AMT_AuditLog_ExportAuditLogSignature = function (SigningMechanism, callback_func) { obj.Exec("AMT_AuditLog", "ExportAuditLogSignature", { "SigningMechanism": SigningMechanism }, callback_func); }
|
||
obj.AMT_AuditLog_SetSigningKeyMaterial = function (SigningMechanismType, SigningKey, LengthOfCertificates, Certificates, callback_func) { obj.Exec("AMT_AuditLog", "SetSigningKeyMaterial", { "SigningMechanismType": SigningMechanismType, "SigningKey": SigningKey, "LengthOfCertificates": LengthOfCertificates, "Certificates": Certificates }, callback_func); }
|
||
obj.AMT_AuditPolicyRule_SetAuditPolicy = function (Enable, AuditedAppID, EventID, PolicyType, callback_func) { obj.Exec("AMT_AuditPolicyRule", "SetAuditPolicy", { "Enable": Enable, "AuditedAppID": AuditedAppID, "EventID": EventID, "PolicyType": PolicyType }, callback_func); }
|
||
obj.AMT_AuditPolicyRule_SetAuditPolicyBulk = function (Enable, AuditedAppID, EventID, PolicyType, callback_func) { obj.Exec("AMT_AuditPolicyRule", "SetAuditPolicyBulk", { "Enable": Enable, "AuditedAppID": AuditedAppID, "EventID": EventID, "PolicyType": PolicyType }, callback_func); }
|
||
obj.AMT_AuthorizationService_AddUserAclEntryEx = function (DigestUsername, DigestPassword, KerberosUserSid, AccessPermission, Realms, callback_func) { obj.Exec("AMT_AuthorizationService", "AddUserAclEntryEx", { "DigestUsername": DigestUsername, "DigestPassword": DigestPassword, "KerberosUserSid": KerberosUserSid, "AccessPermission": AccessPermission, "Realms": Realms }, callback_func); }
|
||
obj.AMT_AuthorizationService_EnumerateUserAclEntries = function (StartIndex, callback_func) { obj.Exec("AMT_AuthorizationService", "EnumerateUserAclEntries", { "StartIndex": StartIndex }, callback_func); }
|
||
obj.AMT_AuthorizationService_GetUserAclEntryEx = function (Handle, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "GetUserAclEntryEx", { "Handle": Handle }, callback_func, tag); }
|
||
obj.AMT_AuthorizationService_UpdateUserAclEntryEx = function (Handle, DigestUsername, DigestPassword, KerberosUserSid, AccessPermission, Realms, callback_func) { obj.Exec("AMT_AuthorizationService", "UpdateUserAclEntryEx", { "Handle": Handle, "DigestUsername": DigestUsername, "DigestPassword": DigestPassword, "KerberosUserSid": KerberosUserSid, "AccessPermission": AccessPermission, "Realms": Realms }, callback_func); }
|
||
obj.AMT_AuthorizationService_RemoveUserAclEntry = function (Handle, callback_func) { obj.Exec("AMT_AuthorizationService", "RemoveUserAclEntry", { "Handle": Handle }, callback_func); }
|
||
obj.AMT_AuthorizationService_SetAdminAclEntryEx = function (Username, DigestPassword, callback_func) { obj.Exec("AMT_AuthorizationService", "SetAdminAclEntryEx", { "Username": Username, "DigestPassword": DigestPassword }, callback_func); }
|
||
obj.AMT_AuthorizationService_GetAdminAclEntry = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminAclEntry", {}, callback_func); }
|
||
obj.AMT_AuthorizationService_GetAdminAclEntryStatus = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminAclEntryStatus", {}, callback_func); }
|
||
obj.AMT_AuthorizationService_GetAdminNetAclEntryStatus = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminNetAclEntryStatus", {}, callback_func); }
|
||
obj.AMT_AuthorizationService_SetAclEnabledState = function (Handle, Enabled, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "SetAclEnabledState", { "Handle": Handle, "Enabled": Enabled }, callback_func, tag); }
|
||
obj.AMT_AuthorizationService_GetAclEnabledState = function (Handle, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "GetAclEnabledState", { "Handle": Handle }, callback_func, tag); }
|
||
obj.AMT_EndpointAccessControlService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.AMT_EndpointAccessControlService_GetPosture = function (PostureType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetPosture", { "PostureType": PostureType }, callback_func); }
|
||
obj.AMT_EndpointAccessControlService_GetPostureHash = function (PostureType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetPostureHash", { "PostureType": PostureType }, callback_func); }
|
||
obj.AMT_EndpointAccessControlService_UpdatePostureState = function (UpdateType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "UpdatePostureState", { "UpdateType": UpdateType }, callback_func); }
|
||
obj.AMT_EndpointAccessControlService_GetEacOptions = function (callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetEacOptions", {}, callback_func); }
|
||
obj.AMT_EndpointAccessControlService_SetEacOptions = function (EacVendors, PostureHashAlgorithm, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "SetEacOptions", { "EacVendors": EacVendors, "PostureHashAlgorithm": PostureHashAlgorithm }, callback_func); }
|
||
obj.AMT_EnvironmentDetectionSettingData_SetSystemDefensePolicy = function (Policy, callback_func) { obj.Exec("AMT_EnvironmentDetectionSettingData", "SetSystemDefensePolicy", { "Policy": Policy }, callback_func); }
|
||
obj.AMT_EnvironmentDetectionSettingData_EnableVpnRouting = function (Enable, callback_func) { obj.Exec("AMT_EnvironmentDetectionSettingData", "EnableVpnRouting", { "Enable": Enable }, callback_func); }
|
||
obj.AMT_EthernetPortSettings_SetLinkPreference = function (LinkPreference, Timeout, callback_func) { obj.Exec("AMT_EthernetPortSettings", "SetLinkPreference", { "LinkPreference": LinkPreference, "Timeout": Timeout }, callback_func); }
|
||
obj.AMT_HeuristicPacketFilterStatistics_ResetSelectedStats = function (SelectedStatistics, callback_func) { obj.Exec("AMT_HeuristicPacketFilterStatistics", "ResetSelectedStats", { "SelectedStatistics": SelectedStatistics }, callback_func); }
|
||
obj.AMT_KerberosSettingData_GetCredentialCacheState = function (callback_func) { obj.Exec("AMT_KerberosSettingData", "GetCredentialCacheState", {}, callback_func); }
|
||
obj.AMT_KerberosSettingData_SetCredentialCacheState = function (Enable, callback_func) { obj.Exec("AMT_KerberosSettingData", "SetCredentialCacheState", { "Enable": Enable }, callback_func); }
|
||
obj.AMT_MessageLog_CancelIteration = function (IterationIdentifier, callback_func) { obj.Exec("AMT_MessageLog", "CancelIteration", { "IterationIdentifier": IterationIdentifier }, callback_func); }
|
||
obj.AMT_MessageLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_MessageLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.AMT_MessageLog_ClearLog = function (callback_func) { obj.Exec("AMT_MessageLog", "ClearLog", { }, callback_func); }
|
||
obj.AMT_MessageLog_GetRecords = function (IterationIdentifier, MaxReadRecords, callback_func, tag) { obj.Exec("AMT_MessageLog", "GetRecords", { "IterationIdentifier": IterationIdentifier, "MaxReadRecords": MaxReadRecords }, callback_func, tag); }
|
||
obj.AMT_MessageLog_GetRecord = function (IterationIdentifier, PositionToNext, callback_func) { obj.Exec("AMT_MessageLog", "GetRecord", { "IterationIdentifier": IterationIdentifier, "PositionToNext": PositionToNext }, callback_func); }
|
||
obj.AMT_MessageLog_PositionAtRecord = function (IterationIdentifier, MoveAbsolute, RecordNumber, callback_func) { obj.Exec("AMT_MessageLog", "PositionAtRecord", { "IterationIdentifier": IterationIdentifier, "MoveAbsolute": MoveAbsolute, "RecordNumber": RecordNumber }, callback_func); }
|
||
obj.AMT_MessageLog_PositionToFirstRecord = function (callback_func, tag) { obj.Exec("AMT_MessageLog", "PositionToFirstRecord", {}, callback_func, tag); }
|
||
obj.AMT_MessageLog_FreezeLog = function (Freeze, callback_func) { obj.Exec("AMT_MessageLog", "FreezeLog", { "Freeze": Freeze }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_AddCRL = function (Url, SerialNumbers, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddCRL", { "Url": Url, "SerialNumbers": SerialNumbers }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_ResetCRLList = function (_method_dummy, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "ResetCRLList", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_AddCertificate = function (CertificateBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddCertificate", { "CertificateBlob": CertificateBlob }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_AddTrustedRootCertificate = function (CertificateBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddTrustedRootCertificate", { "CertificateBlob": CertificateBlob }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_AddKey = function (KeyBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddKey", { "KeyBlob": KeyBlob }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_GeneratePKCS10Request = function (KeyPair, DNName, Usage, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GeneratePKCS10Request", { "KeyPair": KeyPair, "DNName": DNName, "Usage": Usage }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_GeneratePKCS10RequestEx = function (KeyPair, SigningAlgorithm, NullSignedCertificateRequest, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GeneratePKCS10RequestEx", { "KeyPair": KeyPair, "SigningAlgorithm": SigningAlgorithm, "NullSignedCertificateRequest": NullSignedCertificateRequest }, callback_func); }
|
||
obj.AMT_PublicKeyManagementService_GenerateKeyPair = function (KeyAlgorithm, KeyLength, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GenerateKeyPair", { "KeyAlgorithm": KeyAlgorithm, "KeyLength": KeyLength }, callback_func); }
|
||
obj.AMT_RedirectionService_RequestStateChange = function (RequestedState, callback_func) { obj.Exec("AMT_RedirectionService", "RequestStateChange", { "RequestedState": RequestedState }, callback_func); }
|
||
obj.AMT_RedirectionService_TerminateSession = function (SessionType, callback_func) { obj.Exec("AMT_RedirectionService", "TerminateSession", { "SessionType": SessionType }, callback_func); }
|
||
obj.AMT_RemoteAccessService_AddMpServer = function (AccessInfo, InfoFormat, Port, AuthMethod, Certificate, Username, Password, CN, callback_func) { obj.Exec("AMT_RemoteAccessService", "AddMpServer", { "AccessInfo": AccessInfo, "InfoFormat": InfoFormat, "Port": Port, "AuthMethod": AuthMethod, "Certificate": Certificate, "Username": Username, "Password": Password, "CN": CN }, callback_func); }
|
||
obj.AMT_RemoteAccessService_AddRemoteAccessPolicyRule = function (Trigger, TunnelLifeTime, ExtendedData, MpServer, callback_func) { obj.Exec("AMT_RemoteAccessService", "AddRemoteAccessPolicyRule", { "Trigger": Trigger, "TunnelLifeTime": TunnelLifeTime, "ExtendedData": ExtendedData, "MpServer": MpServer }, callback_func); }
|
||
obj.AMT_RemoteAccessService_CloseRemoteAccessConnection = function (_method_dummy, callback_func) { obj.Exec("AMT_RemoteAccessService", "CloseRemoteAccessConnection", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_CommitChanges = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "CommitChanges", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_Unprovision = function (ProvisioningMode, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "Unprovision", { "ProvisioningMode": ProvisioningMode }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_PartialUnprovision = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "PartialUnprovision", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_ResetFlashWearOutProtection = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "ResetFlashWearOutProtection", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_ExtendProvisioningPeriod = function (Duration, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "ExtendProvisioningPeriod", { "Duration": Duration }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_SetMEBxPassword = function (Password, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "SetMEBxPassword", { "Password": Password }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_SetTLSPSK = function (PID, PPS, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "SetTLSPSK", { "PID": PID, "PPS": PPS }, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_GetProvisioningAuditRecord = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetProvisioningAuditRecord", {}, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_GetUuid = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetUuid", {}, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_GetUnprovisionBlockingComponents = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetUnprovisionBlockingComponents", {}, callback_func); }
|
||
obj.AMT_SetupAndConfigurationService_GetProvisioningAuditRecordV2 = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetProvisioningAuditRecordV2", {}, callback_func); }
|
||
obj.AMT_SystemDefensePolicy_GetTimeout = function (callback_func) { obj.Exec("AMT_SystemDefensePolicy", "GetTimeout", {}, callback_func); }
|
||
obj.AMT_SystemDefensePolicy_SetTimeout = function (Timeout, callback_func) { obj.Exec("AMT_SystemDefensePolicy", "SetTimeout", { "Timeout": Timeout }, callback_func); }
|
||
obj.AMT_SystemDefensePolicy_UpdateStatistics = function (NetworkInterface, ResetOnRead, callback_func, tag, pri, selectors) { obj.Exec("AMT_SystemDefensePolicy", "UpdateStatistics", { "NetworkInterface": NetworkInterface, "ResetOnRead": ResetOnRead }, callback_func, tag, pri, selectors); }
|
||
obj.AMT_SystemPowerScheme_SetPowerScheme = function (callback_func, schemeInstanceId, tag) { obj.Exec("AMT_SystemPowerScheme", "SetPowerScheme", {}, callback_func, tag, 0, { "InstanceID": schemeInstanceId }); }
|
||
obj.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch = function (callback_func, tag) { obj.Exec("AMT_TimeSynchronizationService", "GetLowAccuracyTimeSynch", {}, callback_func, tag); }
|
||
obj.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch = function (Ta0, Tm1, Tm2, callback_func, tag) { obj.Exec("AMT_TimeSynchronizationService", "SetHighAccuracyTimeSynch", { "Ta0": Ta0, "Tm1": Tm1, "Tm2": Tm2 }, callback_func, tag); }
|
||
obj.AMT_UserInitiatedConnectionService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_UserInitiatedConnectionService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.AMT_WebUIService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_WebUIService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.AMT_WiFiPortConfigurationService_AddWiFiSettings = function (WiFiEndpoint, WiFiEndpointSettingsInput, IEEE8021xSettingsInput, ClientCredential, CACredential, callback_func) { obj.ExecWithXml("AMT_WiFiPortConfigurationService", "AddWiFiSettings", { "WiFiEndpoint": WiFiEndpoint, "WiFiEndpointSettingsInput": WiFiEndpointSettingsInput, "IEEE8021xSettingsInput": IEEE8021xSettingsInput, "ClientCredential": ClientCredential, "CACredential": CACredential }, callback_func); }
|
||
obj.AMT_WiFiPortConfigurationService_UpdateWiFiSettings = function (WiFiEndpointSettings, WiFiEndpointSettingsInput, IEEE8021xSettingsInput, ClientCredential, CACredential, callback_func) { obj.ExecWithXml("AMT_WiFiPortConfigurationService", "UpdateWiFiSettings", { "WiFiEndpointSettings": WiFiEndpointSettings, "WiFiEndpointSettingsInput": WiFiEndpointSettingsInput, "IEEE8021xSettingsInput": IEEE8021xSettingsInput, "ClientCredential": ClientCredential, "CACredential": CACredential }, callback_func); }
|
||
obj.AMT_WiFiPortConfigurationService_DeleteAllITProfiles = function (_method_dummy, callback_func) { obj.Exec("AMT_WiFiPortConfigurationService", "DeleteAllITProfiles", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.AMT_WiFiPortConfigurationService_DeleteAllUserProfiles = function (_method_dummy, callback_func) { obj.Exec("AMT_WiFiPortConfigurationService", "DeleteAllUserProfiles", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.CIM_Account_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Account", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_AccountManagementService_CreateAccount = function (System, AccountTemplate, callback_func) { obj.Exec("CIM_AccountManagementService", "CreateAccount", { "System": System, "AccountTemplate": AccountTemplate }, callback_func); }
|
||
obj.CIM_BootConfigSetting_ChangeBootOrder = function (Source, callback_func) { obj.Exec("CIM_BootConfigSetting", "ChangeBootOrder", { "Source": Source }, callback_func); }
|
||
obj.CIM_BootService_SetBootConfigRole = function (BootConfigSetting, Role, callback_func) { obj.Exec("CIM_BootService", "SetBootConfigRole", { "BootConfigSetting": BootConfigSetting, "Role": Role }, callback_func, 0, 1); }
|
||
obj.CIM_Card_ConnectorPower = function (Connector, PoweredOn, callback_func) { obj.Exec("CIM_Card", "ConnectorPower", { "Connector": Connector, "PoweredOn": PoweredOn }, callback_func); }
|
||
obj.CIM_Card_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_Card", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
|
||
obj.CIM_Chassis_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_Chassis", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
|
||
obj.CIM_Fan_SetSpeed = function (DesiredSpeed, callback_func) { obj.Exec("CIM_Fan", "SetSpeed", { "DesiredSpeed": DesiredSpeed }, callback_func); }
|
||
obj.CIM_KVMRedirectionSAP_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_KVMRedirectionSAP", "RequestStateChange", { "RequestedState": RequestedState/*, "TimeoutPeriod": TimeoutPeriod */}, callback_func); }
|
||
obj.CIM_MediaAccessDevice_LockMedia = function (Lock, callback_func) { obj.Exec("CIM_MediaAccessDevice", "LockMedia", { "Lock": Lock }, callback_func); }
|
||
obj.CIM_MediaAccessDevice_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_MediaAccessDevice", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_MediaAccessDevice_Reset = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "Reset", {}, callback_func); }
|
||
obj.CIM_MediaAccessDevice_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_MediaAccessDevice", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_MediaAccessDevice_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_MediaAccessDevice", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_MediaAccessDevice_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_MediaAccessDevice", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_MediaAccessDevice_SaveProperties = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_MediaAccessDevice_RestoreProperties = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_MediaAccessDevice_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_MediaAccessDevice", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_PhysicalFrame_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_PhysicalFrame", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
|
||
obj.CIM_PhysicalPackage_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_PhysicalPackage", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
|
||
obj.CIM_PowerManagementService_RequestPowerStateChange = function (PowerState, ManagedElement, Time, TimeoutPeriod, callback_func) { obj.Exec("CIM_PowerManagementService", "RequestPowerStateChange", { "PowerState": PowerState, "ManagedElement": ManagedElement, "Time": Time, "TimeoutPeriod": TimeoutPeriod }, callback_func, 0, 1); }
|
||
obj.CIM_PowerSupply_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_PowerSupply", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_PowerSupply_Reset = function (callback_func) { obj.Exec("CIM_PowerSupply", "Reset", {}, callback_func); }
|
||
obj.CIM_PowerSupply_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_PowerSupply", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_PowerSupply_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_PowerSupply", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_PowerSupply_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_PowerSupply", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_PowerSupply_SaveProperties = function (callback_func) { obj.Exec("CIM_PowerSupply", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_PowerSupply_RestoreProperties = function (callback_func) { obj.Exec("CIM_PowerSupply", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_PowerSupply_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_PowerSupply", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_Processor_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Processor", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_Processor_Reset = function (callback_func) { obj.Exec("CIM_Processor", "Reset", {}, callback_func); }
|
||
obj.CIM_Processor_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Processor", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_Processor_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Processor", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_Processor_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Processor", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_Processor_SaveProperties = function (callback_func) { obj.Exec("CIM_Processor", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_Processor_RestoreProperties = function (callback_func) { obj.Exec("CIM_Processor", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_Processor_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Processor", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_RecordLog_ClearLog = function (callback_func) { obj.Exec("CIM_RecordLog", "ClearLog", {}, callback_func); }
|
||
obj.CIM_RecordLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_RecordLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_RedirectionService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_RedirectionService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_Sensor_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Sensor", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_Sensor_Reset = function (callback_func) { obj.Exec("CIM_Sensor", "Reset", {}, callback_func); }
|
||
obj.CIM_Sensor_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Sensor", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_Sensor_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Sensor", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_Sensor_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Sensor", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_Sensor_SaveProperties = function (callback_func) { obj.Exec("CIM_Sensor", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_Sensor_RestoreProperties = function (callback_func) { obj.Exec("CIM_Sensor", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_Sensor_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Sensor", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_StatisticalData_ResetSelectedStats = function (SelectedStatistics, callback_func) { obj.Exec("CIM_StatisticalData", "ResetSelectedStats", { "SelectedStatistics": SelectedStatistics }, callback_func); }
|
||
obj.CIM_Watchdog_KeepAlive = function (callback_func) { obj.Exec("CIM_Watchdog", "KeepAlive", {}, callback_func); }
|
||
obj.CIM_Watchdog_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Watchdog", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_Watchdog_Reset = function (callback_func) { obj.Exec("CIM_Watchdog", "Reset", {}, callback_func); }
|
||
obj.CIM_Watchdog_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Watchdog", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_Watchdog_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Watchdog", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_Watchdog_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Watchdog", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_Watchdog_SaveProperties = function (callback_func) { obj.Exec("CIM_Watchdog", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_Watchdog_RestoreProperties = function (callback_func) { obj.Exec("CIM_Watchdog", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_Watchdog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Watchdog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.CIM_WiFiPort_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_WiFiPort", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
|
||
obj.CIM_WiFiPort_Reset = function (callback_func) { obj.Exec("CIM_WiFiPort", "Reset", {}, callback_func); }
|
||
obj.CIM_WiFiPort_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_WiFiPort", "EnableDevice", { "Enabled": Enabled }, callback_func); }
|
||
obj.CIM_WiFiPort_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_WiFiPort", "OnlineDevice", { "Online": Online }, callback_func); }
|
||
obj.CIM_WiFiPort_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_WiFiPort", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
|
||
obj.CIM_WiFiPort_SaveProperties = function (callback_func) { obj.Exec("CIM_WiFiPort", "SaveProperties", {}, callback_func); }
|
||
obj.CIM_WiFiPort_RestoreProperties = function (callback_func) { obj.Exec("CIM_WiFiPort", "RestoreProperties", {}, callback_func); }
|
||
obj.CIM_WiFiPort_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_WiFiPort", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.IPS_HostBasedSetupService_Setup = function (NetAdminPassEncryptionType, NetworkAdminPassword, McNonce, Certificate, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "Setup", { "NetAdminPassEncryptionType": NetAdminPassEncryptionType, "NetworkAdminPassword": NetworkAdminPassword, "McNonce": McNonce, "Certificate": Certificate, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
|
||
obj.IPS_HostBasedSetupService_AddNextCertInChain = function (NextCertificate, IsLeafCertificate, IsRootCertificate, callback_func) { obj.Exec("IPS_HostBasedSetupService", "AddNextCertInChain", { "NextCertificate": NextCertificate, "IsLeafCertificate": IsLeafCertificate, "IsRootCertificate": IsRootCertificate }, callback_func); }
|
||
obj.IPS_HostBasedSetupService_AdminSetup = function (NetAdminPassEncryptionType, NetworkAdminPassword, McNonce, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "AdminSetup", { "NetAdminPassEncryptionType": NetAdminPassEncryptionType, "NetworkAdminPassword": NetworkAdminPassword, "McNonce": McNonce, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
|
||
obj.IPS_HostBasedSetupService_UpgradeClientToAdmin = function (McNonce, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "UpgradeClientToAdmin", { "McNonce": McNonce, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
|
||
obj.IPS_HostBasedSetupService_DisableClientControlMode = function (_method_dummy, callback_func) { obj.Exec("IPS_HostBasedSetupService", "DisableClientControlMode", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.IPS_KVMRedirectionSettingData_TerminateSession = function (callback_func) { obj.Exec("IPS_KVMRedirectionSettingData", "TerminateSession", {}, callback_func); }
|
||
obj.IPS_OptInService_StartOptIn = function (callback_func) { obj.Exec("IPS_OptInService", "StartOptIn", {}, callback_func); }
|
||
obj.IPS_OptInService_CancelOptIn = function (callback_func) { obj.Exec("IPS_OptInService", "CancelOptIn", {}, callback_func); }
|
||
obj.IPS_OptInService_SendOptInCode = function (OptInCode, callback_func) { obj.Exec("IPS_OptInService", "SendOptInCode", { "OptInCode": OptInCode }, callback_func); }
|
||
obj.IPS_OptInService_StartService = function (callback_func) { obj.Exec("IPS_OptInService", "StartService", {}, callback_func); }
|
||
obj.IPS_OptInService_StopService = function (callback_func) { obj.Exec("IPS_OptInService", "StopService", {}, callback_func); }
|
||
obj.IPS_OptInService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_OptInService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.IPS_ProvisioningRecordLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
obj.IPS_ProvisioningRecordLog_ClearLog = function (_method_dummy, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "ClearLog", { "_method_dummy": _method_dummy }, callback_func); }
|
||
obj.IPS_SecIOService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_SecIOService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
|
||
|
||
obj.AmtStatusToStr = function (code) { if (obj.AmtStatusCodes[code]) return obj.AmtStatusCodes[code]; else return "UNKNOWN_ERROR" }
|
||
obj.AmtStatusCodes = {
|
||
0x0000: "SUCCESS",
|
||
0x0001: "INTERNAL_ERROR",
|
||
0x0002: "NOT_READY",
|
||
0x0003: "INVALID_PT_MODE",
|
||
0x0004: "INVALID_MESSAGE_LENGTH",
|
||
0x0005: "TABLE_FINGERPRINT_NOT_AVAILABLE",
|
||
0x0006: "INTEGRITY_CHECK_FAILED",
|
||
0x0007: "UNSUPPORTED_ISVS_VERSION",
|
||
0x0008: "APPLICATION_NOT_REGISTERED",
|
||
0x0009: "INVALID_REGISTRATION_DATA",
|
||
0x000A: "APPLICATION_DOES_NOT_EXIST",
|
||
0x000B: "NOT_ENOUGH_STORAGE",
|
||
0x000C: "INVALID_NAME",
|
||
0x000D: "BLOCK_DOES_NOT_EXIST",
|
||
0x000E: "INVALID_BYTE_OFFSET",
|
||
0x000F: "INVALID_BYTE_COUNT",
|
||
0x0010: "NOT_PERMITTED",
|
||
0x0011: "NOT_OWNER",
|
||
0x0012: "BLOCK_LOCKED_BY_OTHER",
|
||
0x0013: "BLOCK_NOT_LOCKED",
|
||
0x0014: "INVALID_GROUP_PERMISSIONS",
|
||
0x0015: "GROUP_DOES_NOT_EXIST",
|
||
0x0016: "INVALID_MEMBER_COUNT",
|
||
0x0017: "MAX_LIMIT_REACHED",
|
||
0x0018: "INVALID_AUTH_TYPE",
|
||
0x0019: "AUTHENTICATION_FAILED",
|
||
0x001A: "INVALID_DHCP_MODE",
|
||
0x001B: "INVALID_IP_ADDRESS",
|
||
0x001C: "INVALID_DOMAIN_NAME",
|
||
0x001D: "UNSUPPORTED_VERSION",
|
||
0x001E: "REQUEST_UNEXPECTED",
|
||
0x001F: "INVALID_TABLE_TYPE",
|
||
0x0020: "INVALID_PROVISIONING_STATE",
|
||
0x0021: "UNSUPPORTED_OBJECT",
|
||
0x0022: "INVALID_TIME",
|
||
0x0023: "INVALID_INDEX",
|
||
0x0024: "INVALID_PARAMETER",
|
||
0x0025: "INVALID_NETMASK",
|
||
0x0026: "FLASH_WRITE_LIMIT_EXCEEDED",
|
||
0x0027: "INVALID_IMAGE_LENGTH",
|
||
0x0028: "INVALID_IMAGE_SIGNATURE",
|
||
0x0029: "PROPOSE_ANOTHER_VERSION",
|
||
0x002A: "INVALID_PID_FORMAT",
|
||
0x002B: "INVALID_PPS_FORMAT",
|
||
0x002C: "BIST_COMMAND_BLOCKED",
|
||
0x002D: "CONNECTION_FAILED",
|
||
0x002E: "CONNECTION_TOO_MANY",
|
||
0x002F: "RNG_GENERATION_IN_PROGRESS",
|
||
0x0030: "RNG_NOT_READY",
|
||
0x0031: "CERTIFICATE_NOT_READY",
|
||
0x0400: "DISABLED_BY_POLICY",
|
||
0x0800: "NETWORK_IF_ERROR_BASE",
|
||
0x0801: "UNSUPPORTED_OEM_NUMBER",
|
||
0x0802: "UNSUPPORTED_BOOT_OPTION",
|
||
0x0803: "INVALID_COMMAND",
|
||
0x0804: "INVALID_SPECIAL_COMMAND",
|
||
0x0805: "INVALID_HANDLE",
|
||
0x0806: "INVALID_PASSWORD",
|
||
0x0807: "INVALID_REALM",
|
||
0x0808: "STORAGE_ACL_ENTRY_IN_USE",
|
||
0x0809: "DATA_MISSING",
|
||
0x080A: "DUPLICATE",
|
||
0x080B: "EVENTLOG_FROZEN",
|
||
0x080C: "PKI_MISSING_KEYS",
|
||
0x080D: "PKI_GENERATING_KEYS",
|
||
0x080E: "INVALID_KEY",
|
||
0x080F: "INVALID_CERT",
|
||
0x0810: "CERT_KEY_NOT_MATCH",
|
||
0x0811: "MAX_KERB_DOMAIN_REACHED",
|
||
0x0812: "UNSUPPORTED",
|
||
0x0813: "INVALID_PRIORITY",
|
||
0x0814: "NOT_FOUND",
|
||
0x0815: "INVALID_CREDENTIALS",
|
||
0x0816: "INVALID_PASSPHRASE",
|
||
0x0818: "NO_ASSOCIATION",
|
||
0x081B: "AUDIT_FAIL",
|
||
0x081C: "BLOCKING_COMPONENT",
|
||
0x0821: "USER_CONSENT_REQUIRED",
|
||
0x1000: "APP_INTERNAL_ERROR",
|
||
0x1001: "NOT_INITIALIZED",
|
||
0x1002: "LIB_VERSION_UNSUPPORTED",
|
||
0x1003: "INVALID_PARAM",
|
||
0x1004: "RESOURCES",
|
||
0x1005: "HARDWARE_ACCESS_ERROR",
|
||
0x1006: "REQUESTOR_NOT_REGISTERED",
|
||
0x1007: "NETWORK_ERROR",
|
||
0x1008: "PARAM_BUFFER_TOO_SHORT",
|
||
0x1009: "COM_NOT_INITIALIZED_IN_THREAD",
|
||
0x100A: "URL_REQUIRED"
|
||
}
|
||
|
||
//
|
||
// Methods used for getting the event log
|
||
//
|
||
|
||
obj.GetMessageLog = function (func, tag) {
|
||
obj.AMT_MessageLog_PositionToFirstRecord(_GetMessageLog0, [func, tag, []]);
|
||
}
|
||
function _GetMessageLog0(stack, name, responses, status, tag) {
|
||
if (status != 200 || responses.Body["ReturnValue"] != '0') { tag[0](obj, null, tag[2]); return; }
|
||
obj.AMT_MessageLog_GetRecords(responses.Body["IterationIdentifier"], 390, _GetMessageLog1, tag);
|
||
}
|
||
function _GetMessageLog1(stack, name, responses, status, tag) {
|
||
if (status != 200 || responses.Body["ReturnValue"] != '0') { tag[0](obj, null, tag[2]); return; }
|
||
var i, j, x, e, AmtMessages = tag[2], t = new Date(), TimeStamp, ra = responses.Body["RecordArray"];
|
||
if (typeof ra === 'string') { responses.Body["RecordArray"] = [responses.Body["RecordArray"]]; }
|
||
|
||
for (i in ra) {
|
||
e = null;
|
||
try { e = window.atob(ra[i]); } catch (ex) { }
|
||
if (e != null) {
|
||
TimeStamp = ReadIntX(e, 0);
|
||
if ((TimeStamp > 0) && (TimeStamp < 0xFFFFFFFF)) {
|
||
x = { 'DeviceAddress': e.charCodeAt(4), 'EventSensorType': e.charCodeAt(5), 'EventType': e.charCodeAt(6), 'EventOffset': e.charCodeAt(7), 'EventSourceType': e.charCodeAt(8), 'EventSeverity': e.charCodeAt(9), 'SensorNumber': e.charCodeAt(10), 'Entity': e.charCodeAt(11), 'EntityInstance': e.charCodeAt(12), 'EventData': [], 'Time': new Date((TimeStamp + (t.getTimezoneOffset() * 60)) * 1000) };
|
||
for (j = 13; j < 21; j++) { x['EventData'].push(e.charCodeAt(j)); }
|
||
x['EntityStr'] = _SystemEntityTypes[x['Entity']];
|
||
x['Desc'] = _GetEventDetailStr(x['EventSensorType'], x['EventOffset'], x['EventData'], x['Entity']);
|
||
if (!x['EntityStr']) x['EntityStr'] = "Unknown";
|
||
AmtMessages.push(x);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (responses.Body["NoMoreRecords"] != true) { obj.AMT_MessageLog_GetRecords(responses.Body["IterationIdentifier"], 390, _GetMessageLog1, [tag[0], AmtMessages, tag[2]]); } else { tag[0](obj, AmtMessages, tag[2]); }
|
||
}
|
||
|
||
var _EventTrapSourceTypes = "Platform firmware (e.g. BIOS)|SMI handler|ISV system management software|Alert ASIC|IPMI|BIOS vendor|System board set vendor|System integrator|Third party add-in|OSV|NIC|System management card".split('|');
|
||
var _SystemFirmwareError = "Unspecified.|No system memory is physically installed in the system.|No usable system memory, all installed memory has experienced an unrecoverable failure.|Unrecoverable hard-disk/ATAPI/IDE device failure.|Unrecoverable system-board failure.|Unrecoverable diskette subsystem failure.|Unrecoverable hard-disk controller failure.|Unrecoverable PS/2 or USB keyboard failure.|Removable boot media not found.|Unrecoverable video controller failure.|No video device detected.|Firmware (BIOS) ROM corruption detected.|CPU voltage mismatch (processors that share same supply have mismatched voltage requirements)|CPU speed matching failure".split('|');
|
||
var _SystemFirmwareProgress = "Unspecified.|Memory initialization.|Starting hard-disk initialization and test|Secondary processor(s) initialization|User authentication|User-initiated system setup|USB resource configuration|PCI resource configuration|Option ROM initialization|Video initialization|Cache initialization|SM Bus initialization|Keyboard controller initialization|Embedded controller/management controller initialization|Docking station attachment|Enabling docking station|Docking station ejection|Disabling docking station|Calling operating system wake-up vector|Starting operating system boot process|Baseboard or motherboard initialization|reserved|Floppy initialization|Keyboard test|Pointing device test|Primary processor initialization".split('|');
|
||
var _SystemEntityTypes = "Unspecified|Other|Unknown|Processor|Disk|Peripheral|System management module|System board|Memory module|Processor module|Power supply|Add in card|Front panel board|Back panel board|Power system board|Drive backplane|System internal expansion board|Other system board|Processor board|Power unit|Power module|Power management board|Chassis back panel board|System chassis|Sub chassis|Other chassis board|Disk drive bay|Peripheral bay|Device bay|Fan cooling|Cooling unit|Cable interconnect|Memory device|System management software|BIOS|Intel(r) ME|System bus|Group|Intel(r) ME|External environment|Battery|Processing blade|Connectivity switch|Processor/memory module|I/O module|Processor I/O module|Management controller firmware|IPMI channel|PCI bus|PCI express bus|SCSI bus|SATA/SAS bus|Processor front side bus".split('|');
|
||
obj.RealmNames = "||Redirection|PT Administration|Hardware Asset|Remote Control|Storage|Event Manager|Storage Admin|Agent Presence Local|Agent Presence Remote|Circuit Breaker|Network Time|General Information|Firmware Update|EIT|LocalUN|Endpoint Access Control|Endpoint Access Control Admin|Event Log Reader|Audit Log|ACL Realm|||Local System".split('|');
|
||
obj.WatchdogCurrentStates = { 1: 'Not Started', 2: 'Stopped', 4: 'Running', 8: 'Expired', 16: 'Suspended' };
|
||
|
||
function _GetEventDetailStr(eventSensorType, eventOffset, eventDataField, entity) {
|
||
|
||
if (eventSensorType == 15)
|
||
{
|
||
if (eventDataField[0] == 235) return "Invalid Data";
|
||
if (eventOffset == 0) return _SystemFirmwareError[eventDataField[1]];
|
||
return _SystemFirmwareProgress[eventDataField[1]];
|
||
}
|
||
|
||
if (eventSensorType == 18 && eventDataField[0] == 170) // System watchdog event
|
||
{
|
||
return "Agent watchdog " + char2hex(eventDataField[4]) + char2hex(eventDataField[3]) + char2hex(eventDataField[2]) + char2hex(eventDataField[1]) + "-" + char2hex(eventDataField[6]) + char2hex(eventDataField[5]) + "-... changed to " + obj.WatchdogCurrentStates[eventDataField[7]];
|
||
}
|
||
|
||
/*
|
||
if (eventSensorType == 5 && eventOffset == 0) // System chassis
|
||
{
|
||
return "Case intrusion";
|
||
}
|
||
|
||
if (eventSensorType == 192 && eventOffset == 0 && eventDataField[0] == 170 && eventDataField[1] == 48)
|
||
{
|
||
if (eventDataField[2] == 0) return "A remote Serial Over LAN session was established.";
|
||
if (eventDataField[2] == 1) return "Remote Serial Over LAN session finished. User control was restored.";
|
||
if (eventDataField[2] == 2) return "A remote IDE-Redirection session was established.";
|
||
if (eventDataField[2] == 3) return "Remote IDE-Redirection session finished. User control was restored.";
|
||
}
|
||
|
||
if (eventSensorType == 36)
|
||
{
|
||
long handle = ((long)(eventDataField[1]) << 24) + ((long)(eventDataField[2]) << 16) + ((long)(eventDataField[3]) << 8) + (long)(eventDataField[4]);
|
||
string nic = string.Format("#{0}", eventDataField[0]);
|
||
if (eventDataField[0] == 0xAA) nic = "wired"; // TODO: Add wireless *****
|
||
//if (eventDataField[0] == 0xAA) nic = "wireless";
|
||
|
||
if (handle == 4294967293) { return string.Format("All received packet filter was matched on {0} interface.", nic); }
|
||
if (handle == 4294967292) { return string.Format("All outbound packet filter was matched on {0} interface.", nic); }
|
||
if (handle == 4294967290) { return string.Format("Spoofed packet filter was matched on {0} interface.", nic); }
|
||
return string.Format("Filter {0} was matched on {1} interface.", handle, nic);
|
||
}
|
||
|
||
if (eventSensorType == 192)
|
||
{
|
||
if (eventDataField[2] == 0) return "Security policy invoked. Some or all network traffic (TX) was stopped.";
|
||
if (eventDataField[2] == 2) return "Security policy invoked. Some or all network traffic (RX) was stopped.";
|
||
return "Security policy invoked.";
|
||
}
|
||
|
||
if (eventSensorType == 193)
|
||
{
|
||
if (eventDataField[0] == 0xAA && eventDataField[1] == 0x30 && eventDataField[2] == 0x00 && eventDataField[3] == 0x00) { return "User request for remote connection."; }
|
||
if (eventDataField[0] == 0xAA && eventDataField[1] == 0x20 && eventDataField[2] == 0x03 && eventDataField[3] == 0x01) { return "EAC error: attempt to get posture while NAC in Intel<65> AMT is disabled."; // eventDataField = 0xAA20030100000000 }
|
||
if (eventDataField[0] == 0xAA && eventDataField[1] == 0x20 && eventDataField[2] == 0x04 && eventDataField[3] == 0x00) { return "Certificate revoked. "; }
|
||
}
|
||
*/
|
||
|
||
if (eventSensorType == 6) return "Authentication failed " + (eventDataField[1] + (eventDataField[2] << 8)) + " times. The system may be under attack.";
|
||
if (eventSensorType == 30) return "No bootable media";
|
||
if (eventSensorType == 32) return "Operating system lockup or power interrupt";
|
||
if (eventSensorType == 35) return "System boot failure";
|
||
if (eventSensorType == 37) return "System firmware started (at least one CPU is properly executing).";
|
||
return "Unknown Sensor Type #" + eventSensorType;
|
||
}
|
||
|
||
|
||
return obj;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// TinyMD5 from https://github.com/jbt/js-crypto
|
||
|
||
// Perform MD5 setup
|
||
var md5_k = [];
|
||
for (var i = 0; i < 64;) { md5_k[i] = 0 | (Math.abs(Math.sin(++i)) * 4294967296); }
|
||
|
||
// Perform MD5 on raw string and return hex
|
||
function hex_md5(str) {
|
||
var b, c, d, j,
|
||
x = [],
|
||
str2 = unescape(encodeURI(str)),
|
||
a = str2.length,
|
||
h = [b = 1732584193, c = -271733879, ~b, ~c],
|
||
i = 0;
|
||
|
||
for (; i <= a;) x[i >> 2] |= (str2.charCodeAt(i) || 128) << 8 * (i++ % 4);
|
||
|
||
x[str = (a + 8 >> 6) * 16 + 14] = a * 8;
|
||
i = 0;
|
||
|
||
for (; i < str; i += 16) {
|
||
a = h; j = 0;
|
||
for (; j < 64;) {
|
||
a = [
|
||
d = a[3],
|
||
((b = a[1] | 0) +
|
||
((d = (
|
||
(a[0] +
|
||
[
|
||
b & (c = a[2]) | ~b & d,
|
||
d & b | ~d & c,
|
||
b ^ c ^ d,
|
||
c ^ (b | ~d)
|
||
][a = j >> 4]
|
||
) +
|
||
(md5_k[j] +
|
||
(x[[
|
||
j,
|
||
5 * j + 1,
|
||
3 * j + 5,
|
||
7 * j
|
||
][a] % 16 + i] | 0)
|
||
)
|
||
)) << (a = [
|
||
7, 12, 17, 22,
|
||
5, 9, 14, 20,
|
||
4, 11, 16, 23,
|
||
6, 10, 15, 21
|
||
][4 * a + j++ % 4]) | d >>> 32 - a)
|
||
),
|
||
b,
|
||
c
|
||
];
|
||
}
|
||
for (j = 4; j;) h[--j] = h[j] + a[j];
|
||
}
|
||
|
||
str = '';
|
||
for (; j < 32;) str += ((h[j >> 3] >> ((1 ^ j++ & 7) * 4)) & 15).toString(16);
|
||
return str;
|
||
}
|
||
|
||
|
||
// Perform MD5 on raw string and return raw string result
|
||
function rstr_md5(str) { return hex2rstr(hex_md5(str)); }
|
||
|
||
/*
|
||
Convert arguments into selector set and body XML. Used by AMT_WiFiPortConfigurationService_UpdateWiFiSettings.
|
||
args = {
|
||
"WiFiEndpoint": {
|
||
__parameterType: 'reference',
|
||
__resourceUri: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint',
|
||
Name: 'WiFi Endpoint 0'
|
||
},
|
||
"WiFiEndpointSettingsInput":
|
||
{
|
||
__parameterType: 'instance',
|
||
__namespace: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings',
|
||
ElementName: document.querySelector('#editProfile-profileName').value,
|
||
InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + document.querySelector('#editProfile-profileName').value,
|
||
AuthenticationMethod: document.querySelector('#editProfile-networkAuthentication').value,
|
||
//BSSType: 3, // Intel(r) AMT supports only infrastructure networks
|
||
EncryptionMethod: document.querySelector('#editProfile-encryption').value,
|
||
SSID: document.querySelector('#editProfile-networkName').value,
|
||
Priority: 100,
|
||
PSKPassPhrase: document.querySelector('#editProfile-passPhrase').value
|
||
},
|
||
"IEEE8021xSettingsInput": null,
|
||
"ClientCredential": null,
|
||
"CACredential": null
|
||
},
|
||
*/
|
||
function execArgumentsToXml(args) {
|
||
if(args === undefined || args === null) return null;
|
||
|
||
var result = '';
|
||
for(var argName in args) {
|
||
var arg = args[argName];
|
||
if(!arg) continue;
|
||
if(arg['__parameterType'] === 'reference') result += referenceToXml(argName, arg);
|
||
else result += instanceToXml(argName, arg);
|
||
//if(arg['__isInstance']) result += instanceToXml(argName, arg);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Convert JavaScript object into XML
|
||
|
||
<r:WiFiEndpointSettingsInput xmlns:q="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings">
|
||
<q:ElementName>Wireless-Profile-Admin</q:ElementName>
|
||
<q:InstanceID>Intel(r) AMT:WiFi Endpoint Settings Wireless-Profile-Admin</q:InstanceID>
|
||
<q:AuthenticationMethod>6</q:AuthenticationMethod>
|
||
<q:EncryptionMethod>4</q:EncryptionMethod>
|
||
<q:Priority>100</q:Priority>
|
||
<q:PSKPassPhrase>P@ssw0rd</q:PSKPassPhrase>
|
||
</r:WiFiEndpointSettingsInput>
|
||
*/
|
||
function instanceToXml(instanceName, inInstance) {
|
||
if(inInstance === undefined || inInstance === null) return null;
|
||
|
||
var hasNamespace = !!inInstance['__namespace'];
|
||
var startTag = hasNamespace ? '<q:' : '<';
|
||
var endTag = hasNamespace ? '</q:' : '</';
|
||
var namespaceDef = hasNamespace ? (' xmlns:q="' + inInstance['__namespace'] + '"' ): '';
|
||
var result = '<r:' + instanceName + namespaceDef + '>';
|
||
for(var prop in inInstance) {
|
||
if (!inInstance.hasOwnProperty(prop) || prop.indexOf('__') === 0) continue;
|
||
|
||
if (typeof inInstance[prop] === 'function' || Array.isArray(inInstance[prop]) ) continue;
|
||
|
||
if (typeof inInstance[prop] === 'object') {
|
||
//result += startTag + prop +'>' + instanceToXml('prop', inInstance[prop]) + endTag + prop +'>';
|
||
console.error('only convert one level down...');
|
||
}
|
||
else {
|
||
result += startTag + prop +'>' + inInstance[prop].toString() + endTag + prop +'>';
|
||
}
|
||
}
|
||
result += '</r:' + instanceName + '>';
|
||
return result;
|
||
}
|
||
|
||
|
||
/**
|
||
* Convert a selector set into XML. Expect no nesting.
|
||
* {
|
||
* selectorName : selectorValue,
|
||
* selectorName : selectorValue,
|
||
* ... ...
|
||
* }
|
||
|
||
<r:WiFiEndpoint>
|
||
<a:Address>http://192.168.1.103:16992/wsman</a:Address>
|
||
<a:ReferenceParameters>
|
||
<w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint</w:ResourceURI>
|
||
<w:SelectorSet>
|
||
<w:Selector Name="Name">WiFi Endpoint 0</w:Selector>
|
||
</w:SelectorSet>
|
||
</a:ReferenceParameters>
|
||
</r:WiFiEndpoint>
|
||
|
||
*/
|
||
function referenceToXml(referenceName, inReference) {
|
||
if(inReference === undefined || inReference === null ) return null;
|
||
|
||
var result = '<r:' + referenceName + '><a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>'+ inReference['__resourceUri']+'</w:ResourceURI><w:SelectorSet>';
|
||
for(var selectorName in inReference) {
|
||
if (!inReference.hasOwnProperty(selectorName) || selectorName.indexOf('__') === 0) continue;
|
||
|
||
if (typeof inReference[selectorName] === 'function' ||
|
||
typeof inReference[selectorName] === 'object' ||
|
||
Array.isArray(inReference[selectorName]) )
|
||
continue;
|
||
|
||
result += '<w:Selector Name="' + selectorName +'">' + inReference[selectorName].toString() + '</w:Selector>';
|
||
}
|
||
|
||
result += '</w:SelectorSet></a:ReferenceParameters></r:' + referenceName + '>';
|
||
return result;
|
||
}
|
||
|
||
// Convert a byte array of SID into string
|
||
function GetSidString(sid) {
|
||
var r = "S-" + sid.charCodeAt(0) + "-" + sid.charCodeAt(7);
|
||
for (var i = 2; i < (sid.length / 4) ; i++) r += "-" + ReadIntX(sid, i * 4);
|
||
return r;
|
||
}
|
||
|
||
// Convert a SID readable string into bytes
|
||
function GetSidByteArray(sidString) {
|
||
if (!sidString || sidString == null) return null;
|
||
var sidParts = sidString.split('-');
|
||
|
||
// Make sure the SID has at least 4 parts and starts with 'S'
|
||
if (sidParts.length < 4 || (sidParts[0] != 's' && sidParts[0] != 'S')) return null;
|
||
|
||
// Check that each part of the SID is really an integer
|
||
for (var i = 1; i < sidParts.length; i++) { var y = parseInt(sidParts[i]); if (y != sidParts[i]) return null; sidParts[i] = y; }
|
||
|
||
// Version (8 bit) + Id count (8 bit) + 48 bit in big endian -- DO NOT use bitwise right shift operator. JavaScript converts the number into a 32 bit integer before shifting. In real world, it's highly likely this part is always 0.
|
||
var r = String.fromCharCode(sidParts[1]) + String.fromCharCode(sidParts.length - 3) + ShortToStr(Math.floor(sidParts[2] / Math.pow(2, 32))) + IntToStr((sidParts[2]) & 0xFFFF);
|
||
|
||
// the rest are in 32 bit in little endian
|
||
for (var i = 3; i < sidParts.length; i++) r += IntToStrX(sidParts[i]);
|
||
return r;
|
||
}
|
||
/**
|
||
* @description Intel(r) AMT WSMAN Stack
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.2.0
|
||
*/
|
||
|
||
// Construct a MeshServer object
|
||
var WsmanStackCreateService = function (host, port, user, pass, tls, extra) {
|
||
var obj = {};
|
||
//obj.onDebugMessage = null; // Set to a function if you want to get debug messages.
|
||
obj.NextMessageId = 1; // Next message number, used to label WSMAN calls.
|
||
obj.Address = '/wsman';
|
||
obj.comm = CreateWsmanComm(host, port, user, pass, tls, extra);
|
||
|
||
obj.PerformAjax = function (postdata, callback, tag, pri, namespaces) {
|
||
if (namespaces == undefined) namespaces = '';
|
||
obj.comm.PerformAjax('<?xml version=\"1.0\" encoding=\"utf-8\"?><Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns=\"http://www.w3.org/2003/05/soap-envelope\" ' + namespaces + '><Header><a:Action>' + postdata, function (data, status, tag) {
|
||
if (status != 200) { callback(obj, null, { Header: { HttpError: status } }, status, tag); return; }
|
||
var wsresponse = obj.ParseWsman(data);
|
||
if (!wsresponse || wsresponse == null) { callback(obj, null, { Header: { HttpError: status } }, 601, tag); } else { callback(obj, wsresponse.Header["ResourceURI"], wsresponse, 200, tag); }
|
||
}, tag, pri);
|
||
}
|
||
|
||
// Private method
|
||
//obj.Debug = function (msg) { /*console.log(msg);*/ }
|
||
|
||
// Cancel all pending queries with given status
|
||
obj.CancelAllQueries = function (s) { obj.comm.CancelAllQueries(s); }
|
||
|
||
// Get the last element of a URI string
|
||
obj.GetNameFromUrl = function (resuri) {
|
||
var x = resuri.lastIndexOf("/");
|
||
return (x == -1)?resuri:resuri.substring(x + 1);
|
||
}
|
||
|
||
// Perform a WSMAN Subscribe operation
|
||
obj.ExecSubscribe = function (resuri, delivery, url, callback, tag, pri, selectors, opaque, user, pass) {
|
||
var digest = "", digest2 = "";
|
||
if (user != undefined && pass != undefined) { digest = '<t:IssuedTokens><t:RequestSecurityTokenResponse><t:TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</t:TokenType><t:RequestedSecurityToken><se:UsernameToken><se:Username>' + user + '</se:Username><se:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#PasswordText">' + pass + '</se:Password></se:UsernameToken></t:RequestedSecurityToken></t:RequestSecurityTokenResponse></t:IssuedTokens>'; digest2 = '<Auth Profile="http://schemas.xmlsoap.org/ws/2004/08/eventing/DeliveryModes/secprofile/http/digest"/>'; }
|
||
if (opaque != undefined && opaque != null) { opaque = '<a:ReferenceParameters>' + opaque + '</a:ReferenceParameters>'; } else { opaque = ""; }
|
||
var data = "http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo>" + _PutObjToSelectorsXml(selectors) + digest + '</Header><Body><e:Subscribe><e:Delivery Mode="http://schemas.dmtf.org/wbem/wsman/1/wsman/' + delivery + '"><e:NotifyTo><a:Address>' + url + '</a:Address></e:NotifyTo>' + digest2 + '</e:Delivery><e:Expires>PT0.000000S</e:Expires></e:Subscribe>';
|
||
obj.PerformAjax(data + "</Body></Envelope>", callback, tag, pri, 'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"');
|
||
}
|
||
|
||
// Perform a WSMAN UnSubscribe operation
|
||
obj.ExecUnSubscribe = function (resuri, callback, tag, pri, selectors) {
|
||
var data = "http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo>" + _PutObjToSelectorsXml(selectors) + '</Header><Body><e:Unsubscribe/>';
|
||
obj.PerformAjax(data + "</Body></Envelope>", callback, tag, pri, 'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"');
|
||
}
|
||
|
||
// Perform a WSMAN PUT operation
|
||
obj.ExecPut = function (resuri, putobj, callback, tag, pri, selectors) {
|
||
var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Put</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60.000S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + '</Header><Body>' + _PutObjToBodyXml(resuri, putobj);
|
||
obj.PerformAjax(data + "</Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN CREATE operation
|
||
obj.ExecCreate = function (resuri, putobj, callback, tag, pri, selectors) {
|
||
var objname = obj.GetNameFromUrl(resuri);
|
||
var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Create</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + "</Header><Body><g:" + objname + " xmlns:g=\"" + resuri + "\">";
|
||
for (var n in putobj) { data += "<g:" + n + ">" + putobj[n] + "</g:" + n + ">" }
|
||
obj.PerformAjax(data + "</g:" + objname + "></Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN CREATE operation
|
||
obj.ExecCreateXml = function (resuri, argsxml, callback, tag, pri) {
|
||
var objname = obj.GetNameFromUrl(resuri), selector = "";
|
||
obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60.000S</w:OperationTimeout></Header><Body><r:" + objname + " xmlns:r=\"" + resuri + "\">" + argsxml + "</r:" + objname + "></Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN DELETE operation
|
||
obj.ExecDelete = function (resuri, putobj, callback, tag, pri) {
|
||
var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(putobj) + "</Header><Body /></Envelope>";
|
||
obj.PerformAjax(data, callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN GET operation
|
||
obj.ExecGet = function (resuri, callback, tag, pri) {
|
||
obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body /></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN method call operation
|
||
obj.ExecMethod = function (resuri, method, args, callback, tag, pri, selectors) {
|
||
var argsxml = "";
|
||
for (var i in args) { if (args[i] != null) { if (Array.isArray(args[i])) { for (var x in args[i]) { argsxml += "<r:" + i + ">" + args[i][x] + "</r:" + i + ">"; } } else { argsxml += "<r:" + i + ">" + args[i] + "</r:" + i + ">"; } } }
|
||
obj.ExecMethodXml(resuri, method, argsxml, callback, tag, pri, selectors);
|
||
}
|
||
|
||
// Perform a WSMAN method call operation. The arguments are already formatted in XML.
|
||
obj.ExecMethodXml = function (resuri, method, argsxml, callback, tag, pri, selectors) {
|
||
obj.PerformAjax(resuri + "/" + method + "</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + "</Header><Body><r:" + method + '_INPUT' + " xmlns:r=\"" + resuri + "\">" + argsxml + "</r:" + method + "_INPUT></Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN ENUM operation
|
||
obj.ExecEnum = function (resuri, callback, tag, pri) {
|
||
obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body><Enumerate xmlns=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\" /></Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Perform a WSMAN PULL operation
|
||
obj.ExecPull = function (resuri, enumctx, callback, tag, pri) {
|
||
obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body><Pull xmlns=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\"><EnumerationContext>" + enumctx + "</EnumerationContext><MaxElements>999</MaxElements><MaxCharacters>99999</MaxCharacters></Pull></Body></Envelope>", callback, tag, pri);
|
||
}
|
||
|
||
// Private method
|
||
obj.ParseWsman = function (xml) {
|
||
try {
|
||
if (!xml.childNodes) xml = _turnToXml(xml);
|
||
var r = { Header:{} }, header = xml.getElementsByTagName("Header")[0], t;
|
||
if (!header) header = xml.getElementsByTagName("a:Header")[0];
|
||
if (!header) return null;
|
||
for (var i = 0; i < header.childNodes.length; i++) {
|
||
var child = header.childNodes[i];
|
||
r.Header[child.localName] = child.textContent;
|
||
}
|
||
var body = xml.getElementsByTagName("Body")[0];
|
||
if (!body) body = xml.getElementsByTagName("a:Body")[0];
|
||
if (!body) return null;
|
||
if (body.childNodes.length > 0) {
|
||
t = body.childNodes[0].localName;
|
||
if (t.indexOf("_OUTPUT") == t.length - 7) { t = t.substring(0, t.length - 7); }
|
||
r.Header['Method'] = t;
|
||
r.Body = _ParseWsmanRec(body.childNodes[0]);
|
||
}
|
||
return r;
|
||
} catch (e) {
|
||
console.log("Unable to parse XML: " + xml);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Private method
|
||
function _ParseWsmanRec(node) {
|
||
var data, r = {};
|
||
for (var i = 0; i < node.childNodes.length; i++) {
|
||
var child = node.childNodes[i];
|
||
if (child.childElementCount == 0) { data = child.textContent; } else { data = _ParseWsmanRec(child); }
|
||
if (data == 'true') data = true; // Convert 'true' into true
|
||
if (data == 'false') data = false; // Convert 'false' into false
|
||
|
||
var childObj = data;
|
||
if (child.attributes.length > 0) {
|
||
childObj = {'Value': data };
|
||
for(var j = 0; j < child.attributes.length; j++) {
|
||
childObj['@' + child.attributes[j].name] = child.attributes[j].value;
|
||
}
|
||
}
|
||
|
||
if (r[child.localName] instanceof Array) { r[child.localName].push(childObj); }
|
||
else if (r[child.localName] == undefined) { r[child.localName] = childObj; }
|
||
else { r[child.localName] = [r[child.localName], childObj]; }
|
||
}
|
||
return r;
|
||
}
|
||
|
||
function _PutObjToBodyXml(resuri, putObj) {
|
||
if(!resuri || putObj === undefined || putObj === null) return '';
|
||
var objname = obj.GetNameFromUrl(resuri);
|
||
var result = '<r:' + objname + ' xmlns:r="' + resuri + '">';
|
||
|
||
for (var prop in putObj) {
|
||
if (!putObj.hasOwnProperty(prop) || prop.indexOf('__') === 0 || prop.indexOf('@') === 0) continue;
|
||
if (putObj[prop] === undefined || putObj[prop] === null || typeof putObj[prop] === 'function') continue;
|
||
if (typeof putObj[prop] === 'object' && putObj[prop]['ReferenceParameters']) {
|
||
result += '<r:' + prop + '><a:Address>' + putObj[prop].Address + '</a:Address><a:ReferenceParameters><w:ResourceURI>' + putObj[prop]['ReferenceParameters']["ResourceURI"] + '</w:ResourceURI><w:SelectorSet>';
|
||
var selectorArray = putObj[prop]['ReferenceParameters']['SelectorSet']['Selector'];
|
||
if (Array.isArray(selectorArray)) {
|
||
for (var i=0; i< selectorArray.length; i++) {
|
||
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray[i]) + '>' + selectorArray[i]['Value'] + '</w:Selector>';
|
||
}
|
||
}
|
||
else {
|
||
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray) + '>' + selectorArray['Value'] + '</w:Selector>';
|
||
}
|
||
result += '</w:SelectorSet></a:ReferenceParameters></r:' + prop + '>';
|
||
}
|
||
else {
|
||
if (Array.isArray(putObj[prop])) {
|
||
for (var i = 0; i < putObj[prop].length; i++) {
|
||
result += '<r:' + prop + '>' + putObj[prop][i].toString() + '</r:' + prop + '>';
|
||
}
|
||
} else {
|
||
result += '<r:' + prop + '>' + putObj[prop].toString() + '</r:' + prop + '>';
|
||
}
|
||
}
|
||
}
|
||
|
||
result += '</r:' + objname + '>';
|
||
return result;
|
||
}
|
||
|
||
/*
|
||
convert
|
||
{ @Name: 'InstanceID', @AttrName: 'Attribute Value'}
|
||
into
|
||
' Name="InstanceID" AttrName="Attribute Value" '
|
||
*/
|
||
function _ObjectToXmlAttributes(objWithAttributes) {
|
||
if(!objWithAttributes) return '';
|
||
var result = ' ';
|
||
for (var propName in objWithAttributes) {
|
||
if (!objWithAttributes.hasOwnProperty(propName) || propName.indexOf('@') !== 0) continue;
|
||
result += propName.substring(1) + '="' + objWithAttributes[propName] + '" ';
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function _PutObjToSelectorsXml(selectorSet) {
|
||
if (!selectorSet) return '';
|
||
if (typeof selectorSet == 'string') return selectorSet;
|
||
if (selectorSet['InstanceID']) return "<w:SelectorSet><w:Selector Name=\"InstanceID\">" + selectorSet['InstanceID'] + "</w:Selector></w:SelectorSet>";
|
||
var result = '<w:SelectorSet>';
|
||
for(var propName in selectorSet) {
|
||
if (!selectorSet.hasOwnProperty(propName)) continue;
|
||
result += '<w:Selector Name="' + propName + '">';
|
||
if (selectorSet[propName]['ReferenceParameters']) {
|
||
result += '<a:EndpointReference>';
|
||
result += '<a:Address>' + selectorSet[propName]['Address'] + '</a:Address><a:ReferenceParameters><w:ResourceURI>' + selectorSet[propName]['ReferenceParameters']['ResourceURI'] + '</w:ResourceURI><w:SelectorSet>';
|
||
var selectorArray = selectorSet[propName]['ReferenceParameters']['SelectorSet']['Selector'];
|
||
if (Array.isArray(selectorArray)) {
|
||
for (var i = 0; i < selectorArray.length; i++) {
|
||
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray[i]) + '>' + selectorArray[i]['Value'] + '</w:Selector>';
|
||
}
|
||
}
|
||
else {
|
||
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray) + '>' + selectorArray['Value'] + '</w:Selector>';
|
||
}
|
||
result += '</w:SelectorSet></a:ReferenceParameters></a:EndpointReference>';
|
||
} else {
|
||
result += selectorSet[propName];
|
||
}
|
||
result += '</w:Selector>';
|
||
}
|
||
result += '</w:SelectorSet>';
|
||
return result;
|
||
}
|
||
|
||
function _turnToXml(text) {
|
||
if (window.DOMParser) {
|
||
return new DOMParser().parseFromString(text, "text/xml");
|
||
}
|
||
else // Internet Explorer
|
||
{
|
||
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
|
||
xmlDoc.async = false;
|
||
xmlDoc.loadXML(text);
|
||
return xmlDoc;
|
||
}
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @description Remote Desktop
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.2g
|
||
*/
|
||
|
||
// Construct a MeshServer object
|
||
var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
|
||
var obj = {};
|
||
obj.canvasid = divid;
|
||
obj.CanvasId = Q(divid);
|
||
obj.scrolldiv = scrolldiv;
|
||
obj.canvas = Q(divid).getContext("2d");
|
||
obj.protocol = 2; // KVM
|
||
obj.state = 0;
|
||
obj.acc = "";
|
||
obj.ScreenWidth = 960;
|
||
obj.ScreenHeight = 700;
|
||
obj.width = 0;
|
||
obj.height = 0;
|
||
obj.rwidth = 0;
|
||
obj.rheight = 0;
|
||
obj.bpp = 2; // Bytes per pixel (1 or 2 supported)
|
||
obj.useZRLE = true;
|
||
obj.showmouse = true;
|
||
obj.buttonmask = 0;
|
||
obj.localKeyMap = true;
|
||
//obj.inbytes = 0;
|
||
//obj.outbytes = 0;
|
||
obj.spare = null;
|
||
obj.sparew = 0;
|
||
obj.spareh = 0;
|
||
obj.sparew2 = 0;
|
||
obj.spareh2 = 0;
|
||
obj.sparecache = {};
|
||
obj.ZRLEfirst = 1;
|
||
obj.onScreenSizeChange = null;
|
||
obj.frameRateDelay = 0;
|
||
// ###BEGIN###{DesktopInband}
|
||
obj.kvmDataSupported = false;
|
||
obj.onKvmData = null;
|
||
obj.onKvmDataPending = [];
|
||
obj.onKvmDataAck = -1;
|
||
obj.holding = false;
|
||
obj.lastKeepAlive = Date.now();
|
||
// ###END###{DesktopInband}
|
||
|
||
|
||
// Private method
|
||
obj.Debug = function (msg) { console.log(msg); }
|
||
|
||
obj.xxStateChange = function (newstate) {
|
||
if (newstate == 0) {
|
||
obj.canvas.fillStyle = '#000000';
|
||
obj.canvas.fillRect(0, 0, obj.width, obj.height);
|
||
obj.canvas.canvas.width = obj.rwidth = obj.width = 640;
|
||
obj.canvas.canvas.height = obj.rheight = obj.height = 400;
|
||
QS(obj.canvasid).cursor = 'default';
|
||
} else {
|
||
QS(obj.canvasid).cursor = obj.showmouse ?'default':'none';
|
||
}
|
||
}
|
||
|
||
obj.ProcessData = function (data) {
|
||
if (!data) return;
|
||
// obj.Debug("KRecv(" + data.length + "): " + rstr2hex(data));
|
||
//obj.inbytes += data.length;
|
||
//obj.Debug("KRecv(" + obj.inbytes + ")");
|
||
obj.acc += data;
|
||
while (obj.acc.length > 0) {
|
||
//obj.Debug("KAcc(" + obj.acc.length + "): " + rstr2hex(obj.acc));
|
||
var cmdsize = 0;
|
||
if (obj.state == 0 && obj.acc.length >= 12) {
|
||
// Getting handshake & version
|
||
cmdsize = 12;
|
||
//if (obj.acc.substring(0, 4) != "RFB ") { return obj.Stop(); }
|
||
//var version = parseFloat(obj.acc.substring(4, 11));
|
||
//obj.Debug("KVersion: " + version);
|
||
obj.state = 1;
|
||
obj.send("RFB 003.008\n");
|
||
}
|
||
else if (obj.state == 1 && obj.acc.length >= 1) {
|
||
// Getting security options
|
||
cmdsize = obj.acc.charCodeAt(0) + 1;
|
||
obj.send(String.fromCharCode(1)); // Send the "None" security type. Since we already authenticated using redirection digest auth, we don't need to do this again.
|
||
obj.state = 2;
|
||
}
|
||
else if (obj.state == 2 && obj.acc.length >= 4) {
|
||
// Getting security response
|
||
cmdsize = 4;
|
||
if (ReadInt(obj.acc, 0) != 0) { return obj.Stop(); }
|
||
obj.send(String.fromCharCode(1)); // Send share desktop flag
|
||
obj.state = 3;
|
||
}
|
||
else if (obj.state == 3 && obj.acc.length >= 24) {
|
||
// Getting server init
|
||
var namelen = ReadInt(obj.acc, 20);
|
||
if (obj.acc.length < 24 + namelen) return;
|
||
cmdsize = 24 + namelen;
|
||
obj.canvas.canvas.width = obj.rwidth = obj.width = obj.ScreenWidth = ReadShort(obj.acc, 0);
|
||
obj.canvas.canvas.height = obj.rheight = obj.height = obj.ScreenHeight = ReadShort(obj.acc, 2);
|
||
|
||
// These are all values we don't really need, we are going to only run in RGB565 or RGB332 and not use the flexibility provided by these settings.
|
||
// Makes the javascript code smaller and maybe a bit faster.
|
||
/*
|
||
obj.xbpp = obj.acc.charCodeAt(4);
|
||
obj.depth = obj.acc.charCodeAt(5);
|
||
obj.bigend = obj.acc.charCodeAt(6);
|
||
obj.truecolor = obj.acc.charCodeAt(7);
|
||
obj.rmax = ReadShort(obj.acc, 8);
|
||
obj.gmax = ReadShort(obj.acc, 10);
|
||
obj.bmax = ReadShort(obj.acc, 12);
|
||
obj.rsh = obj.acc.charCodeAt(14);
|
||
obj.gsh = obj.acc.charCodeAt(15);
|
||
obj.bsh = obj.acc.charCodeAt(16);
|
||
var name = obj.acc.substring(24, 24 + namelen);
|
||
obj.Debug("name: " + name);
|
||
obj.Debug("width: " + obj.width + ", height: " + obj.height);
|
||
obj.Debug("bits-per-pixel: " + obj.xbpp);
|
||
obj.Debug("depth: " + obj.depth);
|
||
obj.Debug("big-endian-flag: " + obj.bigend);
|
||
obj.Debug("true-colour-flag: " + obj.truecolor);
|
||
obj.Debug("rgb max: " + obj.rmax + "," + obj.gmax + "," + obj.bmax);
|
||
obj.Debug("rgb shift: " + obj.rsh + "," + obj.gsh + "," + obj.bsh);
|
||
*/
|
||
|
||
// SetEncodings, with AMT we can't omit RAW, must be specified.
|
||
// Intel AMT supports encodings: RAW (0), ZRLE (16), Desktop Size (0xFFFFFF21, -223)
|
||
|
||
var supportedEncodings = '';
|
||
if (obj.useZRLE) supportedEncodings += IntToStr(16);
|
||
supportedEncodings += IntToStr(0);
|
||
// ###BEGIN###{DesktopInband}
|
||
supportedEncodings += IntToStr(1092);
|
||
// ###END###{DesktopInband}
|
||
|
||
obj.send(String.fromCharCode(2, 0) + ShortToStr((supportedEncodings.length / 4) + 1) + supportedEncodings + IntToStr(-223)); // Supported Encodings + Desktop Size
|
||
|
||
// Set the pixel encoding to something much smaller
|
||
// obj.send(String.fromCharCode(0, 0, 0, 0, 16, 16, 0, 1) + ShortToStr(31) + ShortToStr(63) + ShortToStr(31) + String.fromCharCode(11, 5, 0, 0, 0, 0)); // Setup 16 bit color RGB565 (This is the default, so we don't need to set it)
|
||
if (obj.bpp == 1) obj.send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(7) + ShortToStr(7) + ShortToStr(3) + String.fromCharCode(5, 2, 0, 0, 0, 0)); // Setup 8 bit color RGB332
|
||
|
||
obj.state = 4;
|
||
obj.parent.xxStateChange(3);
|
||
_SendRefresh();
|
||
//obj.timer = setInterval(obj.xxOnTimer, 50);
|
||
|
||
|
||
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
|
||
}
|
||
else if (obj.state == 4) {
|
||
switch (obj.acc.charCodeAt(0)) {
|
||
case 0: // FramebufferUpdate
|
||
if (obj.acc.length < 4) return;
|
||
obj.state = 100 + ReadShort(obj.acc, 2); // Read the number of tiles that are going to be sent, add 100 and use that as our protocol state.
|
||
cmdsize = 4;
|
||
break;
|
||
case 2: // This is the bell, do nothing.
|
||
cmdsize = 1;
|
||
break;
|
||
case 3: // This is ServerCutText
|
||
if (obj.acc.length < 8) return;
|
||
var len = ReadInt(obj.acc, 4) + 8;
|
||
if (obj.acc.length < len) return;
|
||
cmdsize = handleServerCutText(obj.acc);
|
||
break;
|
||
}
|
||
}
|
||
else if (obj.state > 100 && obj.acc.length >= 12) {
|
||
var x = ReadShort(obj.acc, 0),
|
||
y = ReadShort(obj.acc, 2),
|
||
width = ReadShort(obj.acc, 4),
|
||
height = ReadShort(obj.acc, 6),
|
||
s = width * height,
|
||
encoding = ReadInt(obj.acc, 8);
|
||
|
||
if (encoding < 17) {
|
||
if (width < 1 || width > 64 || height < 1 || height > 64) { console.log("Invalid tile size (" + width + "," + height + "), disconnecting."); return obj.Stop(); }
|
||
|
||
// Set the spare bitmap to the rigth size if it's not already. This allows us to recycle the spare most if not all the time.
|
||
if (obj.sparew != width || obj.spareh != height) {
|
||
obj.sparew = obj.sparew2 = width;
|
||
obj.spareh = obj.spareh2 = height;
|
||
var xspacecachename = obj.sparew2 + 'x' + obj.spareh2;
|
||
obj.spare = obj.sparecache[xspacecachename];
|
||
if (!obj.spare) { obj.sparecache[xspacecachename] = obj.spare = obj.canvas.createImageData(obj.sparew2, obj.spareh2); }
|
||
}
|
||
|
||
}
|
||
|
||
if (encoding == 0xFFFFFF21) {
|
||
// Desktop Size (0xFFFFFF21, -223)
|
||
obj.canvas.canvas.width = obj.rwidth = obj.width = width;
|
||
obj.canvas.canvas.height = obj.rheight = obj.height = height;
|
||
obj.send(String.fromCharCode(3, 0, 0, 0, 0, 0) + ShortToStr(obj.width) + ShortToStr(obj.height)); // FramebufferUpdateRequest
|
||
cmdsize = 12;
|
||
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
|
||
// obj.Debug("New desktop width: " + obj.width + ", height: " + obj.height);
|
||
}
|
||
else if (encoding == 0) {
|
||
// RAW encoding
|
||
var ptr = 12, cs = 12 + (s * obj.bpp);
|
||
if (obj.acc.length < cs) return; // Check we have all the data needed and we can only draw 64x64 tiles.
|
||
cmdsize = cs;
|
||
|
||
// CRITICAL LOOP, optimize this as much as possible
|
||
for (var i = 0; i < s; i++) { _setPixel(obj.acc.charCodeAt(ptr++) + ((obj.bpp == 2) ? (obj.acc.charCodeAt(ptr++) << 8) : 0), i); }
|
||
_putImage(obj.spare, x, y);
|
||
}
|
||
else if (encoding == 16) {
|
||
// ZRLE encoding
|
||
if (obj.acc.length < 16) return;
|
||
var datalen = ReadInt(obj.acc, 12);
|
||
if (obj.acc.length < (16 + datalen)) return;
|
||
//obj.Debug("RECT ZRLE (" + x + "," + y + "," + width + "," + height + ") LEN = " + datalen);
|
||
//obj.Debug("RECT ZRLE LEN: " + ReadShortX(obj.acc, 17) + ", DATA: " + rstr2hex(obj.acc.substring(16)));
|
||
|
||
// Process the ZLib header if this is the first block
|
||
var ptr = 16, delta = 5, dx = 0;
|
||
|
||
if (datalen > 5 && obj.acc.charCodeAt(ptr) == 0 && ReadShortX(obj.acc, ptr + 1) == (datalen - delta)) {
|
||
// This is an uncompressed ZLib data block
|
||
_decodeLRE(obj.acc, ptr + 5, x, y, width, height, s, datalen);
|
||
}
|
||
|
||
cmdsize = 16 + datalen;
|
||
}
|
||
else {
|
||
obj.Debug("Unknown Encoding: " + encoding);
|
||
return obj.Stop();
|
||
}
|
||
if (--obj.state == 100) {
|
||
obj.state = 4;
|
||
if (obj.frameRateDelay == 0) {
|
||
_SendRefresh(); // Ask for new frame
|
||
} else {
|
||
setTimeout(_SendRefresh, obj.frameRateDelay); // Hold x miliseconds before asking for a new frame
|
||
}
|
||
}
|
||
}
|
||
|
||
if (cmdsize == 0) return;
|
||
obj.acc = obj.acc.substring(cmdsize);
|
||
}
|
||
}
|
||
|
||
function _decodeLRE(data, ptr, x, y, width, height, s, datalen) {
|
||
var subencoding = data.charCodeAt(ptr++), index, v, runlengthdecode, palette = {}, rlecount = 0, runlength = 0, i;
|
||
// obj.Debug("RECT RLE (" + (datalen - 5) + ", " + subencoding + "):" + rstr2hex(data.substring(21, 21 + (datalen - 5))));
|
||
if (subencoding == 0) {
|
||
// RAW encoding
|
||
for (i = 0; i < s; i++) { _setPixel(data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0), i); }
|
||
_putImage(obj.spare, x, y);
|
||
}
|
||
else if (subencoding == 1) {
|
||
// Solid color tile
|
||
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
|
||
obj.canvas.fillStyle = 'rgb(' + ((obj.bpp == 1) ? ((v & 224) + ',' + ((v & 28) << 3) + ',' + _fixColor((v & 3) << 6)) : (((v >> 8) & 248) + ',' + ((v >> 3) & 252) + ',' + ((v & 31) << 3))) + ')';
|
||
|
||
|
||
obj.canvas.fillRect(x, y, width, height);
|
||
}
|
||
else if (subencoding > 1 && subencoding < 17) { // Packed palette encoded tile
|
||
// Read the palette
|
||
var br = 4, bm = 15; // br is BitRead and bm is BitMask. By adjusting these two we can support all the variations in this encoding.
|
||
for (i = 0; i < subencoding; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
|
||
|
||
// Compute bits to read & bit mark
|
||
if (subencoding == 2) { br = 1; bm = 1; } else if (subencoding <= 4) { br = 2; bm = 3; }
|
||
|
||
// Display all the bits
|
||
while (rlecount < s && ptr < data.length) { v = data.charCodeAt(ptr++); for (i = (8 - br) ; i >= 0; i -= br) { _setPixel(palette[(v >> i) & bm], rlecount++); } }
|
||
_putImage(obj.spare, x, y);
|
||
}
|
||
else if (subencoding == 128) { // RLE encoded tile
|
||
while (rlecount < s && ptr < data.length) {
|
||
// Get the run color
|
||
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
|
||
|
||
// Decode the run length. This is the fastest and most compact way I found to do this.
|
||
runlength = 1; do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255);
|
||
|
||
// Draw a run
|
||
while (--runlength >= 0) { _setPixel(v, rlecount++); }
|
||
}
|
||
_putImage(obj.spare, x, y);
|
||
}
|
||
else if (subencoding > 129) { // Palette RLE encoded tile
|
||
// Read the palette
|
||
for (i = 0; i < (subencoding - 128) ; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
|
||
|
||
// Decode RLE on palette
|
||
while (rlecount < s && ptr < data.length) {
|
||
// Setup the run, get the color index and get the color from the palette.
|
||
runlength = 1; index = data.charCodeAt(ptr++); v = palette[index % 128];
|
||
|
||
// If the index starts with high order bit 1, this is a run and decode the run length.
|
||
if (index > 127) { do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255); }
|
||
|
||
// Draw a run
|
||
while (--runlength >= 0) { _setPixel(v, rlecount++); }
|
||
}
|
||
_putImage(obj.spare, x, y);
|
||
}
|
||
}
|
||
|
||
// ###BEGIN###{DesktopInband}
|
||
obj.hold = function (holding) {
|
||
if (obj.holding == holding) return;
|
||
obj.holding = holding;
|
||
obj.canvas.fillStyle = '#000000';
|
||
obj.canvas.fillRect(0, 0, obj.width, obj.height); // Paint black
|
||
if (obj.holding == false) {
|
||
// Go back to normal operations
|
||
// Set canvas size and ask for full screen refresh
|
||
if ((obj.canvas.canvas.width != obj.width) || (obj.canvas.canvas.height != obj.height)) {
|
||
obj.canvas.canvas.width = obj.width; obj.canvas.canvas.height = obj.height;
|
||
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); } // ???
|
||
}
|
||
obj.Send(String.fromCharCode(3, 0, 0, 0, 0, 0) + ShortToStr(obj.width) + ShortToStr(obj.height)); // FramebufferUpdateRequest
|
||
} else {
|
||
obj.UnGrabMouseInput();
|
||
obj.UnGrabKeyInput();
|
||
}
|
||
}
|
||
// ###END###{DesktopInband}
|
||
|
||
function _putImage(i, x, y) {
|
||
// ###BEGIN###{DesktopInband}
|
||
if (obj.holding == true) return;
|
||
// ###END###{DesktopInband}
|
||
obj.canvas.putImageData(i, x, y);
|
||
}
|
||
|
||
function _setPixel(v, p) {
|
||
var pp = p * 4;
|
||
|
||
|
||
if (obj.bpp == 1) {
|
||
// Set 8bit color RGB332
|
||
obj.spare.data[pp++] = v & 224;
|
||
obj.spare.data[pp++] = (v & 28) << 3;
|
||
obj.spare.data[pp++] = _fixColor((v & 3) << 6);
|
||
} else {
|
||
// Set 16bit color RGB565
|
||
obj.spare.data[pp++] = (v >> 8) & 248;
|
||
obj.spare.data[pp++] = (v >> 3) & 252;
|
||
obj.spare.data[pp++] = (v & 31) << 3;
|
||
}
|
||
obj.spare.data[pp] = 0xFF; // Set alpha channel to opaque.
|
||
}
|
||
|
||
|
||
function _fixColor(c) { return (c > 127) ? (c + 32) : c; }
|
||
|
||
function _SendRefresh() {
|
||
// ###BEGIN###{DesktopInband}
|
||
if (obj.holding == true) return;
|
||
// ###END###{DesktopInband}
|
||
// Request the entire screen
|
||
obj.send(String.fromCharCode(3, 1, 0, 0, 0, 0) + ShortToStr(obj.rwidth) + ShortToStr(obj.rheight)); // FramebufferUpdateRequest
|
||
}
|
||
|
||
obj.Start = function () {
|
||
//obj.Debug("KVM-Start");
|
||
obj.state = 0;
|
||
obj.acc = "";
|
||
obj.ZRLEfirst = 1;
|
||
//obj.inbytes = 0;
|
||
//obj.outbytes = 0;
|
||
// ###BEGIN###{DesktopInband}
|
||
obj.onKvmDataPending = [];
|
||
obj.onKvmDataAck = -1;
|
||
obj.kvmDataSupported = false;
|
||
// ###END###{DesktopInband}
|
||
for (var i in obj.sparecache) { delete obj.sparecache[i]; }
|
||
}
|
||
|
||
obj.Stop = function () {
|
||
obj.UnGrabMouseInput();
|
||
obj.UnGrabKeyInput();
|
||
obj.parent.Stop();
|
||
}
|
||
|
||
obj.send = function (x) {
|
||
//obj.Debug("KSend(" + x.length + "): " + rstr2hex(x));
|
||
//obj.outbytes += x.length;
|
||
obj.parent.send(x);
|
||
}
|
||
|
||
var convertAmtKeyCodeTable = {
|
||
"Pause": 19,
|
||
"CapsLock": 20,
|
||
"Space": 32,
|
||
"Quote": 39,
|
||
"Minus": 45,
|
||
"NumpadMultiply": 42,
|
||
"NumpadAdd": 43,
|
||
"PrintScreen": 44,
|
||
"Comma": 44,
|
||
"NumpadSubtract": 45,
|
||
"NumpadDecimal": 46,
|
||
"Period": 46,
|
||
"Slash": 47,
|
||
"NumpadDivide": 47,
|
||
"Semicolon": 59,
|
||
"Equal": 61,
|
||
"OSLeft": 91,
|
||
"BracketLeft": 91,
|
||
"OSRight": 91,
|
||
"Backslash": 92,
|
||
"BracketRight": 93,
|
||
"ContextMenu": 93,
|
||
"Backquote": 96,
|
||
"NumLock": 144,
|
||
"ScrollLock": 145,
|
||
"Backspace": 0xff08,
|
||
"Tab": 0xff09,
|
||
"Enter": 0xff0d,
|
||
"NumpadEnter": 0xff0d,
|
||
"Escape": 0xff1b,
|
||
"Delete": 0xffff,
|
||
"Home": 0xff50,
|
||
"PageUp": 0xff55,
|
||
"PageDown": 0xff56,
|
||
"ArrowLeft": 0xff51,
|
||
"ArrowUp": 0xff52,
|
||
"ArrowRight": 0xff53,
|
||
"ArrowDown": 0xff54,
|
||
"End": 0xff57,
|
||
"Insert": 0xff63,
|
||
"F1": 0xffbe,
|
||
"F2": 0xffbf,
|
||
"F3": 0xffc0,
|
||
"F4": 0xffc1,
|
||
"F5": 0xffc2,
|
||
"F6": 0xffc3,
|
||
"F7": 0xffc4,
|
||
"F8": 0xffc5,
|
||
"F9": 0xffc6,
|
||
"F10": 0xffc7,
|
||
"F11": 0xffc8,
|
||
"F12": 0xffc9,
|
||
"ShiftLeft": 0xffe1,
|
||
"ShiftRight": 0xffe2,
|
||
"ControlLeft": 0xffe3,
|
||
"ControlRight": 0xffe4,
|
||
"AltLeft": 0xffe9,
|
||
"AltRight": 0xffea,
|
||
"MetaLeft": 0xffe7,
|
||
"MetaRight": 0xffe8
|
||
}
|
||
function convertAmtKeyCode(e) {
|
||
if (e.code.startsWith('Key') && e.code.length == 4) { return e.code.charCodeAt(3) + ((e.shiftKey == false) ? 32 : 0); }
|
||
if (e.code.startsWith('Digit') && e.code.length == 6) { return e.code.charCodeAt(5); }
|
||
if (e.code.startsWith('Numpad') && e.code.length == 7) { return e.code.charCodeAt(6); }
|
||
return convertAmtKeyCodeTable[e.code];
|
||
}
|
||
|
||
/*
|
||
Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you don<6F>t need to
|
||
implement all the languages (this is taken care by the USB Scancode Extension in RFB4.0 protocol).
|
||
The only subset recognized by the FW is the defined by the following sets : XK_LATIN1 , XK_MISCELLANY, XK_3270, XK_XKB_KEYS, XK_KATAKANA.
|
||
In addition to keysymdef.h symbols there are 6 japanese extra keys that we do support:
|
||
|
||
#define XK_Intel_EU_102kbd_backslash_pipe_45 0x17170056 // European 102-key: 45 (backslash/pipe), usb Usage: 0x64
|
||
#define XK_Intel_JP_106kbd_yen_pipe 0x1717007d // Japanese 106-key: 14 (Yen/pipe), usb Usage: 0x89
|
||
#define XK_Intel_JP_106kbd_backslash_underbar 0x17170073 // Japanese 106-key: 56 (backslash/underbar), usb Usage: 0x87
|
||
#define XK_Intel_JP_106kbd_NoConvert 0x1717007b // Japanese 106-key: 131 (NoConvert), usb Usage: 0x8b
|
||
#define XK_Intel_JP_106kbd_Convert 0x17170079 // Japanese 106-key: 132 (Convert), usb Usage: 0x8a
|
||
#define XK_Intel_JP_106kbd_Hirigana_Katakana 0x17170070 // Japanese 106-key: 133 (Hirigana/Katakana), usb Usage: 0x88
|
||
*/
|
||
|
||
function _keyevent(d, e) {
|
||
if (!e) { e = window.event; }
|
||
|
||
if (e.code && (obj.localKeyMap == false)) {
|
||
// For new browsers, this mapping is keyboard language independent
|
||
var k = convertAmtKeyCode(e);
|
||
if (k != null) { obj.sendkey(k, d); }
|
||
} else {
|
||
// For older browsers, this mapping works best for EN-US keyboard
|
||
var k = e.keyCode, kk = k;
|
||
if (e.shiftKey == false && k >= 65 && k <= 90) kk = k + 32;
|
||
if (k >= 112 && k <= 124) kk = k + 0xFF4E;
|
||
if (k == 8) kk = 0xff08; // Backspace
|
||
if (k == 9) kk = 0xff09; // Tab
|
||
if (k == 13) kk = 0xff0d; // Return
|
||
if (k == 16) kk = 0xffe1; // Shift (Left)
|
||
if (k == 17) kk = 0xffe3; // Ctrl (Left)
|
||
if (k == 18) kk = 0xffe9; // Alt (Left)
|
||
if (k == 27) kk = 0xff1b; // ESC
|
||
if (k == 33) kk = 0xff55; // PageUp
|
||
if (k == 34) kk = 0xff56; // PageDown
|
||
if (k == 35) kk = 0xff57; // End
|
||
if (k == 36) kk = 0xff50; // Home
|
||
if (k == 37) kk = 0xff51; // Left
|
||
if (k == 38) kk = 0xff52; // Up
|
||
if (k == 39) kk = 0xff53; // Right
|
||
if (k == 40) kk = 0xff54; // Down
|
||
if (k == 45) kk = 0xff63; // Insert
|
||
if (k == 46) kk = 0xffff; // Delete
|
||
if (k >= 96 && k <= 105) kk = k - 48; // Key pad numbers
|
||
if (k == 106) kk = 42; // Pad *
|
||
if (k == 107) kk = 43; // Pad +
|
||
if (k == 109) kk = 45; // Pad -
|
||
if (k == 110) kk = 46; // Pad .
|
||
if (k == 111) kk = 47; // Pad /
|
||
if (k == 186) kk = 59; // ;
|
||
if (k == 187) kk = 61; // =
|
||
if (k == 188) kk = 44; // ,
|
||
if (k == 189) kk = 45; // -
|
||
if (k == 190) kk = 46; // .
|
||
if (k == 191) kk = 47; // /
|
||
if (k == 192) kk = 96; // `
|
||
if (k == 219) kk = 91; // [
|
||
if (k == 220) kk = 92; // \
|
||
if (k == 221) kk = 93; // ]t
|
||
if (k == 222) kk = 39; // '
|
||
//console.log('Key' + d + ": " + k + " = " + kk);
|
||
obj.sendkey(kk, d);
|
||
}
|
||
return obj.haltEvent(e);
|
||
}
|
||
|
||
obj.sendkey = function (k, d) {
|
||
if (typeof k == 'object') { for (var i in k) { obj.sendkey(k[i][0], k[i][1]); } }
|
||
else { obj.send(String.fromCharCode(4, d, 0, 0) + IntToStr(k)); }
|
||
}
|
||
|
||
function handleServerCutText(acc) {
|
||
if (acc.length < 8) return 0;
|
||
var len = ReadInt(obj.acc, 4) + 8;
|
||
if (acc.length < len) return 0;
|
||
// ###BEGIN###{DesktopInband}
|
||
if (obj.onKvmData != null) {
|
||
var d = acc.substring(8, len);
|
||
if ((d.length >= 16) && (d.substring(0, 15) == '\0KvmDataChannel')) {
|
||
if (obj.kvmDataSupported == false) { obj.kvmDataSupported = true; console.log('KVM Data Channel Supported.'); }
|
||
if (((obj.onKvmDataAck == -1) && (d.length == 16)) || (d.charCodeAt(15) != 0)) { obj.onKvmDataAck = true; }
|
||
//if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Recv(' + (d.length - 16) + '): ' + d.substring(16)); }
|
||
if (d.length >= 16) { obj.onKvmData(d.substring(16)); } // Event the data and ack
|
||
if ((obj.onKvmDataAck == true) && (obj.onKvmDataPending.length > 0)) { obj.sendKvmData(obj.onKvmDataPending.shift()); } // Send pending data
|
||
}
|
||
}
|
||
// ###END###{DesktopInband}
|
||
return len;
|
||
}
|
||
|
||
// ###BEGIN###{DesktopInband}
|
||
obj.sendKvmData = function (x) {
|
||
if (obj.onKvmDataAck !== true) {
|
||
obj.onKvmDataPending.push(x);
|
||
} else {
|
||
//if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Send(' + x.length + '): ' + x); }
|
||
x = '\0KvmDataChannel\0' + x;
|
||
obj.send(String.fromCharCode(6, 0, 0, 0) + IntToStr(x.length) + x);
|
||
obj.onKvmDataAck = false;
|
||
}
|
||
}
|
||
|
||
// Send a HWKVM keep alive if it's not been sent in the last 5 seconds.
|
||
obj.sendKeepAlive = function () {
|
||
if (obj.lastKeepAlive < Date.now() - 5000) { obj.lastKeepAlive = Date.now(); obj.send(String.fromCharCode(6, 0, 0, 0) + IntToStr(16) + '\0KvmDataChannel\0'); }
|
||
}
|
||
// ###END###{DesktopInband}
|
||
|
||
obj.SendCtrlAltDelMsg = function () { obj.sendcad(); }
|
||
obj.sendcad = function () { obj.sendkey([[0xFFE3, 1], [0xFFE9, 1], [0xFFFF, 1], [0xFFFF, 0], [0xFFE9, 0], [0xFFE3, 0]]); } // Control down, Alt down, Delete down, Delete up , Alt up , Control up
|
||
|
||
var _MouseInputGrab = false;
|
||
var _KeyInputGrab = false;
|
||
|
||
obj.GrabMouseInput = function () {
|
||
if (_MouseInputGrab == true) return;
|
||
var c = obj.canvas.canvas;
|
||
c.onmouseup = obj.mouseup;
|
||
c.onmousedown = obj.mousedown;
|
||
c.onmousemove = obj.mousemove;
|
||
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
|
||
_MouseInputGrab = true;
|
||
}
|
||
|
||
obj.UnGrabMouseInput = function () {
|
||
if (_MouseInputGrab == false) return;
|
||
var c = obj.canvas.canvas;
|
||
c.onmousemove = null;
|
||
c.onmouseup = null;
|
||
c.onmousedown = null;
|
||
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
|
||
_MouseInputGrab = false;
|
||
}
|
||
|
||
obj.GrabKeyInput = function () {
|
||
if (_KeyInputGrab == true) return;
|
||
document.onkeyup = obj.handleKeyUp;
|
||
document.onkeydown = obj.handleKeyDown;
|
||
document.onkeypress = obj.handleKeys;
|
||
_KeyInputGrab = true;
|
||
}
|
||
|
||
obj.UnGrabKeyInput = function () {
|
||
if (_KeyInputGrab == false) return;
|
||
document.onkeyup = null;
|
||
document.onkeydown = null;
|
||
document.onkeypress = null;
|
||
_KeyInputGrab = false;
|
||
}
|
||
|
||
obj.handleKeys = function (e) { return obj.haltEvent(e); }
|
||
obj.handleKeyUp = function (e) { return _keyevent(0, e); }
|
||
obj.handleKeyDown = function (e) { return _keyevent(1, e); }
|
||
obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
|
||
// RFB "PointerEvent" and mouse handlers
|
||
obj.mousedblclick = function (e) { }
|
||
obj.mousedown = function (e) { obj.buttonmask |= (1 << e.button); return obj.mousemove(e); }
|
||
obj.mouseup = function (e) { obj.buttonmask &= (0xFFFF - (1 << e.button)); return obj.mousemove(e); }
|
||
obj.mousemove = function (e) {
|
||
if (obj.state != 4) return true;
|
||
var pos = obj.getPositionOfControl(Q(obj.canvasid));
|
||
obj.mx = (e.pageX - pos[0]) * (obj.canvas.canvas.height / Q(obj.canvasid).offsetHeight);
|
||
obj.my = ((e.pageY - pos[1] + (scrolldiv ? scrolldiv.scrollTop : 0)) * (obj.canvas.canvas.width / Q(obj.canvasid).offsetWidth));
|
||
|
||
|
||
obj.send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
|
||
|
||
|
||
return obj.haltEvent(e);
|
||
}
|
||
|
||
obj.getPositionOfControl = function (Control) {
|
||
var Position = Array(2);
|
||
Position[0] = Position[1] = 0;
|
||
while (Control) {
|
||
Position[0] += Control.offsetLeft;
|
||
Position[1] += Control.offsetTop;
|
||
Control = Control.offsetParent;
|
||
}
|
||
return Position;
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @description Remote Terminal
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.2c
|
||
*/
|
||
|
||
// Construct a MeshServer object
|
||
var CreateAmtRemoteTerminal = function (divid) {
|
||
var obj = {};
|
||
obj.DivId = divid;
|
||
obj.DivElement = document.getElementById(divid);
|
||
obj.protocol = 1; // SOL
|
||
obj.fxEmulation = 0;
|
||
obj.lineFeed = '\r\n';
|
||
obj.debugmode = 0;
|
||
|
||
obj.width = 80; // 80 or 100
|
||
obj.height = 25; // 25 or 30
|
||
|
||
var _Terminal_CellHeight = 21;
|
||
var _Terminal_CellWidth = 13;
|
||
var _TermColors = ['000000', 'BB0000', '00BB00', 'BBBB00', '0000BB', 'BB00BB', '00BBBB', 'BBBBBB', '555555', 'FF5555', '55FF55', 'FFFF55', '5555FF', 'FF55FF', '55FFFF', 'FFFFFF'];
|
||
var _TermCurrentReverse = 0;
|
||
var _TermCurrentFColor = 7;
|
||
var _TermCurrentBColor = 0;
|
||
var _TermLineWrap = true;
|
||
var _termx = 0;
|
||
var _termy = 0;
|
||
var _termstate = 0;
|
||
var _escNumber = [];
|
||
var _escNumberPtr = 0;
|
||
var _scratt = [];
|
||
var _tscreen = [];
|
||
var _VTUNDERLINE = 1;
|
||
var _VTREVERSE = 2;
|
||
|
||
obj.Start = function () { }
|
||
|
||
obj.Init = function (width, height) {
|
||
obj.width = width ? width : 80;
|
||
obj.height = height ? height : 25;
|
||
for (var y = 0; y < obj.height; y++) {
|
||
_tscreen[y] = [];
|
||
_scratt[y] = [];
|
||
for (var x = 0; x < obj.width; x++) { _tscreen[y][x] = ' '; _scratt[y][x] = (7 << 6); }
|
||
}
|
||
obj.TermInit();
|
||
obj.TermDraw();
|
||
}
|
||
|
||
obj.xxStateChange = function(newstate) { }
|
||
|
||
obj.ProcessData = function (str) {
|
||
if (obj.debugmode == 2) { console.log("TRecv(" + str.length + "): " + rstr2hex(str)); }
|
||
if (obj.capture != null) obj.capture += str; _ProcessVt100EscString(str); obj.TermDraw();
|
||
}
|
||
|
||
function _ProcessVt100EscString(str) { for (var i = 0; i < str.length; i++) _ProcessVt100EscChar(String.fromCharCode(str.charCodeAt(i)), str.charCodeAt(i)); }
|
||
|
||
function _ProcessVt100EscChar(b, c) {
|
||
switch (_termstate) {
|
||
case 0: // Normal Term State
|
||
switch (c) {
|
||
case 27: // ESC
|
||
_termstate = 1;
|
||
break;
|
||
default:
|
||
// Process a single char
|
||
_ProcessVt100Char(b);
|
||
break;
|
||
}
|
||
break;
|
||
case 1:
|
||
switch (b) {
|
||
case '[':
|
||
_escNumberPtr = 0;
|
||
_escNumber = [];
|
||
_termstate = 2;
|
||
break;
|
||
case '(':
|
||
_termstate = 4;
|
||
break;
|
||
case ')':
|
||
_termstate = 5;
|
||
break;
|
||
default:
|
||
_termstate = 0;
|
||
break;
|
||
}
|
||
break;
|
||
case 2:
|
||
if (b >= '0' && b <= '9') {
|
||
// This is a number
|
||
if (!_escNumber[_escNumberPtr]) {
|
||
_escNumber[_escNumberPtr] = (b - '0');
|
||
}
|
||
else {
|
||
_escNumber[_escNumberPtr] = ((_escNumber[_escNumberPtr] * 10) + (b - '0'));
|
||
}
|
||
break;
|
||
}
|
||
else if (b == ';') {
|
||
// New number
|
||
_escNumberPtr++;
|
||
break;
|
||
}
|
||
else {
|
||
// Process Escape Sequence
|
||
if (!_escNumber[0]) _escNumber[0] = 0;
|
||
_ProcessEscapeHandler(b, _escNumber, _escNumberPtr + 1);
|
||
_termstate = 0;
|
||
}
|
||
break;
|
||
case 4: // '(' Code
|
||
_termstate = 0;
|
||
break;
|
||
case 5: // ')' Code
|
||
_termstate = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
function _ProcessEscapeHandler(code, args, argslen) {
|
||
var i;
|
||
switch (code) {
|
||
case 'c': // ResetDevice
|
||
// Reset
|
||
obj.TermResetScreen();
|
||
break;
|
||
case 'A': // Move cursor up n lines
|
||
if (argslen == 1) {
|
||
_termy -= args[0];
|
||
if (_termy < 0) _termy = 0;
|
||
}
|
||
break;
|
||
case 'B': // Move cursor down n lines
|
||
if (argslen == 1) {
|
||
_termy += args[0];
|
||
if (_termy > obj.height) _termy = obj.height;
|
||
}
|
||
break;
|
||
case 'C': // Move cursor right n lines
|
||
if (argslen == 1) {
|
||
_termx += args[0];
|
||
if (_termx > obj.width) _termx = obj.width;
|
||
}
|
||
break;
|
||
case 'D': // Move cursor left n lines
|
||
if (argslen == 1) {
|
||
_termx -= args[0];
|
||
if (_termx < 0) _termx = 0;
|
||
}
|
||
break;
|
||
case 'd': // Set cursor to line n
|
||
if (argslen == 1) {
|
||
_termy = args[0] - 1;
|
||
if (_termy > obj.height) _termy = obj.height;
|
||
if (_termy < 0) _termy = 0;
|
||
}
|
||
break;
|
||
case 'G': // Set cursor to col n
|
||
if (argslen == 1) {
|
||
_termx = args[0] - 1;
|
||
if (_termx < 0) _termx = 0;
|
||
if (_termx > 79) _termx = 79;
|
||
}
|
||
break;
|
||
case 'J': // ClearScreen:
|
||
if (argslen == 1 && args[0] == 2) {
|
||
obj.TermClear((_TermCurrentBColor << 12) + (_TermCurrentFColor << 6)); // Erase entire screen
|
||
_termx = 0;
|
||
_termy = 0;
|
||
}
|
||
else if (argslen == 0 || argslen == 1 && args[0] == 0) // Erase cursor down
|
||
{
|
||
_EraseCursorToEol();
|
||
for (i = _termy + 1; i < obj.height; i++) _EraseLine(i);
|
||
}
|
||
else if (argslen == 1 && args[0] == 1) // Erase cursor up
|
||
{
|
||
_EraseCursorToEol();
|
||
for (i = 0; i < _termy - 1; i++) _EraseLine(i);
|
||
}
|
||
break;
|
||
case 'H': // MoveCursor:
|
||
if (argslen == 2) {
|
||
if (args[0] < 1) args[0] = 1;
|
||
if (args[1] < 1) args[1] = 1;
|
||
if (args[0] > obj.height) args[0] = obj.height;
|
||
if (args[1] > obj.width) args[1] = obj.width;
|
||
_termy = args[0] - 1;
|
||
_termx = args[1] - 1;
|
||
}
|
||
else {
|
||
_termy = 0;
|
||
_termx = 0;
|
||
}
|
||
break;
|
||
case 'm': // ScreenAttribs:
|
||
// Change attributes
|
||
for (i = 0; i < argslen; i++) {
|
||
if (!args[i] || args[i] == 0) {
|
||
// Reset Attributes
|
||
_TermCurrentBColor = 0;
|
||
_TermCurrentFColor = 7;
|
||
_TermCurrentReverse = 0;
|
||
}
|
||
else if (args[i] == 1) {
|
||
// Bright
|
||
if (_TermCurrentFColor < 8) _TermCurrentFColor += 8;
|
||
}
|
||
else if (args[i] == 2 || args[i] == 22) {
|
||
// Dim
|
||
if (_TermCurrentFColor >= 8) _TermCurrentFColor -= 8;
|
||
}
|
||
else if (args[i] == 7) {
|
||
// Set Reverse attribute true
|
||
_TermCurrentReverse = 2;
|
||
}
|
||
else if (args[i] == 27) {
|
||
// Set Reverse attribute false
|
||
_TermCurrentReverse = 0;
|
||
}
|
||
else if (args[i] >= 30 && args[i] <= 37) {
|
||
// Set Foreground Color
|
||
var bright = (_TermCurrentFColor >= 8);
|
||
_TermCurrentFColor = (args[i] - 30);
|
||
if (bright && _TermCurrentFColor <= 8) _TermCurrentFColor += 8;
|
||
}
|
||
else if (args[i] >= 40 && args[i] <= 47) {
|
||
// Set Background Color
|
||
_TermCurrentBColor = (args[i] - 40);
|
||
}
|
||
else if (args[i] >= 90 && args[i] <= 99) {
|
||
// Set Bright Foreground Color
|
||
_TermCurrentFColor = (args[i] - 82);
|
||
}
|
||
else if (args[i] >= 100 && args[i] <= 109) {
|
||
// Set Bright Background Color
|
||
_TermCurrentBColor = (args[i] - 92);
|
||
}
|
||
}
|
||
break;
|
||
case 'K': // EraseLine:
|
||
if (argslen == 0 || (argslen == 1 && (!args[0] || args[0] == 0))) {
|
||
_EraseCursorToEol(); // Erase from the cursor to the end of the line
|
||
}
|
||
else if (argslen == 1) {
|
||
if (args[0] == 1) // Erase from the beginning of the line to the cursor
|
||
{
|
||
_EraseBolToCursor();
|
||
}
|
||
else if (args[0] == 2) // Erase the line with the cursor
|
||
{
|
||
_EraseLine(_termy);
|
||
}
|
||
}
|
||
break;
|
||
case 'h': // EnableLineWrap:
|
||
_TermLineWrap = true;
|
||
break;
|
||
case 'l': // DisableLineWrap:
|
||
_TermLineWrap = false;
|
||
break;
|
||
default:
|
||
//if (code != '@') alert(code);
|
||
break;
|
||
}
|
||
}
|
||
|
||
obj.ProcessVt100String = function (str) {
|
||
for (var i = 0; i < str.length; i++) _ProcessVt100Char(String.fromCharCode(str.charCodeAt(i)));
|
||
}
|
||
|
||
|
||
|
||
|
||
function _ProcessVt100Char(c) {
|
||
if (c == '\0' || c.charCodeAt() == 7) return; // Ignore null & bell
|
||
var ch = c.charCodeAt();
|
||
|
||
|
||
|
||
|
||
//if (ch < 32 && ch != 10 && ch != 13) alert(ch);
|
||
switch (ch) {
|
||
case 16: { c = ' '; break; } // This is an odd char that show up on Intel BIOS's.
|
||
case 24: { c = '↑'; break; }
|
||
case 25: { c = '↓'; break; }
|
||
}
|
||
|
||
if (_termx > obj.width) _termx = obj.width;
|
||
if (_termy > (obj.height - 1)) _termy = (obj.height - 1);
|
||
|
||
switch (c) {
|
||
case '\b': // Backspace
|
||
if (_termx > 0) {
|
||
_termx = _termx - 1;
|
||
_TermDrawChar(' ');
|
||
}
|
||
break;
|
||
case '\t': // tab
|
||
var tab = 8 - (_termx % 8)
|
||
for (var x = 0; x < tab; x++) _ProcessVt100Char(" ");
|
||
break;
|
||
case '\n': // Linefeed
|
||
_termy++;
|
||
if (_termy > (obj.height - 1)) {
|
||
// Move everything up one line
|
||
_TermMoveUp(1);
|
||
_termy = (obj.height - 1);
|
||
}
|
||
if (obj.lineFeed = '\n') { _termx = 0; } // *** If we are in Linux mode, \n will also return the cursor to the first col
|
||
break;
|
||
case '\r': // Carriage Return
|
||
_termx = 0;
|
||
break;
|
||
default:
|
||
if (_termx >= obj.width) {
|
||
_termx = 0;
|
||
if (_TermLineWrap) { _termy++; }
|
||
if (_termy >= (obj.height - 1)) { _TermMoveUp(1); _termy = (obj.height - 1); }
|
||
}
|
||
_TermDrawChar(c);
|
||
_termx++;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
function _TermDrawChar(c) {
|
||
_tscreen[_termy][_termx] = c;
|
||
_scratt[_termy][_termx] = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
|
||
}
|
||
|
||
obj.TermClear = function(TermColor) {
|
||
for (var y = 0; y < obj.height; y++) {
|
||
for (var x = 0; x < obj.width; x++) {
|
||
_tscreen[y][x] = ' ';
|
||
_scratt[y][x] = TermColor;
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.TermResetScreen = function () {
|
||
_TermCurrentReverse = 0;
|
||
_TermCurrentFColor = 7;
|
||
_TermCurrentBColor = 0;
|
||
_TermLineWrap = true;
|
||
_termx = 0;
|
||
_termy = 0;
|
||
obj.TermClear(7 << 6);
|
||
}
|
||
|
||
function _EraseCursorToEol() {
|
||
var t = (_TermCurrentBColor << 12);
|
||
for (var x = _termx; x < obj.width; x++) {
|
||
_tscreen[_termy][x] = ' ';
|
||
_scratt[_termy][x] = t;
|
||
}
|
||
}
|
||
|
||
function _EraseBolToCursor() {
|
||
var t = (_TermCurrentBColor << 12);
|
||
for (var x = 0; x < _termx; x++) {
|
||
_tscreen[_termy][x] = ' ';
|
||
_scratt[_termy][x] = t;
|
||
}
|
||
}
|
||
|
||
function _EraseLine(line) {
|
||
var t = (_TermCurrentBColor << 12);
|
||
for (var x = 0; x < obj.width; x++) {
|
||
_tscreen[line][x] = ' ';
|
||
_scratt[line][x] = t;
|
||
}
|
||
}
|
||
|
||
obj.TermSendKeys = function (keys) { if (obj.debugmode == 2) { if (obj.debugmode == 2) { console.log("TSend(" + keys.length + "): " + rstr2hex(keys)); } } obj.parent.send(keys); }
|
||
obj.TermSendKey = function (key) { if (obj.debugmode == 2) { if (obj.debugmode == 2) { console.log("TSend(1): " + rstr2hex(String.fromCharCode(key))); } } obj.parent.send(String.fromCharCode(key)); }
|
||
|
||
function _TermMoveUp(linecount) {
|
||
var x, y;
|
||
for (y = 0; y < obj.height - linecount; y++) {
|
||
_tscreen[y] = _tscreen[y + linecount];
|
||
_scratt[y] = _scratt[y + linecount];
|
||
}
|
||
for (y = obj.height - linecount; y < obj.height; y++) {
|
||
_tscreen[y] = [];
|
||
_scratt[y] = [];
|
||
for (x = 0; x < obj.width; x++) {
|
||
_tscreen[y][x] = ' ';
|
||
_scratt[y][x] = (7 << 6);
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.TermHandleKeys = function (e) {
|
||
if (!e.ctrlKey) {
|
||
if (e.which == 127) obj.TermSendKey(8);
|
||
else if (e.which == 13) obj.TermSendKeys(obj.lineFeed);
|
||
else if (e.which != 0) obj.TermSendKey(e.which);
|
||
return false;
|
||
}
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (e.stopPropagation) e.stopPropagation();
|
||
}
|
||
|
||
obj.TermHandleKeyUp = function (e) {
|
||
if ((e.which != 8) && (e.which != 32) && (e.which != 9)) return true;
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (e.stopPropagation) e.stopPropagation();
|
||
return false;
|
||
}
|
||
|
||
obj.TermHandleKeyDown = function (e) {
|
||
if ((e.which >= 65) && (e.which <= 90) && (e.ctrlKey == true)) {
|
||
obj.TermSendKey(e.which - 64);
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (e.stopPropagation) e.stopPropagation();
|
||
return;
|
||
}
|
||
if (e.which == 27) { obj.TermSendKeys(String.fromCharCode(27)); return true; }; // ESC
|
||
if (e.which == 37) { obj.TermSendKeys(String.fromCharCode(27, 91, 68)); return true; }; // Left
|
||
if (e.which == 38) { obj.TermSendKeys(String.fromCharCode(27, 91, 65)); return true; }; // Up
|
||
if (e.which == 39) { obj.TermSendKeys(String.fromCharCode(27, 91, 67)); return true; }; // Right
|
||
if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 91, 66)); return true; }; // Down
|
||
if (e.which == 9) { obj.TermSendKeys("\t"); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return true; }; // TAB
|
||
|
||
// F1 to F12 keys
|
||
|
||
if (e.which != 8 && e.which != 32 && e.which != 9) return true;
|
||
obj.TermSendKey(e.which);
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (e.stopPropagation) e.stopPropagation();
|
||
return false;
|
||
}
|
||
|
||
obj.TermDraw = function() {
|
||
var c, buf = '', closetag = '', newat, oldat = 1, x1, x2;
|
||
for (var y = 0; y < obj.height; ++y) {
|
||
for (var x = 0; x < obj.width; ++x) {
|
||
newat = _scratt[y][x];
|
||
if (_termx == x && _termy == y) { newat |= _VTREVERSE; } // If this is the cursor location, reverse the color.
|
||
if (newat != oldat) {
|
||
buf += closetag;
|
||
closetag = '';
|
||
x1 = 6; x2 = 12;
|
||
if (newat & _VTREVERSE) { x1 = 12; x2 = 6;}
|
||
buf += '<span style="color:#' + _TermColors[(newat >> x1) & 0x3F] + ';background-color:#' + _TermColors[(newat >> x2) & 0x3F];
|
||
if (newat & _VTUNDERLINE) buf += ';text-decoration:underline';
|
||
buf += ';">';
|
||
closetag = "</span>" + closetag;
|
||
oldat = newat;
|
||
}
|
||
|
||
c = _tscreen[y][x];
|
||
switch (c) {
|
||
case '&':
|
||
buf += '&'; break;
|
||
case '<':
|
||
buf += '<'; break;
|
||
case '>':
|
||
buf += '>'; break;
|
||
case ' ':
|
||
buf += ' '; break;
|
||
default:
|
||
buf += c;
|
||
break;
|
||
}
|
||
}
|
||
if (y != (obj.height - 1)) buf += '<br>';
|
||
}
|
||
obj.DivElement.innerHTML = "<font size='4'><b>" + buf + closetag + "</b></font>";
|
||
}
|
||
|
||
obj.TermInit = function () { obj.TermResetScreen(); }
|
||
|
||
obj.Init();
|
||
return obj;
|
||
}/* zlib.js -- JavaScript implementation for the zlib.
|
||
Version: 0.2.0
|
||
LastModified: Apr 12 2012
|
||
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
|
||
|
||
The original copyright notice (zlib 1.2.6):
|
||
|
||
Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler
|
||
|
||
This software is provided 'as-is', without any express or implied
|
||
warranty. In no event will the authors be held liable for any damages
|
||
arising from the use of this software.
|
||
|
||
Permission is granted to anyone to use this software for any purpose,
|
||
including commercial applications, and to alter it and redistribute it
|
||
freely, subject to the following restrictions:
|
||
|
||
1. The origin of this software must not be misrepresented; you must not
|
||
claim that you wrote the original software. If you use this software
|
||
in a product, an acknowledgment in the product documentation would be
|
||
appreciated but is not required.
|
||
2. Altered source versions must be plainly marked as such, and must not be
|
||
misrepresented as being the original software.
|
||
3. This notice may not be removed or altered from any source distribution.
|
||
|
||
Jean-loup Gailly Mark Adler
|
||
jloup@gzip.org madler@alumni.caltech.edu
|
||
|
||
|
||
The data format used by the zlib library is described by RFCs (Request for
|
||
Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
|
||
(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
|
||
*/
|
||
|
||
var ZLIB = ( ZLIB || {} ); // ZLIB namespace initialization
|
||
|
||
// common definitions
|
||
if(typeof ZLIB.common_initialized === 'undefined') {
|
||
ZLIB.Z_NO_FLUSH = 0;
|
||
ZLIB.Z_PARTIAL_FLUSH = 1;
|
||
ZLIB.Z_SYNC_FLUSH = 2;
|
||
ZLIB.Z_FULL_FLUSH = 3;
|
||
ZLIB.Z_FINISH = 4;
|
||
ZLIB.Z_BLOCK = 5;
|
||
ZLIB.Z_TREES = 6;
|
||
/* Allowed flush values; see deflate() and inflate() below for details */
|
||
|
||
ZLIB.Z_OK = 0;
|
||
ZLIB.Z_STREAM_END = 1;
|
||
ZLIB.Z_NEED_DICT = 2;
|
||
ZLIB.Z_ERRNO = (-1);
|
||
ZLIB.Z_STREAM_ERROR = (-2);
|
||
ZLIB.Z_DATA_ERROR = (-3);
|
||
ZLIB.Z_MEM_ERROR = (-4);
|
||
ZLIB.Z_BUF_ERROR = (-5);
|
||
ZLIB.Z_VERSION_ERROR = (-6);
|
||
/* Return codes for the compression/decompression functions. Negative values
|
||
* are errors, positive values are used for special but normal events.
|
||
*/
|
||
|
||
ZLIB.Z_DEFLATED = 8; /* The deflate compression method (the only one supported in this version) */
|
||
|
||
/**
|
||
* z_stream constructor
|
||
* @constructor
|
||
*/
|
||
ZLIB.z_stream = function() {
|
||
this.next_in = 0; /* next input byte */
|
||
this.avail_in = 0; /* number of bytes available in input_data */
|
||
this.total_in = 0; /* total number of input bytes read so far */
|
||
|
||
this.next_out = 0; /* next output byte */
|
||
this.avail_out = 0; /* remaining free space at next_out */
|
||
this.total_out = 0; /* total number of bytes output so far */
|
||
|
||
this.msg = null; /* last error message, null if no error */
|
||
this.state = null; /* not visible by applications */
|
||
|
||
this.data_type = 0; /* best guess about the data type: binary or text */
|
||
this.adler = 0; /* TODO: adler32 value of the uncompressed data */
|
||
|
||
// zlib.js
|
||
this.input_data = ''; /* input data */
|
||
this.output_data = ''; /* output data */
|
||
this.error = 0; /* error code */
|
||
this.checksum_function = null; /* crc32(for gzip) or adler32(for zlib) */
|
||
};
|
||
|
||
/**
|
||
* TODO
|
||
* @constructor
|
||
*/
|
||
ZLIB.gz_header = function() {
|
||
this.text = 0; /* true if compressed data believed to be text */
|
||
this.time = 0; /* modification time */
|
||
this.xflags = 0; /* extra flags (not used when writing a gzip file) */
|
||
this.os = 0xff; /* operating system */
|
||
this.extra = null; /* extra field string or null if none */
|
||
this.extra_len = 0; /* this.extra.length (only when reading header) */
|
||
this.extra_max = 0; /* space at extra (only when reading header) */
|
||
this.name = null; /* file name string or null if none */
|
||
this.name_max = 0; /* space at name (only when reading header) */
|
||
this.comment = null; /* comment string or null if none */
|
||
this.comm_max = 0; /* space at comment (only when reading header) */
|
||
this.hcrc = 0; /* true if there was or will be a header crc */
|
||
this.done = 0; /* true when done reading gzip header (not used
|
||
when writing a gzip file) */
|
||
};
|
||
|
||
ZLIB.common_initialized = true;
|
||
} // common definitions
|
||
/* zlib-inflate.js -- JavaScript implementation for the zlib inflate.
|
||
Version: 0.2.0
|
||
LastModified: Apr 12 2012
|
||
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
|
||
|
||
This library is one of the JavaScript zlib implementation.
|
||
Some API's are modified from the original.
|
||
Only inflate API is implemented.
|
||
|
||
The original copyright notice (zlib 1.2.6):
|
||
|
||
Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler
|
||
|
||
This software is provided 'as-is', without any express or implied
|
||
warranty. In no event will the authors be held liable for any damages
|
||
arising from the use of this software.
|
||
|
||
Permission is granted to anyone to use this software for any purpose,
|
||
including commercial applications, and to alter it and redistribute it
|
||
freely, subject to the following restrictions:
|
||
|
||
1. The origin of this software must not be misrepresented; you must not
|
||
claim that you wrote the original software. If you use this software
|
||
in a product, an acknowledgment in the product documentation would be
|
||
appreciated but is not required.
|
||
2. Altered source versions must be plainly marked as such, and must not be
|
||
misrepresented as being the original software.
|
||
3. This notice may not be removed or altered from any source distribution.
|
||
|
||
Jean-loup Gailly Mark Adler
|
||
jloup@gzip.org madler@alumni.caltech.edu
|
||
|
||
|
||
The data format used by the zlib library is described by RFCs (Request for
|
||
Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
|
||
(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
|
||
*/
|
||
|
||
/*
|
||
API documentation
|
||
==============================================================================
|
||
Usage: z_stream = ZLIB.inflateInit([windowBits]);
|
||
|
||
Create the stream object for decompression.
|
||
See zlib.h for windowBits information.
|
||
|
||
==============================================================================
|
||
Usage: decoded_string = z_stream.inflate(encoded_string [, {OPTIONS...}]);
|
||
|
||
OPTIONS:
|
||
next_in: decode start offset for encoded_string.
|
||
|
||
avail_in: // TODO document. See zlib.h for the information.
|
||
|
||
avail_out: // TODO document. See zlib.h for the information.
|
||
|
||
flush: // TODO document. See zlib.h for the information.
|
||
|
||
Ex: decoded_string = z_stream.inflate(encoded_string);
|
||
decoded_string = z_stream.inflate(encoded_string,
|
||
{next_in: 0,
|
||
avail_in: encoded_string.length,
|
||
avail_out: 1024,
|
||
flush: ZLIB.Z_NO_FLUSH});
|
||
|
||
See zlib.h for more information.
|
||
|
||
==============================================================================
|
||
Usage: z_stream.inflateReset();
|
||
TODO document
|
||
|
||
*/
|
||
|
||
if( typeof ZLIB === 'undefined' ) {
|
||
alert('ZLIB is not defined. SRC zlib.js before zlib-inflate.js')
|
||
}
|
||
|
||
(function() {
|
||
|
||
/* inflate.c -- zlib decompression
|
||
* Copyright (C) 1995-2011 Mark Adler
|
||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||
*/
|
||
|
||
var DEF_WBITS = 15;
|
||
|
||
// inflate_mode
|
||
var HEAD = 0; /* i: waiting for magic header */
|
||
var FLAGS = 1; /* i: waiting for method and flags (gzip) */
|
||
var TIME = 2; /* i: waiting for modification time (gzip) */
|
||
var OS = 3; /* i: waiting for extra flags and operating system (gzip) */
|
||
var EXLEN = 4; /* i: waiting for extra length (gzip) */
|
||
var EXTRA = 5; /* i: waiting for extra bytes (gzip) */
|
||
var NAME = 6; /* i: waiting for end of file name (gzip) */
|
||
var COMMENT = 7; /* i: waiting for end of comment (gzip) */
|
||
var HCRC = 8; /* i: waiting for header crc (gzip) */
|
||
var DICTID = 9; /* i: waiting for dictionary check value */
|
||
var DICT = 10; /* waiting for inflateSetDictionary() call */
|
||
var TYPE = 11; /* i: waiting for type bits, including last-flag bit */
|
||
var TYPEDO = 12; /* i: same, but skip check to exit inflate on new block */
|
||
var STORED = 13; /* i: waiting for stored size (length and complement) */
|
||
var COPY_ = 14; /* i/o: same as COPY below, but only first time in */
|
||
var COPY = 15; /* i/o: waiting for input or output to copy stored block */
|
||
var TABLE = 16; /* i: waiting for dynamic block table lengths */
|
||
var LENLENS = 17; /* i: waiting for code length code lengths */
|
||
var CODELENS = 18; /* i: waiting for length/lit and distance code lengths */
|
||
var LEN_ = 19; /* i: same as LEN below, but only first time in */
|
||
var LEN = 20; /* i: waiting for length/lit/eob code */
|
||
var LENEXT = 21; /* i: waiting for length extra bits */
|
||
var DIST = 22; /* i: waiting for distance code */
|
||
var DISTEXT = 23; /* i: waiting for distance extra bits */
|
||
var MATCH = 24; /* o: waiting for output space to copy string */
|
||
var LIT = 25; /* o: waiting for output space to write literal */
|
||
var CHECK = 26; /* i: waiting for 32-bit check value */
|
||
var LENGTH = 27; /* i: waiting for 32-bit length (gzip) */
|
||
var DONE = 28; /* finished check, done -- remain here until reset */
|
||
var BAD = 29; /* got a data error -- remain here until reset */
|
||
var MEM = 30; /* got an inflate() memory error -- remain here until reset */
|
||
var SYNC = 31; /* looking for synchronization bytes to restart inflate() */
|
||
|
||
/* Maximum size of the dynamic table. The maximum number of code structures is
|
||
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
||
codes. These values were found by exhaustive searches using the program
|
||
examples/enough.c found in the zlib distribtution. The arguments to that
|
||
program are the number of symbols, the initial root table size, and the
|
||
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
||
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
|
||
The initial root table size (9 or 6) is found in the fifth argument of the
|
||
inflate_table() calls in inflate.c and infback.c. If the root table size is
|
||
changed, then these maximum sizes would be need to be recalculated and
|
||
updated. */
|
||
var ENOUGH_LENS = 852;
|
||
var ENOUGH_DISTS = 592;
|
||
var ENOUGH = (ENOUGH_LENS + ENOUGH_DISTS);
|
||
|
||
/* Type of code to build for inflate_table() */
|
||
var CODES = 0;
|
||
var LENS = 1;
|
||
var DISTS = 2;
|
||
|
||
|
||
|
||
var inflate_table_lbase = [ /* Length codes 257..285 base */
|
||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0];
|
||
var inflate_table_lext = [ /* Length codes 257..285 extra */
|
||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 69];
|
||
var inflate_table_dbase = [ /* Distance codes 0..29 base */
|
||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||
8193, 12289, 16385, 24577, 0, 0];
|
||
var inflate_table_dext = [ /* Distance codes 0..29 extra */
|
||
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
|
||
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
|
||
28, 28, 29, 29, 64, 64];
|
||
|
||
/* inftrees.c -- generate Huffman trees for efficient decoding
|
||
* Copyright (C) 1995-2012 Mark Adler
|
||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||
*/
|
||
|
||
ZLIB.inflate_copyright =
|
||
' inflate 1.2.6 Copyright 1995-2012 Mark Adler ';
|
||
/*
|
||
If you use the zlib library in a product, an acknowledgment is welcome
|
||
in the documentation of your product. If for some reason you cannot
|
||
include such an acknowledgment, I would appreciate that you keep this
|
||
copyright string in the executable of your product.
|
||
*/
|
||
|
||
/*
|
||
Build a set of tables to decode the provided canonical Huffman code.
|
||
The code lengths are lens[0..codes-1]. The result starts at *table,
|
||
whose indices are 0..2^bits-1. work is a writable array of at least
|
||
lens shorts, which is used as a work area. type is the type of code
|
||
to be generated, CODES, LENS, or DISTS. On return, zero is success,
|
||
-1 is an invalid code, and +1 means that ENOUGH isn't enough. table
|
||
on return points to the next available entry's address. bits is the
|
||
requested root table index bits, and on return it is the actual root
|
||
table index bits. It will differ if the request is greater than the
|
||
longest code or if it is less than the shortest code.
|
||
*/
|
||
function inflate_table(state, type)
|
||
{
|
||
var MAXBITS = 15;
|
||
var table = state.next;
|
||
var bits = (type == DISTS ? state.distbits : state.lenbits);
|
||
var work = state.work;
|
||
var lens = state.lens;
|
||
var lens_offset = (type == DISTS ? state.nlen : 0);
|
||
var state_codes = state.codes;
|
||
var codes;
|
||
if(type == LENS)
|
||
codes = state.nlen;
|
||
else if(type == DISTS)
|
||
codes = state.ndist;
|
||
else // CODES
|
||
codes = 19;
|
||
|
||
var len; /* a code's length in bits */
|
||
var sym; /* index of code symbols */
|
||
var min, max; /* minimum and maximum code lengths */
|
||
var root; /* number of index bits for root table */
|
||
var curr; /* number of index bits for current table */
|
||
var drop; /* code bits to drop for sub-table */
|
||
var left; /* number of prefix codes available */
|
||
var used; /* code entries in table used */
|
||
var huff; /* Huffman code */
|
||
var incr; /* for incrementing code, index */
|
||
var fill; /* index for replicating entries */
|
||
var low; /* low bits for current root entry */
|
||
var mask; /* mask for low root bits */
|
||
var here; /* table entry for duplication */
|
||
var next; /* next available space in table */
|
||
var base; /* base value table to use */
|
||
var base_offset;
|
||
var extra; /* extra bits table to use */
|
||
var extra_offset;
|
||
var end; /* use base and extra for symbol > end */
|
||
var count = new Array(MAXBITS+1); /* number of codes of each length */
|
||
var offs = new Array(MAXBITS+1); /* offsets in table for each length */
|
||
|
||
/*
|
||
Process a set of code lengths to create a canonical Huffman code. The
|
||
code lengths are lens[0..codes-1]. Each length corresponds to the
|
||
symbols 0..codes-1. The Huffman code is generated by first sorting the
|
||
symbols by length from short to long, and retaining the symbol order
|
||
for codes with equal lengths. Then the code starts with all zero bits
|
||
for the first code of the shortest length, and the codes are integer
|
||
increments for the same length, and zeros are appended as the length
|
||
increases. For the deflate format, these bits are stored backwards
|
||
from their more natural integer increment ordering, and so when the
|
||
decoding tables are built in the large loop below, the integer codes
|
||
are incremented backwards.
|
||
|
||
This routine assumes, but does not check, that all of the entries in
|
||
lens[] are in the range 0..MAXBITS. The caller must assure this.
|
||
1..MAXBITS is interpreted as that code length. zero means that that
|
||
symbol does not occur in this code.
|
||
|
||
The codes are sorted by computing a count of codes for each length,
|
||
creating from that a table of starting indices for each length in the
|
||
sorted table, and then entering the symbols in order in the sorted
|
||
table. The sorted table is work[], with that space being provided by
|
||
the caller.
|
||
|
||
The length counts are used for other purposes as well, i.e. finding
|
||
the minimum and maximum length codes, determining if there are any
|
||
codes at all, checking for a valid set of lengths, and looking ahead
|
||
at length counts to determine sub-table sizes when building the
|
||
decoding tables.
|
||
*/
|
||
|
||
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
|
||
for (len = 0; len <= MAXBITS; len++)
|
||
count[len] = 0;
|
||
for (sym = 0; sym < codes; sym++)
|
||
count[lens[lens_offset + sym]]++;
|
||
|
||
/* bound code lengths, force root to be within code lengths */
|
||
root = bits;
|
||
|
||
for (max = MAXBITS; max >= 1; max--)
|
||
if (count[max] != 0) break;
|
||
if (root > max) root = max;
|
||
if (max == 0) {
|
||
/* no symbols to code at all */
|
||
/* invalid code marker */
|
||
here = {op:64, bits:1, val:0};
|
||
state_codes[table++] = here; /* make a table to force an error */
|
||
state_codes[table++] = here;
|
||
if(type == DISTS) state.distbits = 1; else state.lenbits = 1; // *bits = 1;
|
||
state.next = table;
|
||
return 0; /* no symbols, but wait for decoding to report error */
|
||
}
|
||
for (min = 1; min < max; min++)
|
||
if (count[min] != 0) break;
|
||
if (root < min) root = min;
|
||
|
||
/* check for an over-subscribed or incomplete set of lengths */
|
||
left = 1;
|
||
for (len = 1; len <= MAXBITS; len++) {
|
||
left <<= 1;
|
||
left -= count[len];
|
||
if (left < 0) return -1; /* over-subscribed */
|
||
}
|
||
if (left > 0 && (type == CODES || max != 1)) {
|
||
state.next = table;
|
||
return -1; /* incomplete set */
|
||
}
|
||
|
||
/* generate offsets into symbol table for each length for sorting */
|
||
offs[1] = 0;
|
||
for (len = 1; len < MAXBITS; len++)
|
||
offs[len + 1] = offs[len] + count[len];
|
||
|
||
/* sort symbols by length, by symbol order within each length */
|
||
for (sym = 0; sym < codes; sym++)
|
||
if (lens[lens_offset + sym] != 0) work[offs[lens[lens_offset + sym]]++] = sym;
|
||
|
||
/*
|
||
Create and fill in decoding tables. In this loop, the table being
|
||
filled is at next and has curr index bits. The code being used is huff
|
||
with length len. That code is converted to an index by dropping drop
|
||
bits off of the bottom. For codes where len is less than drop + curr,
|
||
those top drop + curr - len bits are incremented through all values to
|
||
fill the table with replicated entries.
|
||
|
||
root is the number of index bits for the root table. When len exceeds
|
||
root, sub-tables are created pointed to by the root entry with an index
|
||
of the low root bits of huff. This is saved in low to check for when a
|
||
new sub-table should be started. drop is zero when the root table is
|
||
being filled, and drop is root when sub-tables are being filled.
|
||
|
||
When a new sub-table is needed, it is necessary to look ahead in the
|
||
code lengths to determine what size sub-table is needed. The length
|
||
counts are used for this, and so count[] is decremented as codes are
|
||
entered in the tables.
|
||
|
||
used keeps track of how many table entries have been allocated from the
|
||
provided *table space. It is checked for LENS and DIST tables against
|
||
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
|
||
the initial root table size constants. See the comments in inftrees.h
|
||
for more information.
|
||
|
||
sym increments through all symbols, and the loop terminates when
|
||
all codes of length max, i.e. all codes, have been processed. This
|
||
routine permits incomplete codes, so another loop after this one fills
|
||
in the rest of the decoding tables with invalid code markers.
|
||
*/
|
||
|
||
/* set up for code type */
|
||
switch (type) {
|
||
case CODES:
|
||
base = extra = work; /* dummy value--not used */
|
||
base_offset = 0;
|
||
extra_offset = 0;
|
||
end = 19;
|
||
break;
|
||
case LENS:
|
||
base = inflate_table_lbase;
|
||
base_offset = -257; // base -= 257;
|
||
extra = inflate_table_lext;
|
||
extra_offset = -257; // extra -= 257;
|
||
end = 256;
|
||
break;
|
||
default: /* DISTS */
|
||
base = inflate_table_dbase;
|
||
extra = inflate_table_dext;
|
||
base_offset = 0;
|
||
extra_offset = 0;
|
||
end = -1;
|
||
}
|
||
|
||
/* initialize state for loop */
|
||
huff = 0; /* starting code */
|
||
sym = 0; /* starting code symbol */
|
||
len = min; /* starting code length */
|
||
next = table; /* current table to fill in */
|
||
curr = root; /* current table index bits */
|
||
drop = 0; /* current bits to drop from code for index */
|
||
low = -1; /* trigger new sub-table when len > root */
|
||
used = 1 << root; /* use root table entries */
|
||
mask = used - 1; /* mask for comparing low */
|
||
|
||
/* check available table space */
|
||
if ((type == LENS && used >= ENOUGH_LENS) ||
|
||
(type == DISTS && used >= ENOUGH_DISTS)) {
|
||
state.next = table;
|
||
return 1;
|
||
}
|
||
|
||
/* process all codes and make table entries */
|
||
for (;;) {
|
||
/* create table entry */
|
||
here = {op:0, bits:len - drop, val:0};
|
||
if (work[sym] < end) {
|
||
here.val = work[sym];
|
||
}
|
||
else if (work[sym] > end) {
|
||
here.op = extra[extra_offset + work[sym]];
|
||
here.val = base[base_offset + work[sym]];
|
||
}
|
||
else {
|
||
here.op = 32 + 64; /* end of block */
|
||
}
|
||
|
||
/* replicate for those indices with low len bits equal to huff */
|
||
incr = 1 << (len - drop);
|
||
fill = 1 << curr;
|
||
min = fill; /* save offset to next table */
|
||
do {
|
||
fill -= incr;
|
||
state_codes[next + (huff >>> drop) + fill] = here;
|
||
} while (fill != 0);
|
||
|
||
/* backwards increment the len-bit code huff */
|
||
incr = 1 << (len - 1);
|
||
while (huff & incr)
|
||
incr >>>= 1;
|
||
if (incr != 0) {
|
||
huff &= incr - 1;
|
||
huff += incr;
|
||
}
|
||
else
|
||
huff = 0;
|
||
|
||
/* go to next symbol, update count, len */
|
||
sym++;
|
||
if (--(count[len]) == 0) {
|
||
if (len == max) break;
|
||
len = lens[lens_offset + work[sym]];
|
||
}
|
||
|
||
/* create new sub-table if needed */
|
||
if (len > root && (huff & mask) != low) {
|
||
/* if first time, transition to sub-tables */
|
||
if (drop == 0)
|
||
drop = root;
|
||
|
||
/* increment past last table */
|
||
next += min; /* here min is 1 << curr */
|
||
|
||
/* determine length of next table */
|
||
curr = len - drop;
|
||
left = (1 << curr);
|
||
while (curr + drop < max) {
|
||
left -= count[curr + drop];
|
||
if (left <= 0) break;
|
||
curr++;
|
||
left <<= 1;
|
||
}
|
||
|
||
/* check for enough space */
|
||
used += 1 << curr;
|
||
if ((type == LENS && used >= ENOUGH_LENS) ||
|
||
(type == DISTS && used >= ENOUGH_DISTS)) {
|
||
state.next = table;
|
||
return 1;
|
||
}
|
||
|
||
/* point entry in root table to sub-table */
|
||
low = huff & mask;
|
||
state_codes[table + low] = {op:curr, bits:root, val:next - table};
|
||
}
|
||
}
|
||
|
||
/* fill in remaining table entry if code is incomplete (guaranteed to have
|
||
at most one remaining entry, since if the code is incomplete, the
|
||
maximum code length that was allowed to get this far is one bit) */
|
||
if (huff != 0) {
|
||
state_codes[next + huff] = {op:64, bits:len - drop, val:0};
|
||
}
|
||
|
||
/* set return parameters */
|
||
state.next = table + used;
|
||
if(type == DISTS) state.distbits = root; else state.lenbits = root; //*bits = root;
|
||
return 0;
|
||
}
|
||
|
||
/* inffast.c -- fast decoding
|
||
* Copyright (C) 1995-2008, 2010 Mark Adler
|
||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||
*/
|
||
|
||
/*
|
||
Decode literal, length, and distance codes and write out the resulting
|
||
literal and match bytes until either not enough input or output is
|
||
available, an end-of-block is encountered, or a data error is encountered.
|
||
When large enough input and output buffers are supplied to inflate(), for
|
||
example, a 16K input buffer and a 64K output buffer, more than 95% of the
|
||
inflate execution time is spent in this routine.
|
||
|
||
Entry assumptions:
|
||
|
||
state->mode == LEN
|
||
strm->avail_in >= 6
|
||
strm->avail_out >= 258
|
||
start >= strm->avail_out
|
||
state->bits < 8
|
||
|
||
On return, state->mode is one of:
|
||
|
||
LEN -- ran out of enough output space or enough available input
|
||
TYPE -- reached end of block code, inflate() to interpret next block
|
||
BAD -- error in block data
|
||
|
||
Notes:
|
||
|
||
- The maximum input bits used by a length/distance pair is 15 bits for the
|
||
length code, 5 bits for the length extra, 15 bits for the distance code,
|
||
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
|
||
Therefore if strm->avail_in >= 6, then there is enough input to avoid
|
||
checking for available input while decoding.
|
||
|
||
- The maximum bytes that a single length/distance pair can output is 258
|
||
bytes, which is the maximum length that can be coded. inflate_fast()
|
||
requires strm->avail_out >= 258 for each loop to avoid checking for
|
||
output space.
|
||
*/
|
||
function inflate_fast(strm,
|
||
start) /* inflate()'s starting value for strm->avail_out */
|
||
{
|
||
var state;
|
||
var input_data; /* local strm->input_data */
|
||
var next_in; /* zlib.js: index of input_data */
|
||
var last; /* while next_in < last, enough input available */
|
||
var out; /* local strm.next_out */
|
||
var beg; /* inflate()'s initial strm.next_out */
|
||
var end; /* while out < end, enough space available */
|
||
//NOSPRT #ifdef INFLATE_STRICT
|
||
// unsigned dmax; /* maximum distance from zlib header */
|
||
//#endif
|
||
var wsize; /* window size or zero if not using window */
|
||
var whave; /* valid bytes in the window */
|
||
var wnext; /* window write index */
|
||
var window; /* allocated sliding window, if wsize != 0 */
|
||
var hold; /* local strm->hold */
|
||
var bits; /* local strm->bits */
|
||
var codes; /* zlib.js: local state.codes */
|
||
var lcode; /* local strm->lencode */
|
||
var dcode; /* local strm->distcode */
|
||
var lmask; /* mask for first level of length codes */
|
||
var dmask; /* mask for first level of distance codes */
|
||
var here; /* retrieved table entry */
|
||
var op; /* code bits, operation, extra bits, or */
|
||
/* window position, window bytes to copy */
|
||
var len; /* match length, unused bytes */
|
||
var dist; /* match distance */
|
||
// var from; /* where to copy match from */
|
||
var from_window_offset = -1; /* index of window[] */
|
||
var from_out_offset = -1; /* index of next_out[] */
|
||
|
||
/* copy state to local variables */
|
||
state = strm.state;
|
||
input_data = strm.input_data;
|
||
next_in = strm.next_in;
|
||
last = next_in + strm.avail_in - 5;
|
||
out = strm.next_out;
|
||
beg = out - (start - strm.avail_out);
|
||
end = out + (strm.avail_out - 257);
|
||
//NOSPRT #ifdef INFLATE_STRICT
|
||
// dmax = state->dmax;
|
||
//#endif
|
||
wsize = state.wsize;
|
||
whave = state.whave;
|
||
wnext = state.wnext;
|
||
window = state.window;
|
||
hold = state.hold;
|
||
bits = state.bits;
|
||
codes = state.codes;
|
||
lcode = state.lencode;
|
||
dcode = state.distcode;
|
||
lmask = (1 << state.lenbits) - 1;
|
||
dmask = (1 << state.distbits) - 1;
|
||
|
||
/* decode literals and length/distances until end-of-block or not enough
|
||
input data or output space */
|
||
loop: do {
|
||
if (bits < 15) {
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
}
|
||
here = codes[lcode + (hold & lmask)];
|
||
dolen: while(true) {
|
||
op = here.bits;
|
||
hold >>>= op;
|
||
bits -= op;
|
||
op = here.op;
|
||
if (op == 0) { /* literal */
|
||
// Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||
// "inflate: literal '%c'\n" :
|
||
// "inflate: literal 0x%02x\n", here.val));
|
||
strm.output_data += String.fromCharCode(here.val);
|
||
out++;
|
||
}
|
||
else if (op & 16) { /* length base */
|
||
len = here.val;
|
||
op &= 15; /* number of extra bits */
|
||
if (op) {
|
||
if (bits < op) {
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
}
|
||
len += hold & ((1 << op) - 1);
|
||
hold >>>= op;
|
||
bits -= op;
|
||
}
|
||
// Tracevv((stderr, "inflate: length %u\n", len));
|
||
if (bits < 15) {
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
}
|
||
here = codes[dcode + (hold & dmask)];
|
||
dodist: while(true) {
|
||
op = here.bits;
|
||
hold >>>= op;
|
||
bits -= op;
|
||
op = here.op;
|
||
if (op & 16) { /* distance base */
|
||
dist = here.val;
|
||
op &= 15; /* number of extra bits */
|
||
if (bits < op) {
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
if (bits < op) {
|
||
hold += (input_data.charCodeAt(next_in++) & 0xff) << bits;
|
||
bits += 8;
|
||
}
|
||
}
|
||
dist += hold & ((1 << op) - 1);
|
||
//NOSPRT #ifdef INFLATE_STRICT
|
||
// if (dist > dmax) {
|
||
// strm->msg = (char *)"invalid distance too far back";
|
||
// state->mode = BAD;
|
||
// break loop;
|
||
// }
|
||
//#endif
|
||
hold >>>= op;
|
||
bits -= op;
|
||
// Tracevv((stderr, "inflate: distance %u\n", dist));
|
||
op = out - beg; /* max distance in output */
|
||
if (dist > op) { /* see if copy from window */
|
||
op = dist - op; /* distance back in window */
|
||
if (op > whave) {
|
||
if (state.sane) {
|
||
strm.msg = 'invalid distance too far back';
|
||
state.mode = BAD;
|
||
break loop;
|
||
}
|
||
//NOSPRT #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||
// if (len <= op - whave) {
|
||
// do {
|
||
// PUP(out) = 0;
|
||
// } while (--len);
|
||
// continue;
|
||
// }
|
||
// len -= op - whave;
|
||
// do {
|
||
// PUP(out) = 0;
|
||
// } while (--op > whave);
|
||
// if (op == 0) {
|
||
// from = out - dist;
|
||
// do {
|
||
// PUP(out) = PUP(from);
|
||
// } while (--len);
|
||
// continue;
|
||
// }
|
||
//#endif
|
||
} // if (op > whave)
|
||
|
||
from_window_offset = 0;
|
||
from_out_offset = -1;
|
||
if (wnext == 0) { /* very common case */
|
||
from_window_offset += wsize - op;
|
||
if (op < len) { /* some from window */
|
||
len -= op;
|
||
strm.output_data += window.substring(from_window_offset, from_window_offset + op);
|
||
out += op;
|
||
op = 0;
|
||
from_window_offset = -1;
|
||
from_out_offset = out - dist; /* rest from output */
|
||
}
|
||
}
|
||
//NOTREACHED else if (wnext < op) { /* wrap around window */
|
||
//NOTREACHED from += wsize + wnext - op;
|
||
//NOTREACHED op -= wnext;
|
||
//NOTREACHED if (op < len) { /* some from end of window */
|
||
//NOTREACHED len -= op;
|
||
//NOTREACHED do {
|
||
//NOTREACHED PUP(out) = PUP(from);
|
||
//NOTREACHED } while (--op);
|
||
//NOTREACHED from = window - OFF;
|
||
//NOTREACHED if (wnext < len) { /* some from start of window */
|
||
//NOTREACHED op = wnext;
|
||
//NOTREACHED len -= op;
|
||
//NOTREACHED do {
|
||
//NOTREACHED PUP(out) = PUP(from);
|
||
//NOTREACHED } while (--op);
|
||
//NOTREACHED from = out - dist; /* rest from output */
|
||
//NOTREACHED }
|
||
//NOTREACHED }
|
||
//NOTREACHED }
|
||
else { /* contiguous in window */
|
||
from_window_offset += wnext - op;
|
||
if (op < len) { /* some from window */
|
||
len -= op;
|
||
strm.output_data += window.substring(from_window_offset, from_window_offset + op);
|
||
out += op;
|
||
from_window_offset = -1;
|
||
from_out_offset = out - dist; /* rest from output */
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
from_window_offset = -1;
|
||
from_out_offset = out - dist; /* copy direct from output */
|
||
}
|
||
|
||
if (from_window_offset >= 0) {
|
||
strm.output_data += window.substring(from_window_offset, from_window_offset + len);
|
||
out += len;
|
||
from_window_offset += len;
|
||
} else {
|
||
var len_inner = len;
|
||
if(len_inner > out - from_out_offset)
|
||
len_inner = out - from_out_offset;
|
||
strm.output_data += strm.output_data.substring(
|
||
from_out_offset, from_out_offset + len_inner);
|
||
out += len_inner;
|
||
len -= len_inner;
|
||
from_out_offset += len_inner;
|
||
out += len;
|
||
while (len > 2) {
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
len -= 3;
|
||
}
|
||
if (len) {
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
if (len > 1)
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
}
|
||
}
|
||
}
|
||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||
here = codes[dcode + (here.val + (hold & ((1 << op) - 1)))];
|
||
continue dodist; // goto dodist
|
||
}
|
||
else {
|
||
strm.msg = 'invalid distance code';
|
||
state.mode = BAD;
|
||
break loop;
|
||
}
|
||
break dodist; }
|
||
}
|
||
else if ((op & 64) == 0) { /* 2nd level length code */
|
||
here = codes[lcode + (here.val + (hold & ((1 << op) - 1)))];
|
||
continue dolen; // goto dolen;
|
||
}
|
||
else if (op & 32) { /* end-of-block */
|
||
// Tracevv((stderr, "inflate: end of block\n"));
|
||
state.mode = TYPE;
|
||
break loop;
|
||
}
|
||
else {
|
||
strm.msg = 'invalid literal/length code';
|
||
state.mode = BAD;
|
||
break loop;
|
||
}
|
||
break dolen; }
|
||
} while (next_in < last && out < end);
|
||
|
||
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
|
||
len = bits >>> 3;
|
||
next_in -= len;
|
||
bits -= len << 3;
|
||
hold &= (1 << bits) - 1;
|
||
|
||
/* update state and return */
|
||
strm.next_in = next_in;
|
||
strm.next_out = out;
|
||
strm.avail_in = (next_in < last ? 5 + (last - next_in) : 5 - (next_in - last));
|
||
strm.avail_out = (out < end ?
|
||
257 + (end - out) : 257 - (out - end));
|
||
state.hold = hold;
|
||
state.bits = bits;
|
||
}
|
||
|
||
function new_array(size)
|
||
{
|
||
var i;
|
||
var ary = new Array(size);
|
||
for(i = 0; i < size; i++)
|
||
ary[i] = 0;
|
||
return ary;
|
||
}
|
||
|
||
function getarg(opts, name, def_value)
|
||
{
|
||
return (opts && (name in opts)) ? opts[name] : def_value;
|
||
}
|
||
|
||
function checksum_none()
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* z_stream constructor
|
||
* @constructor
|
||
*/
|
||
function inflate_state()
|
||
{
|
||
var i;
|
||
|
||
this.mode = 0; /* current inflate mode */
|
||
this.last = 0; /* true if processing last block */
|
||
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
|
||
this.havedict = 0; /* true if dictionary provided */
|
||
this.flags = 0; /* gzip header method and flags (0 if zlib) */
|
||
this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
|
||
this.check = 0; /* protected copy of check value */
|
||
this.total = 0; /* protected copy of output count */
|
||
this.head = null; /* where to save gzip header information */
|
||
/* sliding window */
|
||
this.wbits = 0; /* log base 2 of requested window size */
|
||
this.wsize = 0; /* window size or zero if not using window */
|
||
this.whave = 0; /* valid bytes in the window */
|
||
this.wnext = 0; /* window write index (TODO remove) */
|
||
this.window = null; /* allocated sliding window, if needed */
|
||
/* bit accumulator */
|
||
this.hold = 0; /* input bit accumulator */
|
||
this.bits = 0; /* number of bits in "in" */
|
||
/* for string and stored block copying */
|
||
this.length = 0; /* literal or length of data to copy */
|
||
this.offset = 0; /* distance back to copy string from */
|
||
/* for table and code decoding */
|
||
this.extra = 0; /* extra bits needed */
|
||
/* fixed and dynamic code tables */
|
||
|
||
/* zlib.js: modified implementation: lencode, distcode, next are offset of codes[] */
|
||
this.lencode = 0; /* starting table for length/literal codes */
|
||
this.distcode = 0; /* starting table for distance codes */
|
||
this.lenbits = 0; /* index bits for lencode */
|
||
this.distbits = 0; /* index bits for distcode */
|
||
/* dynamic table building */
|
||
this.ncode = 0; /* number of code length code lengths */
|
||
this.nlen = 0; /* number of length code lengths */
|
||
this.ndist = 0; /* number of distance code lengths */
|
||
this.have = 0; /* number of code lengths in lens[] */
|
||
this.next = 0; /* next available space in codes[] */
|
||
this.lens = new_array(320); /* temporary storage for code lengths */
|
||
this.work = new_array(288); /* work area for code table building */
|
||
this.codes = new Array(ENOUGH); /* space for code tables */
|
||
var c = {op:0, bits:0, val:0};
|
||
for(i = 0; i < ENOUGH; i++)
|
||
this.codes[i] = c;
|
||
this.sane = 0; /* if false, allow invalid distance too far */
|
||
this.back = 0; /* bits back of last unprocessed length/lit */
|
||
this.was = 0; /* initial length of match */
|
||
}
|
||
|
||
ZLIB.inflateResetKeep = function(strm)
|
||
{
|
||
var state;
|
||
|
||
if (!strm || !strm.state) return ZLIB.Z_STREAM_ERROR;
|
||
state = strm.state;
|
||
strm.total_in = strm.total_out = state.total = 0;
|
||
strm.msg = null;
|
||
if (state.wrap) { /* to support ill-conceived Java test suite */
|
||
strm.adler = state.wrap & 1;
|
||
}
|
||
|
||
state.mode = HEAD;
|
||
state.last = 0;
|
||
state.havedict = 0;
|
||
state.dmax = 32768;
|
||
state.head = null;
|
||
state.hold = 0;
|
||
state.bits = 0;
|
||
state.lencode = 0;
|
||
state.distcode = 0;
|
||
state.next = 0;
|
||
state.sane = 1;
|
||
state.back = -1;
|
||
return ZLIB.Z_OK;
|
||
};
|
||
|
||
// Usage: strm = ZLIB.inflateReset(z_stream [, windowBits]);
|
||
ZLIB.inflateReset = function(strm, windowBits)
|
||
{
|
||
var wrap;
|
||
var state;
|
||
|
||
/* get the state */
|
||
if (!strm || !strm.state) return ZLIB.Z_STREAM_ERROR;
|
||
state = strm.state;
|
||
|
||
if(typeof windowBits === "undefined")
|
||
windowBits = DEF_WBITS;
|
||
|
||
/* extract wrap request from windowBits parameter */
|
||
if (windowBits < 0) {
|
||
wrap = 0;
|
||
windowBits = -windowBits;
|
||
}
|
||
else {
|
||
wrap = (windowBits >>> 4) + 1;
|
||
if (windowBits < 48)
|
||
windowBits &= 15;
|
||
}
|
||
|
||
if(wrap == 1 && (typeof ZLIB.adler32 === 'function')) {
|
||
strm.checksum_function = ZLIB.adler32;
|
||
} else if(wrap == 2 && (typeof ZLIB.crc32 === 'function')) {
|
||
strm.checksum_function = ZLIB.crc32;
|
||
} else {
|
||
strm.checksum_function = checksum_none;
|
||
}
|
||
|
||
/* set number of window bits, free window if different */
|
||
if (windowBits && (windowBits < 8 || windowBits > 15))
|
||
return ZLIB.Z_STREAM_ERROR;
|
||
if (state.window && state.wbits != windowBits) {
|
||
state.window = null;
|
||
}
|
||
|
||
/* update state and reset the rest of it */
|
||
state.wrap = wrap;
|
||
state.wbits = windowBits;
|
||
state.wsize = 0;
|
||
state.whave = 0;
|
||
state.wnext = 0;
|
||
return ZLIB.inflateResetKeep(strm);
|
||
};
|
||
|
||
// Usage: strm = ZLIB.inflateInit([windowBits]);
|
||
ZLIB.inflateInit = function(windowBits)
|
||
{
|
||
var strm = new ZLIB.z_stream();
|
||
strm.state = new inflate_state();
|
||
ZLIB.inflateReset(strm, windowBits);
|
||
return strm;
|
||
};
|
||
|
||
ZLIB.inflatePrime = function(strm, bits, value)
|
||
{
|
||
var state;
|
||
|
||
if (!strm || !strm.state) return ZLIB.Z_STREAM_ERROR;
|
||
state = strm.state;
|
||
if (bits < 0) {
|
||
state.hold = 0;
|
||
state.bits = 0;
|
||
return ZLIB.Z_OK;
|
||
}
|
||
if (bits > 16 || state.bits + bits > 32) return ZLIB.Z_STREAM_ERROR;
|
||
value &= (1 << bits) - 1;
|
||
state.hold += value << state.bits;
|
||
state.bits += bits;
|
||
return ZLIB.Z_OK;
|
||
};
|
||
|
||
var lenfix_ary = null;
|
||
var distfix_ary = null;
|
||
function fixedtables(state)
|
||
{
|
||
var i;
|
||
if (!lenfix_ary) lenfix_ary = [ { op: 96, bits: 7, val: 0 }, { op: 0, bits: 8, val: 80 }, { op: 0, bits: 8, val: 16 }, { op: 20, bits: 8, val: 115 }, { op: 18, bits: 7, val: 31 }, { op: 0, bits: 8, val: 112 }, { op: 0, bits: 8, val: 48 }, { op: 0, bits: 9, val: 192 }, { op: 16, bits: 7, val: 10 }, { op: 0, bits: 8, val: 96 }, { op: 0, bits: 8, val: 32 }, { op: 0, bits: 9, val: 160 }, { op: 0, bits: 8, val: 0 }, { op: 0, bits: 8, val: 128 }, { op: 0, bits: 8, val: 64 }, { op: 0, bits: 9, val: 224 }, { op: 16, bits: 7, val: 6 }, { op: 0, bits: 8, val: 88 }, { op: 0, bits: 8, val: 24 }, { op: 0, bits: 9, val: 144 }, { op: 19, bits: 7, val: 59 }, { op: 0, bits: 8, val: 120 }, { op: 0, bits: 8, val: 56 }, { op: 0, bits: 9, val: 208 }, { op: 17, bits: 7, val: 17 }, { op: 0, bits: 8, val: 104 }, { op: 0, bits: 8, val: 40 }, { op: 0, bits: 9, val: 176 }, { op: 0, bits: 8, val: 8 }, { op: 0, bits: 8, val: 136 }, { op: 0, bits: 8, val: 72 }, { op: 0, bits: 9, val: 240 }, { op: 16, bits: 7, val: 4 }, { op: 0, bits: 8, val: 84 }, { op: 0, bits: 8, val: 20 }, { op: 21, bits: 8, val: 227 }, { op: 19, bits: 7, val: 43 }, { op: 0, bits: 8, val: 116 }, { op: 0, bits: 8, val: 52 }, { op: 0, bits: 9, val: 200 }, { op: 17, bits: 7, val: 13 }, { op: 0, bits: 8, val: 100 }, { op: 0, bits: 8, val: 36 }, { op: 0, bits: 9, val: 168 }, { op: 0, bits: 8, val: 4 }, { op: 0, bits: 8, val: 132 }, { op: 0, bits: 8, val: 68 }, { op: 0, bits: 9, val: 232 }, { op: 16, bits: 7, val: 8 }, { op: 0, bits: 8, val: 92 }, { op: 0, bits: 8, val: 28 }, { op: 0, bits: 9, val: 152 }, { op: 20, bits: 7, val: 83 }, { op: 0, bits: 8, val: 124 }, { op: 0, bits: 8, val: 60 }, { op: 0, bits: 9, val: 216 }, { op: 18, bits: 7, val: 23 }, { op: 0, bits: 8, val: 108 }, { op: 0, bits: 8, val: 44 }, { op: 0, bits: 9, val: 184 }, { op: 0, bits: 8, val: 12 }, { op: 0, bits: 8, val: 140 }, { op: 0, bits: 8, val: 76 }, { op: 0, bits: 9, val: 248 }, { op: 16, bits: 7, val: 3 }, { op: 0, bits: 8, val: 82 }, { op: 0, bits: 8, val: 18 }, { op: 21, bits: 8, val: 163 }, { op: 19, bits: 7, val: 35 }, { op: 0, bits: 8, val: 114 }, { op: 0, bits: 8, val: 50 }, { op: 0, bits: 9, val: 196 }, { op: 17, bits: 7, val: 11 }, { op: 0, bits: 8, val: 98 }, { op: 0, bits: 8, val: 34 }, { op: 0, bits: 9, val: 164 }, { op: 0, bits: 8, val: 2 }, { op: 0, bits: 8, val: 130 }, { op: 0, bits: 8, val: 66 }, { op: 0, bits: 9, val: 228 }, { op: 16, bits: 7, val: 7 }, { op: 0, bits: 8, val: 90 }, { op: 0, bits: 8, val: 26 }, { op: 0, bits: 9, val: 148 }, { op: 20, bits: 7, val: 67 }, { op: 0, bits: 8, val: 122 }, { op: 0, bits: 8, val: 58 }, { op: 0, bits: 9, val: 212 }, { op: 18, bits: 7, val: 19 }, { op: 0, bits: 8, val: 106 }, { op: 0, bits: 8, val: 42 }, { op: 0, bits: 9, val: 180 }, { op: 0, bits: 8, val: 10 }, { op: 0, bits: 8, val: 138 }, { op: 0, bits: 8, val: 74 }, { op: 0, bits: 9, val: 244 }, { op: 16, bits: 7, val: 5 }, { op: 0, bits: 8, val: 86 }, { op: 0, bits: 8, val: 22 }, { op: 64, bits: 8, val: 0 }, { op: 19, bits: 7, val: 51 }, { op: 0, bits: 8, val: 118 }, { op: 0, bits: 8, val: 54 }, { op: 0, bits: 9, val: 204 }, { op: 17, bits: 7, val: 15 }, { op: 0, bits: 8, val: 102 }, { op: 0, bits: 8, val: 38 }, { op: 0, bits: 9, val: 172 }, { op: 0, bits: 8, val: 6 }, { op: 0, bits: 8, val: 134 }, { op: 0, bits: 8, val: 70 }, { op: 0, bits: 9, val: 236 }, { op: 16, bits: 7, val: 9 }, { op: 0, bits: 8, val: 94 }, { op: 0, bits: 8, val: 30 }, { op: 0, bits: 9, val: 156 }, { op: 20, bits: 7, val: 99 }, { op: 0, bits: 8, val: 126 }, { op: 0, bits: 8, val: 62 }, { op: 0, bits: 9, val: 220 }, { op: 18, bits: 7, val: 27 }, { op: 0, bits: 8, val: 110 }, { op: 0, bits: 8, val: 46 }, { op: 0, bits: 9, val: 188 }, { op: 0, bits: 8, val: 14 }, { op: 0, bits: 8, val: 142 }, { op: 0, bits: 8, val: 78 }, { op: 0, bits: 9, val: 252 }, { op: 96, bits: 7, val: 0 }, { op: 0, bits: 8, val: 81 }, { op: 0, bits: 8, val: 17 }, { op: 21, bits: 8, val: 131 }, { op: 18, bits: 7, val: 31 }, { op: 0, bits: 8, val: 113 }, { op: 0, bits: 8, val: 49 }, { op: 0, bits: 9, val: 194 }, { op: 16, bits: 7, val: 10 }, { op: 0, bits: 8, val: 97 }, { op: 0, bits: 8, val: 33 }, { op: 0, bits: 9, val: 162 }, { op: 0, bits: 8, val: 1 }, { op: 0, bits: 8, val: 129 }, { op: 0, bits: 8, val: 65 }, { op: 0, bits: 9, val: 226 }, { op: 16, bits: 7, val: 6 }, { op: 0, bits: 8, val: 89 }, { op: 0, bits: 8, val: 25 }, { op: 0, bits: 9, val: 146 }, { op: 19, bits: 7, val: 59 }, { op: 0, bits: 8, val: 121 }, { op: 0, bits: 8, val: 57 }, { op: 0, bits: 9, val: 210 }, { op: 17, bits: 7, val: 17 }, { op: 0, bits: 8, val: 105 }, { op: 0, bits: 8, val: 41 }, { op: 0, bits: 9, val: 178 }, { op: 0, bits: 8, val: 9 }, { op: 0, bits: 8, val: 137 }, { op: 0, bits: 8, val: 73 }, { op: 0, bits: 9, val: 242 }, { op: 16, bits: 7, val: 4 }, { op: 0, bits: 8, val: 85 }, { op: 0, bits: 8, val: 21 }, { op: 16, bits: 8, val: 258 }, { op: 19, bits: 7, val: 43 }, { op: 0, bits: 8, val: 117 }, { op: 0, bits: 8, val: 53 }, { op: 0, bits: 9, val: 202 }, { op: 17, bits: 7, val: 13 }, { op: 0, bits: 8, val: 101 }, { op: 0, bits: 8, val: 37 }, { op: 0, bits: 9, val: 170 }, { op: 0, bits: 8, val: 5 }, { op: 0, bits: 8, val: 133 }, { op: 0, bits: 8, val: 69 }, { op: 0, bits: 9, val: 234 }, { op: 16, bits: 7, val: 8 }, { op: 0, bits: 8, val: 93 }, { op: 0, bits: 8, val: 29 }, { op: 0, bits: 9, val: 154 }, { op: 20, bits: 7, val: 83 }, { op: 0, bits: 8, val: 125 }, { op: 0, bits: 8, val: 61 }, { op: 0, bits: 9, val: 218 }, { op: 18, bits: 7, val: 23 }, { op: 0, bits: 8, val: 109 }, { op: 0, bits: 8, val: 45 }, { op: 0, bits: 9, val: 186 }, { op: 0, bits: 8, val: 13 }, { op: 0, bits: 8, val: 141 }, { op: 0, bits: 8, val: 77 }, { op: 0, bits: 9, val: 250 }, { op: 16, bits: 7, val: 3 }, { op: 0, bits: 8, val: 83 }, { op: 0, bits: 8, val: 19 }, { op: 21, bits: 8, val: 195 }, { op: 19, bits: 7, val: 35 }, { op: 0, bits: 8, val: 115 }, { op: 0, bits: 8, val: 51 }, { op: 0, bits: 9, val: 198 }, { op: 17, bits: 7, val: 11 }, { op: 0, bits: 8, val: 99 }, { op: 0, bits: 8, val: 35 }, { op: 0, bits: 9, val: 166 }, { op: 0, bits: 8, val: 3 }, { op: 0, bits: 8, val: 131 }, { op: 0, bits: 8, val: 67 }, { op: 0, bits: 9, val: 230 }, { op: 16, bits: 7, val: 7 }, { op: 0, bits: 8, val: 91 }, { op: 0, bits: 8, val: 27 }, { op: 0, bits: 9, val: 150 }, { op: 20, bits: 7, val: 67 }, { op: 0, bits: 8, val: 123 }, { op: 0, bits: 8, val: 59 }, { op: 0, bits: 9, val: 214 }, { op: 18, bits: 7, val: 19 }, { op: 0, bits: 8, val: 107 }, { op: 0, bits: 8, val: 43 }, { op: 0, bits: 9, val: 182 }, { op: 0, bits: 8, val: 11 }, { op: 0, bits: 8, val: 139 }, { op: 0, bits: 8, val: 75 }, { op: 0, bits: 9, val: 246 }, { op: 16, bits: 7, val: 5 }, { op: 0, bits: 8, val: 87 }, { op: 0, bits: 8, val: 23 }, { op: 64, bits: 8, val: 0 }, { op: 19, bits: 7, val: 51 }, { op: 0, bits: 8, val: 119 }, { op: 0, bits: 8, val: 55 }, { op: 0, bits: 9, val: 206 }, { op: 17, bits: 7, val: 15 }, { op: 0, bits: 8, val: 103 }, { op: 0, bits: 8, val: 39 }, { op: 0, bits: 9, val: 174 }, { op: 0, bits: 8, val: 7 }, { op: 0, bits: 8, val: 135 }, { op: 0, bits: 8, val: 71 }, { op: 0, bits: 9, val: 238 }, { op: 16, bits: 7, val: 9 }, { op: 0, bits: 8, val: 95 }, { op: 0, bits: 8, val: 31 }, { op: 0, bits: 9, val: 158 }, { op: 20, bits: 7, val: 99 }, { op: 0, bits: 8, val: 127 }, { op: 0, bits: 8, val: 63 }, { op: 0, bits: 9, val: 222 }, { op: 18, bits: 7, val: 27 }, { op: 0, bits: 8, val: 111 }, { op: 0, bits: 8, val: 47 }, { op: 0, bits: 9, val: 190 }, { op: 0, bits: 8, val: 15 }, { op: 0, bits: 8, val: 143 }, { op: 0, bits: 8, val: 79 }, { op: 0, bits: 9, val: 254 }, { op: 96, bits: 7, val: 0 }, { op: 0, bits: 8, val: 80 }, { op: 0, bits: 8, val: 16 }, { op: 20, bits: 8, val: 115 }, { op: 18, bits: 7, val: 31 }, { op: 0, bits: 8, val: 112 }, { op: 0, bits: 8, val: 48 }, { op: 0, bits: 9, val: 193 }, { op: 16, bits: 7, val: 10 }, { op: 0, bits: 8, val: 96 }, { op: 0, bits: 8, val: 32 }, { op: 0, bits: 9, val: 161 }, { op: 0, bits: 8, val: 0 }, { op: 0, bits: 8, val: 128 }, { op: 0, bits: 8, val: 64 }, { op: 0, bits: 9, val: 225 }, { op: 16, bits: 7, val: 6 }, { op: 0, bits: 8, val: 88 }, { op: 0, bits: 8, val: 24 }, { op: 0, bits: 9, val: 145 }, { op: 19, bits: 7, val: 59 }, { op: 0, bits: 8, val: 120 }, { op: 0, bits: 8, val: 56 }, { op: 0, bits: 9, val: 209 }, { op: 17, bits: 7, val: 17 }, { op: 0, bits: 8, val: 104 }, { op: 0, bits: 8, val: 40 }, { op: 0, bits: 9, val: 177 }, { op: 0, bits: 8, val: 8 }, { op: 0, bits: 8, val: 136 }, { op: 0, bits: 8, val: 72 }, { op: 0, bits: 9, val: 241 }, { op: 16, bits: 7, val: 4 }, { op: 0, bits: 8, val: 84 }, { op: 0, bits: 8, val: 20 }, { op: 21, bits: 8, val: 227 }, { op: 19, bits: 7, val: 43 }, { op: 0, bits: 8, val: 116 }, { op: 0, bits: 8, val: 52 }, { op: 0, bits: 9, val: 201 }, { op: 17, bits: 7, val: 13 }, { op: 0, bits: 8, val: 100 }, { op: 0, bits: 8, val: 36 }, { op: 0, bits: 9, val: 169 }, { op: 0, bits: 8, val: 4 }, { op: 0, bits: 8, val: 132 }, { op: 0, bits: 8, val: 68 }, { op: 0, bits: 9, val: 233 }, { op: 16, bits: 7, val: 8 }, { op: 0, bits: 8, val: 92 }, { op: 0, bits: 8, val: 28 }, { op: 0, bits: 9, val: 153 }, { op: 20, bits: 7, val: 83 }, { op: 0, bits: 8, val: 124 }, { op: 0, bits: 8, val: 60 }, { op: 0, bits: 9, val: 217 }, { op: 18, bits: 7, val: 23 }, { op: 0, bits: 8, val: 108 }, { op: 0, bits: 8, val: 44 }, { op: 0, bits: 9, val: 185 }, { op: 0, bits: 8, val: 12 }, { op: 0, bits: 8, val: 140 }, { op: 0, bits: 8, val: 76 }, { op: 0, bits: 9, val: 249 }, { op: 16, bits: 7, val: 3 }, { op: 0, bits: 8, val: 82 }, { op: 0, bits: 8, val: 18 }, { op: 21, bits: 8, val: 163 }, { op: 19, bits: 7, val: 35 }, { op: 0, bits: 8, val: 114 }, { op: 0, bits: 8, val: 50 }, { op: 0, bits: 9, val: 197 }, { op: 17, bits: 7, val: 11 }, { op: 0, bits: 8, val: 98 }, { op: 0, bits: 8, val: 34 }, { op: 0, bits: 9, val: 165 }, { op: 0, bits: 8, val: 2 }, { op: 0, bits: 8, val: 130 }, { op: 0, bits: 8, val: 66 }, { op: 0, bits: 9, val: 229 }, { op: 16, bits: 7, val: 7 }, { op: 0, bits: 8, val: 90 }, { op: 0, bits: 8, val: 26 }, { op: 0, bits: 9, val: 149 }, { op: 20, bits: 7, val: 67 }, { op: 0, bits: 8, val: 122 }, { op: 0, bits: 8, val: 58 },{ op: 0, bits: 9, val: 213 }, { op: 18, bits: 7, val: 19 }, { op: 0, bits: 8, val: 106 }, { op: 0, bits: 8, val: 42 }, { op: 0, bits: 9, val: 181 }, { op: 0, bits: 8, val: 10 }, { op: 0, bits: 8, val: 138 },{ op: 0, bits: 8, val: 74 }, { op: 0, bits: 9, val: 245 }, { op: 16, bits: 7, val: 5 }, { op: 0, bits: 8, val: 86 }, { op: 0, bits: 8, val: 22 }, { op: 64, bits: 8, val: 0 }, { op: 19, bits: 7, val: 51 },{ op: 0, bits: 8, val: 118 }, { op: 0, bits: 8, val: 54 }, { op: 0, bits: 9, val: 205 }, { op: 17, bits: 7, val: 15 }, { op: 0, bits: 8, val: 102 }, { op: 0, bits: 8, val: 38 }, { op: 0, bits: 9, val: 173 },{ op: 0, bits: 8, val: 6 }, { op: 0, bits: 8, val: 134 }, { op: 0, bits: 8, val: 70 }, { op: 0, bits: 9, val: 237 }, { op: 16, bits: 7, val: 9 }, { op: 0, bits: 8, val: 94 }, { op: 0, bits: 8, val: 30 },{ op: 0, bits: 9, val: 157 }, { op: 20, bits: 7, val: 99 }, { op: 0, bits: 8, val: 126 }, { op: 0, bits: 8, val: 62 }, { op: 0, bits: 9, val: 221 }, { op: 18, bits: 7, val: 27 }, { op: 0, bits: 8, val: 110 }, { op: 0, bits: 8, val: 46 }, { op: 0, bits: 9, val: 189 }, { op: 0, bits: 8, val: 14 }, { op: 0, bits: 8, val: 142 }, { op: 0, bits: 8, val: 78 }, { op: 0, bits: 9, val: 253 }, { op: 96, bits: 7, val: 0 }, { op: 0, bits: 8, val: 81 }, { op: 0, bits: 8, val: 17 }, { op: 21, bits: 8, val: 131 }, { op: 18, bits: 7, val: 31 }, { op: 0, bits: 8, val: 113 }, { op: 0, bits: 8, val: 49 }, { op: 0, bits: 9, val: 195 }, { op: 16, bits: 7, val: 10 }, { op: 0, bits: 8, val: 97 }, { op: 0, bits: 8, val: 33 }, { op: 0, bits: 9, val: 163 }, { op: 0, bits: 8, val: 1 }, { op: 0, bits: 8, val: 129 }, { op: 0, bits: 8, val: 65 }, { op: 0, bits: 9, val: 227 }, { op: 16, bits: 7, val: 6 }, { op: 0, bits: 8, val: 89 }, { op: 0, bits: 8, val: 25 }, { op: 0, bits: 9, val: 147 }, { op: 19, bits: 7, val: 59 }, { op: 0, bits: 8, val: 121 }, { op: 0, bits: 8, val: 57 }, { op: 0, bits: 9, val: 211 }, { op: 17, bits: 7, val: 17 }, { op: 0, bits: 8, val: 105 }, { op: 0, bits: 8, val: 41 }, { op: 0, bits: 9, val: 179 }, { op: 0, bits: 8, val: 9 },{ op: 0, bits: 8, val: 137 }, { op: 0, bits: 8, val: 73 }, { op: 0, bits: 9, val: 243 }, { op: 16, bits: 7, val: 4 }, { op: 0, bits: 8, val: 85 }, { op: 0, bits: 8, val: 21 }, { op: 16, bits: 8, val: 258 },{ op: 19, bits: 7, val: 43 }, { op: 0, bits: 8, val: 117 }, { op: 0, bits: 8, val: 53 }, { op: 0, bits: 9, val: 203 }, { op: 17, bits: 7, val: 13 }, { op: 0, bits: 8, val: 101 }, { op: 0, bits: 8, val: 37 },{ op: 0, bits: 9, val: 171 }, { op: 0, bits: 8, val: 5 }, { op: 0, bits: 8, val: 133 }, { op: 0, bits: 8, val: 69 }, { op: 0, bits: 9, val: 235 }, { op: 16, bits: 7, val: 8 }, { op: 0, bits: 8, val: 93 },{ op: 0, bits: 8, val: 29 }, { op: 0, bits: 9, val: 155 }, { op: 20, bits: 7, val: 83 }, { op: 0, bits: 8, val: 125 }, { op: 0, bits: 8, val: 61 }, { op: 0, bits: 9, val: 219 }, { op: 18, bits: 7, val: 23 },{ op: 0, bits: 8, val: 109 }, { op: 0, bits: 8, val: 45 }, { op: 0, bits: 9, val: 187 }, { op: 0, bits: 8, val: 13 }, { op: 0, bits: 8, val: 141 }, { op: 0, bits: 8, val: 77 }, { op: 0, bits: 9, val: 251 }, { op: 16, bits: 7, val: 3 }, { op: 0, bits: 8, val: 83 }, { op: 0, bits: 8, val: 19 }, { op: 21, bits: 8, val: 195 }, { op: 19, bits: 7, val: 35 }, { op: 0, bits: 8, val: 115 }, { op: 0, bits: 8, val: 51 }, { op: 0, bits: 9, val: 199 }, { op: 17, bits: 7, val: 11 }, { op: 0, bits: 8, val: 99 }, { op: 0, bits: 8, val: 35 }, { op: 0, bits: 9, val: 167 }, { op: 0, bits: 8, val: 3 }, { op: 0, bits: 8, val: 131 }, { op: 0, bits: 8, val: 67 }, { op: 0, bits: 9, val: 231 }, { op: 16, bits: 7, val: 7 }, { op: 0, bits: 8, val: 91 }, { op: 0, bits: 8, val: 27 }, { op: 0, bits: 9, val: 151 }, { op: 20, bits: 7, val: 67 }, { op: 0, bits: 8, val: 123 }, { op: 0, bits: 8, val: 59 }, { op: 0, bits: 9, val: 215 }, { op: 18, bits: 7, val: 19 }, { op: 0, bits: 8, val: 107 }, { op: 0, bits: 8, val: 43 }, { op: 0, bits: 9, val: 183 }, { op: 0, bits: 8, val: 11 }, { op: 0, bits: 8, val: 139 }, { op: 0, bits: 8, val: 75 }, { op: 0, bits: 9, val: 247 }, { op: 16, bits: 7, val: 5 }, { op: 0, bits: 8, val: 87 }, { op: 0, bits: 8, val: 23 }, { op: 64, bits: 8, val: 0 }, { op: 19, bits: 7, val: 51 }, { op: 0, bits: 8, val: 119 }, { op: 0, bits: 8, val: 55 }, { op: 0, bits: 9, val: 207 }, { op: 17, bits: 7, val: 15 }, { op: 0, bits: 8, val: 103 }, { op: 0, bits: 8, val: 39 }, { op: 0, bits: 9, val: 175 }, { op: 0, bits: 8, val: 7 }, { op: 0, bits: 8, val: 135 }, { op: 0, bits: 8, val: 71 }, { op: 0, bits: 9, val: 239 }, { op: 16, bits: 7, val: 9 }, { op: 0, bits: 8, val: 95 }, { op: 0, bits: 8, val: 31 }, { op: 0, bits: 9, val: 159 }, { op: 20, bits: 7, val: 99 }, { op: 0, bits: 8, val: 127 }, { op: 0, bits: 8, val: 63 }, { op: 0, bits: 9, val: 223 }, { op: 18, bits: 7, val: 27 }, { op: 0, bits: 8, val: 111 }, { op: 0, bits: 8, val: 47 }, { op: 0, bits: 9, val: 191 }, { op: 0, bits: 8, val: 15 }, { op: 0, bits: 8, val: 143 }, { op: 0, bits: 8, val: 79 }, { op: 0, bits: 9, val: 255 } ];
|
||
if (!distfix_ary) distfix_ary = [ { op: 16, bits: 5, val: 1 }, { op: 23, bits: 5, val: 257 }, { op: 19, bits: 5, val: 17 }, { op: 27, bits: 5, val: 4097 }, { op: 17, bits: 5, val: 5 }, { op: 25, bits: 5, val: 1025 }, { op: 21, bits: 5, val: 65 }, { op: 29, bits: 5, val: 16385 }, { op: 16, bits: 5, val: 3 }, { op: 24, bits: 5, val: 513 }, { op: 20, bits: 5, val: 33 }, { op: 28, bits: 5, val: 8193 }, { op: 18, bits: 5, val: 9 }, { op: 26, bits: 5, val: 2049 }, { op: 22, bits: 5, val: 129 }, { op: 64, bits: 5, val: 0 }, { op: 16, bits: 5, val: 2 }, { op: 23, bits: 5, val: 385 }, { op: 19, bits: 5, val: 25 }, { op: 27, bits: 5, val: 6145 }, { op: 17, bits: 5, val: 7 }, { op: 25, bits: 5, val: 1537 }, { op: 21, bits: 5, val: 97 }, { op: 29, bits: 5, val: 24577 }, { op: 16, bits: 5, val: 4 }, { op: 24, bits: 5, val: 769 }, { op: 20, bits: 5, val: 49 }, { op: 28, bits: 5, val: 12289 }, { op: 18, bits: 5, val: 13 }, { op: 26, bits: 5, val: 3073 }, { op: 22, bits: 5, val: 193 }, { op: 64, bits: 5, val: 0 } ];
|
||
state.lencode = 0;
|
||
state.distcode = 512;
|
||
for (i = 0; i < 512; i++) { state.codes[i] = lenfix_ary[i]; }
|
||
for (i = 0; i < 32; i++) { state.codes[i + 512] = distfix_ary[i]; }
|
||
state.lenbits = 9;
|
||
state.distbits = 5;
|
||
}
|
||
|
||
/*
|
||
Update the window with the last wsize (normally 32K) bytes written before
|
||
returning. If window does not exist yet, create it. This is only called
|
||
when a window is already in use, or when output has been written during this
|
||
inflate call, but the end of the deflate stream has not been reached yet.
|
||
It is also called to create a window for dictionary data when a dictionary
|
||
is loaded.
|
||
|
||
Providing output buffers larger than 32K to inflate() should provide a speed
|
||
advantage, since only the last 32K of output is copied to the sliding window
|
||
upon return from inflate(), and since all distances after the first 32K of
|
||
output will fall in the output data, making match copies simpler and faster.
|
||
The advantage may be dependent on the size of the processor's data caches.
|
||
*/
|
||
function updatewindow(strm)
|
||
{
|
||
var state = strm.state;
|
||
var out = strm.output_data.length;
|
||
|
||
/* if it hasn't been done already, allocate space for the window */
|
||
if (state.window === null) {
|
||
state.window = '';
|
||
}
|
||
|
||
/* if window not in use yet, initialize */
|
||
if (state.wsize == 0) {
|
||
state.wsize = 1 << state.wbits;
|
||
}
|
||
|
||
// zlib.js: Sliding window
|
||
if (out >= state.wsize) {
|
||
state.window = strm.output_data.substring(out - state.wsize);
|
||
} else {
|
||
if(state.whave + out < state.wsize) {
|
||
state.window += strm.output_data;
|
||
} else {
|
||
state.window = state.window.substring(state.whave - (state.wsize - out)) + strm.output_data;
|
||
}
|
||
}
|
||
state.whave = state.window.length;
|
||
if(state.whave < state.wsize) {
|
||
state.wnext = state.whave;
|
||
} else {
|
||
state.wnext = 0;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
// #ifdef GUNZIP
|
||
function CRC2(strm, word)
|
||
{
|
||
var hbuf = [word & 0xff, (word >>> 8) & 0xff];
|
||
strm.state.check = strm.checksum_function(strm.state.check, hbuf, 0, 2);
|
||
}
|
||
|
||
function CRC4(strm, word)
|
||
{
|
||
var hbuf = [word & 0xff,
|
||
(word >>> 8) & 0xff,
|
||
(word >>> 16) & 0xff,
|
||
(word >>> 24) & 0xff];
|
||
strm.state.check = strm.checksum_function(strm.state.check, hbuf, 0, 4);
|
||
}
|
||
|
||
/* Load registers with state in inflate() for speed */
|
||
function LOAD(strm, s)
|
||
{
|
||
s.strm = strm; /* z_stream */
|
||
s.left = strm.avail_out; /* available output */
|
||
s.next = strm.next_in; /* next input */
|
||
s.have = strm.avail_in; /* available input */
|
||
s.hold = strm.state.hold; /* bit buffer */
|
||
s.bits = strm.state.bits; /* bits in bit buffer */
|
||
return s;
|
||
}
|
||
|
||
/* Restore state from registers in inflate() */
|
||
function RESTORE(s)
|
||
{
|
||
var strm = s.strm;
|
||
strm.next_in = s.next;
|
||
strm.avail_out = s.left;
|
||
strm.avail_in = s.have;
|
||
strm.state.hold = s.hold;
|
||
strm.state.bits = s.bits;
|
||
}
|
||
|
||
/* Clear the input bit accumulator */
|
||
function INITBITS(s)
|
||
{
|
||
s.hold = 0;
|
||
s.bits = 0;
|
||
}
|
||
|
||
/* Get a byte of input into the bit accumulator, or return from inflate()
|
||
if there is no input available. */
|
||
function PULLBYTE(s)
|
||
{
|
||
if (s.have == 0) return false;
|
||
s.have--;
|
||
s.hold += (s.strm.input_data.charCodeAt(s.next++) & 0xff) << s.bits;
|
||
s.bits += 8;
|
||
return true;
|
||
}
|
||
|
||
/* Assure that there are at least n bits in the bit accumulator. If there is
|
||
not enough available input to do that, then return from inflate(). */
|
||
function NEEDBITS(s, n)
|
||
{
|
||
// if(typeof n != 'number') throw 'ERROR';
|
||
while (s.bits < n) {
|
||
if(!PULLBYTE(s))
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/* Return the low n bits of the bit accumulator (n < 16) */
|
||
function BITS(s, n)
|
||
{
|
||
return s.hold & ((1 << n) - 1);
|
||
}
|
||
|
||
/* Remove n bits from the bit accumulator */
|
||
function DROPBITS(s, n)
|
||
{
|
||
// if(typeof n != 'number') throw 'ERROR';
|
||
s.hold >>>= n;
|
||
s.bits -= n;
|
||
}
|
||
|
||
/* Remove zero to seven bits as needed to go to a byte boundary */
|
||
function BYTEBITS(s)
|
||
{
|
||
s.hold >>>= s.bits & 7;
|
||
s.bits -= s.bits & 7;
|
||
}
|
||
|
||
/* Reverse the bytes in a 32-bit value */
|
||
function REVERSE(q)
|
||
{
|
||
return ((q >>> 24) & 0xff) +
|
||
((q >>> 8) & 0xff00) +
|
||
((q & 0xff00) << 8) +
|
||
((q & 0xff) << 24);
|
||
}
|
||
|
||
/*
|
||
inflate() uses a state machine to process as much input data and generate as
|
||
much output data as possible before returning. The state machine is
|
||
structured roughly as follows:
|
||
|
||
for (;;) switch (state) {
|
||
...
|
||
case STATEn:
|
||
if (not enough input data or output space to make progress)
|
||
return;
|
||
... make progress ...
|
||
state = STATEm;
|
||
break;
|
||
...
|
||
}
|
||
|
||
so when inflate() is called again, the same case is attempted again, and
|
||
if the appropriate resources are provided, the machine proceeds to the
|
||
next state. The NEEDBITS() macro is usually the way the state evaluates
|
||
whether it can proceed or should return. NEEDBITS() does the return if
|
||
the requested bits are not available. The typical use of the BITS macros
|
||
is:
|
||
|
||
NEEDBITS(n);
|
||
... do something with BITS(n) ...
|
||
DROPBITS(n);
|
||
|
||
where NEEDBITS(n) either returns from inflate() if there isn't enough
|
||
input left to load n bits into the accumulator, or it continues. BITS(n)
|
||
gives the low n bits in the accumulator. When done, DROPBITS(n) drops
|
||
the low n bits off the accumulator. INITBITS() clears the accumulator
|
||
and sets the number of available bits to zero. BYTEBITS() discards just
|
||
enough bits to put the accumulator on a byte boundary. After BYTEBITS()
|
||
and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
|
||
|
||
NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
|
||
if there is no input available. The decoding of variable length codes uses
|
||
PULLBYTE() directly in order to pull just enough bytes to decode the next
|
||
code, and no more.
|
||
|
||
Some states loop until they get enough input, making sure that enough
|
||
state information is maintained to continue the loop where it left off
|
||
if NEEDBITS() returns in the loop. For example, want, need, and keep
|
||
would all have to actually be part of the saved state in case NEEDBITS()
|
||
returns:
|
||
|
||
case STATEw:
|
||
while (want < need) {
|
||
NEEDBITS(n);
|
||
keep[want++] = BITS(n);
|
||
DROPBITS(n);
|
||
}
|
||
state = STATEx;
|
||
case STATEx:
|
||
|
||
As shown above, if the next state is also the next case, then the break
|
||
is omitted.
|
||
|
||
A state may also return if there is not enough output space available to
|
||
complete that state. Those states are copying stored data, writing a
|
||
literal byte, and copying a matching string.
|
||
|
||
When returning, a "goto inf_leave" is used to update the total counters,
|
||
update the check value, and determine whether any progress has been made
|
||
during that inflate() call in order to return the proper return code.
|
||
Progress is defined as a change in either strm->avail_in or strm->avail_out.
|
||
When there is a window, goto inf_leave will update the window with the last
|
||
output written. If a goto inf_leave occurs in the middle of decompression
|
||
and there is no window currently, goto inf_leave will create one and copy
|
||
output to the window for the next call of inflate().
|
||
|
||
In this implementation, the flush parameter of inflate() only affects the
|
||
return code (per zlib.h). inflate() always writes as much as possible to
|
||
strm->next_out, given the space available and the provided input--the effect
|
||
documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
|
||
the allocation of and copying into a sliding window until necessary, which
|
||
provides the effect documented in zlib.h for Z_FINISH when the entire input
|
||
stream available. So the only thing the flush parameter actually does is:
|
||
when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
|
||
will return Z_BUF_ERROR if it has not reached the end of the stream.
|
||
*/
|
||
|
||
/* permutation of code lengths */
|
||
var inflate_order = [
|
||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
||
ZLIB.inflate = function(strm, flush)
|
||
{
|
||
var state;
|
||
var s;
|
||
var _in, out; /* save starting available input and output */
|
||
var copy; /* number of stored or match bytes to copy */
|
||
var from_window_offset = -1; /* index of window[] */
|
||
var from_out_offset = -1; /* index of next_out[] */
|
||
var here; /* current decoding table entry */
|
||
var last; /* parent table entry */
|
||
var len; /* length to copy for repeats, bits to drop */
|
||
var ret; /* return code */
|
||
|
||
if (!strm || !strm.state ||
|
||
(!strm.input_data && strm.avail_in != 0))
|
||
return ZLIB.Z_STREAM_ERROR;
|
||
|
||
state = strm.state;
|
||
if (state.mode == TYPE) state.mode = TYPEDO; /* skip check */
|
||
|
||
// LOAD
|
||
s = {};
|
||
LOAD(strm, s);
|
||
|
||
_in = s.have;
|
||
out = s.left;
|
||
ret = ZLIB.Z_OK;
|
||
inf_leave: for (;;) {
|
||
switch (state.mode) {
|
||
case HEAD:
|
||
if (state.wrap == 0) {
|
||
state.mode = TYPEDO;
|
||
break;
|
||
}
|
||
if(!NEEDBITS(s, 16)) break inf_leave;
|
||
// #ifdef GUNZIP
|
||
if ((state.wrap & 2) && s.hold == 0x8b1f) { /* gzip header */
|
||
state.check = strm.checksum_function(0, null, 0, 0);
|
||
CRC2(strm, s.hold);
|
||
INITBITS(s);
|
||
state.mode = FLAGS;
|
||
break;
|
||
}
|
||
state.flags = 0; /* expect zlib header */
|
||
if (state.head !== null)
|
||
state.head.done = -1;
|
||
if (!(state.wrap & 1) || /* check if zlib header allowed */
|
||
//#else
|
||
// if (
|
||
//#endif
|
||
((BITS(s, 8) << 8) + (s.hold >>> 8)) % 31) {
|
||
strm.msg = 'incorrect header check';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
if (BITS(s, 4) != ZLIB.Z_DEFLATED) {
|
||
strm.msg = 'unknown compression method';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
|
||
DROPBITS(s, 4);
|
||
len = BITS(s, 4) + 8;
|
||
if (state.wbits == 0)
|
||
state.wbits = len;
|
||
else if (len > state.wbits) {
|
||
strm.msg = 'invalid window size';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
state.dmax = 1 << len;
|
||
// Tracev((stderr, "inflate: zlib header ok\n"));
|
||
strm.adler = state.check = strm.checksum_function(0, null, 0, 0);
|
||
state.mode = s.hold & 0x200 ? DICTID : TYPE;
|
||
INITBITS(s);
|
||
break;
|
||
// #ifdef GUNZIP
|
||
case FLAGS:
|
||
if(!NEEDBITS(s, 16)) break inf_leave;
|
||
state.flags = s.hold;
|
||
if ((state.flags & 0xff) != ZLIB.Z_DEFLATED) {
|
||
strm.msg = "unknown compression method";
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
if (state.flags & 0xe000) {
|
||
strm.msg = "unknown header flags set";
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
if (state.head !== null)
|
||
state.head.text = (s.hold >>> 8) & 1;
|
||
if (state.flags & 0x0200) {
|
||
CRC2(strm, s.hold);
|
||
}
|
||
INITBITS(s);
|
||
state.mode = TIME;
|
||
case TIME:
|
||
if(!NEEDBITS(s, 32)) break inf_leave;
|
||
if (state.head !== null)
|
||
state.head.time = s.hold;
|
||
if (state.flags & 0x0200) {
|
||
CRC4(strm, s.hold);
|
||
}
|
||
INITBITS(s);
|
||
state.mode = OS;
|
||
case OS:
|
||
if(!NEEDBITS(s, 16)) break inf_leave;
|
||
if (state.head !== null) {
|
||
state.head.xflags = s.hold & 0xff;
|
||
state.head.os = s.hold >>> 8;
|
||
}
|
||
if (state.flags & 0x0200) {
|
||
CRC2(strm, s.hold);
|
||
}
|
||
INITBITS(s);
|
||
state.mode = EXLEN;
|
||
case EXLEN:
|
||
if (state.flags & 0x0400) {
|
||
if(!NEEDBITS(s, 16)) break inf_leave;
|
||
state.length = s.hold;
|
||
if (state.head !== null) {
|
||
state.head.extra_len = s.hold;
|
||
}
|
||
if (state.flags & 0x0200) {
|
||
CRC2(strm, s.hold);
|
||
}
|
||
INITBITS(s);
|
||
state.head.extra = "";
|
||
}
|
||
else if (state.head !== null) {
|
||
state.head.extra = null;
|
||
}
|
||
state.mode = EXTRA;
|
||
case EXTRA:
|
||
if (state.flags & 0x0400) {
|
||
copy = state.length;
|
||
if (copy > s.have) copy = s.have;
|
||
if (copy) {
|
||
if (state.head !== null &&
|
||
state.head.extra !== null) {
|
||
len = state.head.extra_len - state.length;
|
||
/*
|
||
zmemcpy(state->head->extra + len, next,
|
||
len + copy > state->head->extra_max ?
|
||
state->head->extra_max - len : copy);
|
||
*/
|
||
state.head.extra += strm.input_data.substring(
|
||
s.next, s.next + (len + copy > state.head.extra_max ?
|
||
state.head.extra_max - len : copy));
|
||
|
||
}
|
||
if (state.flags & 0x0200)
|
||
state.check = strm.checksum_function(state.check, strm.input_data, s.next, copy);
|
||
s.have -= copy;
|
||
s.next += copy;
|
||
state.length -= copy;
|
||
}
|
||
if (state.length) break inf_leave;
|
||
}
|
||
state.length = 0;
|
||
state.mode = NAME;
|
||
case NAME:
|
||
if (state.flags & 0x0800) {
|
||
if (s.have == 0) break inf_leave;
|
||
if (state.head !== null && state.head.name === null) {
|
||
state.head.name = "";
|
||
}
|
||
copy = 0;
|
||
// TODO end = strm.input_data.indexOf("\0", s.next);
|
||
// TODO state.length => state.head.name.length
|
||
do {
|
||
len = strm.input_data.charAt(s.next + copy); copy++;
|
||
if(len === "\0")
|
||
break;
|
||
if (state.head !== null &&
|
||
state.length < state.head.name_max) {
|
||
state.head.name += len;
|
||
state.length++;
|
||
}
|
||
} while (copy < s.have);
|
||
if (state.flags & 0x0200) {
|
||
state.check = strm.checksum_function(state.check, strm.input_data, s.next, copy);
|
||
}
|
||
s.have -= copy;
|
||
s.next += copy;
|
||
if (len !== "\0") break inf_leave;
|
||
}
|
||
else if (state.head !== null)
|
||
state.head.name = null;
|
||
state.length = 0;
|
||
state.mode = COMMENT;
|
||
case COMMENT:
|
||
if (state.flags & 0x1000) {
|
||
if (s.have == 0) break inf_leave;
|
||
copy = 0;
|
||
if (state.head !== null && state.head.comment === null) {
|
||
state.head.comment = "";
|
||
}
|
||
// TODO end = strm.input_data.indexOf("\0", s.next);
|
||
// TODO state.length => state.head.comment.length
|
||
do {
|
||
len = strm.input_data.charAt(s.next + copy); copy++;
|
||
if(len === "\0")
|
||
break;
|
||
if (state.head !== null &&
|
||
state.length < state.head.comm_max) {
|
||
state.head.comment += len;
|
||
state.length++;
|
||
}
|
||
} while (copy < s.have);
|
||
if (state.flags & 0x0200)
|
||
state.check = strm.checksum_function(state.check, strm.input_data, s.next, copy);
|
||
s.have -= copy;
|
||
s.next += copy;
|
||
if (len !== "\0") break inf_leave;
|
||
}
|
||
else if (state.head !== null)
|
||
state.head.comment = null;
|
||
state.mode = HCRC;
|
||
case HCRC:
|
||
if (state.flags & 0x0200) {
|
||
if(!NEEDBITS(s, 16)) break inf_leave;
|
||
if (s.hold != (state.check & 0xffff)) {
|
||
strm.msg = "header crc mismatch";
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
INITBITS(s);
|
||
}
|
||
if (state.head !== null) {
|
||
state.head.hcrc = (state.flags >>> 9) & 1;
|
||
state.head.done = 1;
|
||
}
|
||
strm.adler = state.check = strm.checksum_function(0, null, 0, 0);
|
||
state.mode = TYPE;
|
||
break;
|
||
//#endif
|
||
case DICTID:
|
||
if(!NEEDBITS(s, 32)) break inf_leave;
|
||
strm.adler = state.check = REVERSE(s.hold);
|
||
INITBITS(s);
|
||
state.mode = DICT;
|
||
case DICT:
|
||
if (state.havedict == 0) {
|
||
RESTORE(s);
|
||
return ZLIB.Z_NEED_DICT;
|
||
}
|
||
strm.adler = state.check = strm.checksum_function(0, null, 0, 0);
|
||
state.mode = TYPE;
|
||
case TYPE:
|
||
if (flush == ZLIB.Z_BLOCK || flush == ZLIB.Z_TREES) break inf_leave;
|
||
case TYPEDO:
|
||
if (state.last) {
|
||
BYTEBITS(s);
|
||
state.mode = CHECK;
|
||
break;
|
||
}
|
||
if(!NEEDBITS(s, 3)) break inf_leave;
|
||
state.last = BITS(s, 1);
|
||
DROPBITS(s, 1);
|
||
switch (BITS(s, 2)) {
|
||
case 0: /* stored block */
|
||
// Tracev((stderr, "inflate: stored block%s\n",
|
||
// state->last ? " (last)" : ""));
|
||
state.mode = STORED;
|
||
break;
|
||
case 1: /* fixed block */
|
||
fixedtables(state);
|
||
// Tracev((stderr, "inflate: fixed codes block%s\n",
|
||
// state->last ? " (last)" : ""));
|
||
state.mode = LEN_; /* decode codes */
|
||
if (flush == ZLIB.Z_TREES) {
|
||
DROPBITS(s, 2);
|
||
break inf_leave;
|
||
}
|
||
break;
|
||
case 2: /* dynamic block */
|
||
// Tracev((stderr, "inflate: dynamic codes block%s\n",
|
||
// state->last ? " (last)" : ""));
|
||
state.mode = TABLE;
|
||
break;
|
||
case 3:
|
||
strm.msg = 'invalid block type';
|
||
state.mode = BAD;
|
||
}
|
||
DROPBITS(s, 2);
|
||
break;
|
||
case STORED:
|
||
BYTEBITS(s); /* go to byte boundary */
|
||
if(!NEEDBITS(s, 32)) break inf_leave;
|
||
if ((s.hold & 0xffff) != (((s.hold >>> 16) & 0xffff) ^ 0xffff)) {
|
||
strm.msg = 'invalid stored block lengths';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
state.length = s.hold & 0xffff;
|
||
// Tracev((stderr, "inflate: stored length %u\n",
|
||
// state->length));
|
||
INITBITS(s);
|
||
state.mode = COPY_;
|
||
if (flush == ZLIB.Z_TREES) break inf_leave;
|
||
case COPY_:
|
||
state.mode = COPY;
|
||
case COPY:
|
||
copy = state.length;
|
||
if (copy) {
|
||
if (copy > s.have) copy = s.have;
|
||
if (copy > s.left) copy = s.left;
|
||
if (copy == 0) break inf_leave;
|
||
strm.output_data += strm.input_data.substring(s.next, s.next + copy);
|
||
strm.next_out += copy;
|
||
s.have -= copy;
|
||
s.next += copy;
|
||
s.left -= copy;
|
||
state.length -= copy;
|
||
break;
|
||
}
|
||
// Tracev((stderr, "inflate: stored end\n"));
|
||
state.mode = TYPE;
|
||
break;
|
||
case TABLE:
|
||
if(!NEEDBITS(s, 14)) break inf_leave;
|
||
state.nlen = BITS(s, 5) + 257;
|
||
DROPBITS(s, 5);
|
||
state.ndist = BITS(s, 5) + 1;
|
||
DROPBITS(s, 5);
|
||
state.ncode = BITS(s, 4) + 4;
|
||
DROPBITS(s, 4);
|
||
//#ifndef PKZIP_BUG_WORKAROUND
|
||
if (state.nlen > 286 || state.ndist > 30) {
|
||
strm.msg = 'too many length or distance symbols';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
//#endif
|
||
// Tracev((stderr, "inflate: table sizes ok\n"));
|
||
state.have = 0;
|
||
state.mode = LENLENS;
|
||
case LENLENS:
|
||
while (state.have < state.ncode) {
|
||
if(!NEEDBITS(s, 3)) break inf_leave;
|
||
var tmp = BITS(s, 3);
|
||
state.lens[inflate_order[state.have++]] = tmp;
|
||
DROPBITS(s, 3);
|
||
}
|
||
while (state.have < 19)
|
||
state.lens[inflate_order[state.have++]] = 0;
|
||
state.next = 0;
|
||
state.lencode = 0;
|
||
state.lenbits = 7;
|
||
|
||
// ret = inflate_table(CODES, state->lens, 19, &(state->next),
|
||
// &(state->lenbits), state->work);
|
||
ret = inflate_table(state, CODES);
|
||
|
||
if (ret) {
|
||
strm.msg = 'invalid code lengths set';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
// Tracev((stderr, "inflate: code lengths ok\n"));
|
||
state.have = 0;
|
||
state.mode = CODELENS;
|
||
case CODELENS:
|
||
while (state.have < state.nlen + state.ndist) {
|
||
for (;;) {
|
||
here = state.codes[state.lencode + BITS(s, state.lenbits)];
|
||
if (here.bits <= s.bits) break;
|
||
if(!PULLBYTE(s)) break inf_leave;
|
||
}
|
||
if (here.val < 16) {
|
||
DROPBITS(s, here.bits);
|
||
state.lens[state.have++] = here.val;
|
||
}
|
||
else {
|
||
if (here.val == 16) {
|
||
if(!NEEDBITS(s, here.bits + 2)) break inf_leave;
|
||
DROPBITS(s, here.bits);
|
||
if (state.have == 0) {
|
||
strm.msg = 'invalid bit length repeat';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
len = state.lens[state.have - 1];
|
||
copy = 3 + BITS(s, 2);
|
||
DROPBITS(s, 2);
|
||
}
|
||
else if (here.val == 17) {
|
||
if(!NEEDBITS(s, here.bits + 3)) break inf_leave;
|
||
DROPBITS(s, here.bits);
|
||
len = 0;
|
||
copy = 3 + BITS(s, 3);
|
||
DROPBITS(s, 3);
|
||
}
|
||
else {
|
||
if(!NEEDBITS(s, here.bits + 7)) break inf_leave;
|
||
DROPBITS(s, here.bits);
|
||
len = 0;
|
||
copy = 11 + BITS(s, 7);
|
||
DROPBITS(s, 7);
|
||
}
|
||
if (state.have + copy > state.nlen + state.ndist) {
|
||
strm.msg = 'invalid bit length repeat';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
while (copy--)
|
||
state.lens[state.have++] = len;
|
||
}
|
||
}
|
||
|
||
/* handle error breaks in while */
|
||
if (state.mode == BAD) break;
|
||
|
||
/* check for end-of-block code (better have one) */
|
||
if (state.lens[256] == 0) {
|
||
strm.msg = 'invalid code -- missing end-of-block';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
|
||
/* build code tables -- note: do not change the lenbits or distbits
|
||
values here (9 and 6) without reading the comments in inftrees.h
|
||
concerning the ENOUGH constants, which depend on those values */
|
||
state.next = 0;
|
||
state.lencode = state.next;
|
||
state.lenbits = 9;
|
||
// ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||
// &(state->lenbits), state->work);
|
||
ret = inflate_table(state, LENS);
|
||
if (ret) {
|
||
strm.msg = 'invalid literal/lengths set';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
state.distcode = state.next;
|
||
state.distbits = 6;
|
||
// ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next),
|
||
// &(state->distbits), state->work);
|
||
ret = inflate_table(state, DISTS);
|
||
if (ret) {
|
||
strm.msg = 'invalid distances set';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
// Tracev((stderr, "inflate: codes ok\n"));
|
||
state.mode = LEN_;
|
||
if (flush == ZLIB.Z_TREES) break inf_leave;
|
||
case LEN_:
|
||
state.mode = LEN;
|
||
case LEN:
|
||
if (s.have >= 6 && s.left >= 258) {
|
||
RESTORE(s);
|
||
inflate_fast(strm, out);
|
||
LOAD(strm, s);
|
||
if (state.mode == TYPE)
|
||
state.back = -1;
|
||
break;
|
||
}
|
||
state.back = 0;
|
||
for (;;) {
|
||
here = state.codes[state.lencode + BITS(s, state.lenbits)];
|
||
if (here.bits <= s.bits) break;
|
||
if(!PULLBYTE(s)) break inf_leave;
|
||
}
|
||
if (here.op && (here.op & 0xf0) == 0) {
|
||
last = here;
|
||
for (;;) {
|
||
here = state.codes[state.lencode + last.val +
|
||
(BITS(s, last.bits + last.op) >>> last.bits)];
|
||
if (last.bits + here.bits <= s.bits) break;
|
||
if(!PULLBYTE(s)) break inf_leave;
|
||
}
|
||
DROPBITS(s, last.bits);
|
||
state.back += last.bits;
|
||
}
|
||
DROPBITS(s, here.bits);
|
||
state.back += here.bits;
|
||
state.length = here.val;
|
||
if (here.op == 0) {
|
||
// Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||
// "inflate: literal '%c'\n" :
|
||
// "inflate: literal 0x%02x\n", here.val));
|
||
state.mode = LIT;
|
||
break;
|
||
}
|
||
if (here.op & 32) {
|
||
// Tracevv((stderr, "inflate: end of block\n"));
|
||
state.back = -1;
|
||
state.mode = TYPE;
|
||
break;
|
||
}
|
||
if (here.op & 64) {
|
||
strm.msg = 'invalid literal/length code';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
state.extra = here.op & 15;
|
||
state.mode = LENEXT;
|
||
case LENEXT:
|
||
if (state.extra) {
|
||
if(!NEEDBITS(s, state.extra)) break inf_leave;
|
||
state.length += BITS(s, state.extra);
|
||
DROPBITS(s, state.extra);
|
||
state.back += state.extra;
|
||
}
|
||
//Tracevv((stderr, "inflate: length %u\n", state->length));
|
||
state.was = state.length;
|
||
state.mode = DIST;
|
||
case DIST:
|
||
for (;;) {
|
||
here = state.codes[state.distcode + BITS(s, state.distbits)];
|
||
if (here.bits <= s.bits) break;
|
||
if(!PULLBYTE(s)) break inf_leave;
|
||
}
|
||
if ((here.op & 0xf0) == 0) {
|
||
last = here;
|
||
for (;;) {
|
||
here = state.codes[state.distcode + last.val +
|
||
(BITS(s, last.bits + last.op) >>> last.bits)];
|
||
if ((last.bits + here.bits) <= s.bits) break;
|
||
if(!PULLBYTE(s)) break inf_leave;
|
||
}
|
||
DROPBITS(s, last.bits);
|
||
state.back += last.bits;
|
||
}
|
||
DROPBITS(s, here.bits);
|
||
state.back += here.bits;
|
||
if (here.op & 64) {
|
||
strm.msg = 'invalid distance code';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
state.offset = here.val;
|
||
state.extra = here.op & 15;
|
||
state.mode = DISTEXT;
|
||
case DISTEXT:
|
||
if (state.extra) {
|
||
if(!NEEDBITS(s, state.extra)) break inf_leave;
|
||
state.offset += BITS(s, state.extra);
|
||
DROPBITS(s, state.extra);
|
||
state.back += state.extra;
|
||
}
|
||
//NOSPRT #ifdef INFLATE_STRICT
|
||
// if (state->offset > state->dmax) {
|
||
// strm->msg = (char *)"invalid distance too far back";
|
||
// state->mode = BAD;
|
||
// break;
|
||
// }
|
||
//#endif
|
||
// Tracevv((stderr, "inflate: distance %u\n", state->offset));
|
||
state.mode = MATCH;
|
||
case MATCH:
|
||
if (s.left == 0) break inf_leave;
|
||
copy = out - s.left;
|
||
if (state.offset > copy) { /* copy from window */
|
||
copy = state.offset - copy;
|
||
if (copy > state.whave) {
|
||
if (state.sane) {
|
||
strm.msg = 'invalid distance too far back';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
//NOSPRT #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||
// Trace((stderr, "inflate.c too far\n"));
|
||
// copy -= state->whave;
|
||
// if (copy > state->length) copy = state->length;
|
||
// if (copy > left) copy = left;
|
||
// left -= copy;
|
||
// state->length -= copy;
|
||
// do {
|
||
// *put++ = 0;
|
||
// } while (--copy);
|
||
// if (state->length == 0) state->mode = LEN;
|
||
// break;
|
||
//#endif
|
||
}
|
||
if (copy > state.wnext) {
|
||
copy -= state.wnext;
|
||
// from = state->window + (state->wsize - copy);
|
||
from_window_offset = state.wsize - copy;
|
||
from_out_offset = -1;
|
||
}
|
||
else {
|
||
// from = state->window + (state->wnext - copy);
|
||
from_window_offset = state.wnext - copy;
|
||
from_out_offset = -1;
|
||
}
|
||
if (copy > state.length) copy = state.length;
|
||
}
|
||
else { /* copy from output */
|
||
// from = put - state->offset;
|
||
from_window_offset = -1;
|
||
from_out_offset = strm.next_out - state.offset;
|
||
copy = state.length;
|
||
}
|
||
if (copy > s.left) copy = s.left;
|
||
s.left -= copy;
|
||
state.length -= copy;
|
||
if( from_window_offset >= 0 ) {
|
||
strm.output_data += state.window.substring(from_window_offset, from_window_offset + copy);
|
||
strm.next_out += copy;
|
||
copy = 0;
|
||
} else {
|
||
strm.next_out += copy;
|
||
do {
|
||
strm.output_data += strm.output_data.charAt(from_out_offset++);
|
||
} while (--copy);
|
||
}
|
||
if (state.length == 0) state.mode = LEN;
|
||
break;
|
||
case LIT:
|
||
if (s.left == 0) break inf_leave;
|
||
|
||
strm.output_data += String.fromCharCode(state.length);
|
||
strm.next_out++;
|
||
//*put++ = (unsigned char)(state->length);
|
||
|
||
s.left--;
|
||
state.mode = LEN;
|
||
break;
|
||
case CHECK:
|
||
if (state.wrap) {
|
||
if(!NEEDBITS(s, 32)) break inf_leave;
|
||
out -= s.left;
|
||
strm.total_out += out;
|
||
state.total += out;
|
||
if (out)
|
||
strm.adler = state.check =
|
||
strm.checksum_function(state.check, strm.output_data, strm.output_data.length - out, out);
|
||
out = s.left;
|
||
if ((
|
||
// #ifdef GUNZIP
|
||
state.flags ? s.hold :
|
||
//#endif
|
||
REVERSE(s.hold)) != state.check) {
|
||
strm.msg = "incorrect data check";
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
INITBITS(s);
|
||
//debug("## inflate: check matches trailer\n");
|
||
// Tracev((stderr, "inflate: check matches trailer\n"));
|
||
}
|
||
//#ifdef GUNZIP
|
||
state.mode = LENGTH;
|
||
case LENGTH:
|
||
if (state.wrap && state.flags) {
|
||
if(!NEEDBITS(s, 32)) break inf_leave;
|
||
if (s.hold != (state.total & 0xffffffff)) {
|
||
strm.msg = 'incorrect length check';
|
||
state.mode = BAD;
|
||
break;
|
||
}
|
||
INITBITS(s);
|
||
//Tracev((stderr, "inflate: length matches trailer\n"));
|
||
}
|
||
//#endif
|
||
state.mode = DONE;
|
||
case DONE:
|
||
ret = ZLIB.Z_STREAM_END;
|
||
break inf_leave;
|
||
case BAD:
|
||
ret = ZLIB.Z_DATA_ERROR;
|
||
break inf_leave;
|
||
case MEM:
|
||
return ZLIB.Z_MEM_ERROR;
|
||
case SYNC:
|
||
default:
|
||
return ZLIB.Z_STREAM_ERROR;
|
||
} }
|
||
|
||
/*
|
||
Return from inflate(), updating the total counts and the check value.
|
||
If there was no progress during the inflate() call, return a buffer
|
||
error. Call updatewindow() to create and/or update the window state.
|
||
Note: a memory error from inflate() is non-recoverable.
|
||
*/
|
||
inf_leave:
|
||
RESTORE(s);
|
||
if (state.wsize || (out != strm.avail_out && state.mode < BAD &&
|
||
(state.mode < CHECK || flush != ZLIB.Z_FINISH)))
|
||
if (updatewindow(strm)) {
|
||
state.mode = MEM;
|
||
return ZLIB.Z_MEM_ERROR;
|
||
}
|
||
_in -= strm.avail_in;
|
||
out -= strm.avail_out;
|
||
strm.total_in += _in;
|
||
strm.total_out += out;
|
||
state.total += out;
|
||
if (state.wrap && out)
|
||
strm.adler = state.check = strm.checksum_function(state.check, strm.output_data, 0, strm.output_data.length);
|
||
strm.data_type = state.bits + (state.last ? 64 : 0) +
|
||
(state.mode == TYPE ? 128 : 0) +
|
||
(state.mode == LEN_ || state.mode == COPY_ ? 256 : 0);
|
||
if (((_in == 0 && out == 0) || flush == ZLIB.Z_FINISH) && ret == ZLIB.Z_OK)
|
||
ret = ZLIB.Z_BUF_ERROR;
|
||
return ret;
|
||
};
|
||
|
||
ZLIB.inflateEnd = function(strm)
|
||
{
|
||
var state;
|
||
if (!strm || !strm.state )
|
||
return ZLIB.Z_STREAM_ERROR;
|
||
state = strm.state;
|
||
state.window = null;
|
||
strm.state = null;
|
||
// Tracev((stderr, "inflate: end\n"));
|
||
return ZLIB.Z_OK;
|
||
};
|
||
|
||
ZLIB.z_stream.prototype.inflate = function(input_string, opts)
|
||
{
|
||
var flush;
|
||
var avail_out;
|
||
var DEFAULT_BUFFER_SIZE = 16384;
|
||
|
||
this.input_data = input_string;
|
||
this.next_in = getarg(opts, 'next_in', 0);
|
||
this.avail_in = getarg(opts, 'avail_in', input_string.length - this.next_in);
|
||
|
||
flush = getarg(opts, 'flush', ZLIB.Z_SYNC_FLUSH);
|
||
avail_out = getarg(opts, 'avail_out', -1);
|
||
|
||
var result = '';
|
||
do {
|
||
this.avail_out = (avail_out >= 0 ? avail_out : DEFAULT_BUFFER_SIZE);
|
||
this.output_data = '';
|
||
this.next_out = 0;
|
||
this.error = ZLIB.inflate(this, flush);
|
||
if(avail_out >= 0) {
|
||
return this.output_data;
|
||
}
|
||
result += this.output_data;
|
||
if(this.avail_out > 0) {
|
||
break;
|
||
}
|
||
} while(this.error == ZLIB.Z_OK);
|
||
|
||
return result;
|
||
};
|
||
|
||
ZLIB.z_stream.prototype.inflateReset = function(windowBits)
|
||
{
|
||
return ZLIB.inflateReset(this, windowBits);
|
||
};
|
||
|
||
}());
|
||
/* zlib-adler32.js -- JavaScript implementation for the zlib adler32.
|
||
Version: 0.2.0
|
||
LastModified: Apr 12 2012
|
||
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
|
||
|
||
API documentation
|
||
==============================================================================
|
||
Usage: adler = ZLIB.adler32(adler, buf, offset, len);
|
||
|
||
Update a running Adler-32 checksum with the bytes buf[offset..offset+len-1] and
|
||
return the updated checksum. If buf is null, this function returns the
|
||
required initial value for the checksum.
|
||
|
||
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
|
||
much faster.
|
||
|
||
Usage example:
|
||
|
||
var adler = ZLIB.adler32(0, null, 0, 0);
|
||
|
||
while (read_buffer(buffer, length) != EOF) {
|
||
adler = ZLIB.adler32(adler, buffer, 0, length);
|
||
}
|
||
if (adler != original_adler) error();
|
||
|
||
==============================================================================
|
||
Usage: adler = ZLIB.adler32_combine(adler1, adler2, len2);
|
||
|
||
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
|
||
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
|
||
each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
|
||
seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
|
||
that the z_off_t type (like off_t) is a signed integer. If len2 is
|
||
negative, the result has no meaning or utility.
|
||
*/
|
||
|
||
if( typeof ZLIB === 'undefined' ) {
|
||
alert('ZLIB is not defined. SRC zlib.js before zlib-adler32.js')
|
||
}
|
||
|
||
(function() {
|
||
|
||
/* adler32.c -- compute the Adler-32 checksum of a data stream
|
||
* Copyright (C) 1995-2011 Mark Adler
|
||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||
*/
|
||
|
||
var BASE = 65521; /* largest prime smaller than 65536 */
|
||
var NMAX = 5552;
|
||
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||
|
||
/* ========================================================================= */
|
||
function adler32_string(adler, buf, offset, len)
|
||
{
|
||
var sum2;
|
||
var n;
|
||
|
||
/* split Adler-32 into component sums */
|
||
sum2 = (adler >>> 16) & 0xffff;
|
||
adler &= 0xffff;
|
||
|
||
/* in case user likes doing a byte at a time, keep it fast */
|
||
if (len == 1) {
|
||
adler += buf.charCodeAt(offset) & 0xff;
|
||
if (adler >= BASE)
|
||
adler -= BASE;
|
||
sum2 += adler;
|
||
if (sum2 >= BASE)
|
||
sum2 -= BASE;
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* initial Adler-32 value (deferred check for len == 1 speed) */
|
||
if (buf === null)
|
||
return 1;
|
||
|
||
/* in case short lengths are provided, keep it somewhat fast */
|
||
if (len < 16) {
|
||
while (len--) {
|
||
adler += buf.charCodeAt(offset++) & 0xff;
|
||
sum2 += adler;
|
||
}
|
||
if (adler >= BASE)
|
||
adler -= BASE;
|
||
sum2 %= BASE; /* only added so many BASE's */
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* do length NMAX blocks -- requires just one modulo operation */
|
||
while (len >= NMAX) {
|
||
len -= NMAX;
|
||
n = NMAX >> 4; /* NMAX is divisible by 16 */
|
||
do {
|
||
/* 16 sums unrolled */
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
} while (--n);
|
||
adler %= BASE;
|
||
sum2 %= BASE;
|
||
}
|
||
|
||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||
if (len) { /* avoid modulos if none remaining */
|
||
while (len >= 16) {
|
||
len -= 16;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
}
|
||
while (len--) {
|
||
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
|
||
}
|
||
adler %= BASE;
|
||
sum2 %= BASE;
|
||
}
|
||
|
||
/* return recombined sums */
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
function adler32_array(adler, buf, offset, len)
|
||
{
|
||
var sum2;
|
||
var n;
|
||
|
||
/* split Adler-32 into component sums */
|
||
sum2 = (adler >>> 16) & 0xffff;
|
||
adler &= 0xffff;
|
||
|
||
/* in case user likes doing a byte at a time, keep it fast */
|
||
if (len == 1) {
|
||
adler += buf[offset];
|
||
if (adler >= BASE)
|
||
adler -= BASE;
|
||
sum2 += adler;
|
||
if (sum2 >= BASE)
|
||
sum2 -= BASE;
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* initial Adler-32 value (deferred check for len == 1 speed) */
|
||
if (buf === null)
|
||
return 1;
|
||
|
||
/* in case short lengths are provided, keep it somewhat fast */
|
||
if (len < 16) {
|
||
while (len--) {
|
||
adler += buf[offset++];
|
||
sum2 += adler;
|
||
}
|
||
if (adler >= BASE)
|
||
adler -= BASE;
|
||
sum2 %= BASE; /* only added so many BASE's */
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* do length NMAX blocks -- requires just one modulo operation */
|
||
while (len >= NMAX) {
|
||
len -= NMAX;
|
||
n = NMAX >> 4; /* NMAX is divisible by 16 */
|
||
do {
|
||
/* 16 sums unrolled */
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
} while (--n);
|
||
adler %= BASE;
|
||
sum2 %= BASE;
|
||
}
|
||
|
||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||
if (len) { /* avoid modulos if none remaining */
|
||
while (len >= 16) {
|
||
len -= 16;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
adler += buf[offset++]; sum2 += adler;
|
||
}
|
||
while (len--) {
|
||
adler += buf[offset++]; sum2 += adler;
|
||
}
|
||
adler %= BASE;
|
||
sum2 %= BASE;
|
||
}
|
||
|
||
/* return recombined sums */
|
||
return adler | (sum2 << 16);
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
ZLIB.adler32 = function(adler, buf, offset, len)
|
||
{
|
||
if(typeof buf === 'string') {
|
||
return adler32_string(adler, buf, offset, len);
|
||
} else {
|
||
return adler32_array(adler, buf, offset, len);
|
||
}
|
||
};
|
||
|
||
ZLIB.adler32_combine = function(adler1, adler2, len2)
|
||
{
|
||
var sum1;
|
||
var sum2;
|
||
var rem;
|
||
|
||
/* for negative len, return invalid adler32 as a clue for debugging */
|
||
if (len2 < 0)
|
||
return 0xffffffff;
|
||
|
||
/* the derivation of this formula is left as an exercise for the reader */
|
||
len2 %= BASE; /* assumes len2 >= 0 */
|
||
rem = len2;
|
||
sum1 = adler1 & 0xffff;
|
||
sum2 = rem * sum1;
|
||
sum2 %= BASE;
|
||
sum1 += (adler2 & 0xffff) + BASE - 1;
|
||
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
|
||
if (sum1 >= BASE) sum1 -= BASE;
|
||
if (sum1 >= BASE) sum1 -= BASE;
|
||
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
|
||
if (sum2 >= BASE) sum2 -= BASE;
|
||
return sum1 | (sum2 << 16);
|
||
}
|
||
|
||
}());
|
||
/* zlib-adler32.js -- JavaScript implementation for the zlib crc32.
|
||
Version: 0.2.0
|
||
LastModified: Apr 12 2012
|
||
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
|
||
|
||
API documentation
|
||
==============================================================================
|
||
Usage: crc = ZLIB.crc32(crc, buf, offset, len);
|
||
|
||
Update a running CRC-32 with the bytes buf[offset..offset+len-1] and return the
|
||
updated CRC-32. If buf is null, this function returns the required
|
||
initial value for the for the crc. Pre- and post-conditioning (one's
|
||
complement) is performed within this function so it shouldn't be done by the
|
||
application.
|
||
|
||
Usage example:
|
||
|
||
var crc = ZLIB.crc32(0, null, 0, 0);
|
||
|
||
while (read_buffer(buffer, length) != EOF) {
|
||
crc = ZLIB.crc32(crc, buffer, 0, length);
|
||
}
|
||
if (crc != original_crc) error();
|
||
|
||
==============================================================================
|
||
Usage: crc = crc32_combine(crc1, crc2, len2);
|
||
|
||
Combine two CRC-32 check values into one. For two sequences of bytes,
|
||
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
|
||
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
|
||
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
|
||
len2.
|
||
*/
|
||
|
||
if( typeof ZLIB === 'undefined' ) {
|
||
alert('ZLIB is not defined. SRC zlib.js before zlib-crc32.js')
|
||
}
|
||
|
||
(function() {
|
||
|
||
/* crc32.c -- compute the CRC-32 of a data stream
|
||
* Copyright (C) 1995-2006, 2010, 2011 Mark Adler
|
||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||
*
|
||
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
|
||
* CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
|
||
* tables for updating the shift register in one step with three exclusive-ors
|
||
* instead of four steps with four exclusive-ors. This results in about a
|
||
* factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
|
||
*/
|
||
|
||
var crc_table = [
|
||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
|
||
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
|
||
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
|
||
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
|
||
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
|
||
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
|
||
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
|
||
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
|
||
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
|
||
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
|
||
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
|
||
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
|
||
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
|
||
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
|
||
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
|
||
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
|
||
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
|
||
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
|
||
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
|
||
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
|
||
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
|
||
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
|
||
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
|
||
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
|
||
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
|
||
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
|
||
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
|
||
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
|
||
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
|
||
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
|
||
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
|
||
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
|
||
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
|
||
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
|
||
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
|
||
0x2d02ef8d ];
|
||
|
||
/* ========================================================================= */
|
||
function crc32_string(crc, buf, offset, len)
|
||
{
|
||
if (buf == null) return 0;
|
||
|
||
crc = crc ^ 0xffffffff;
|
||
while (len >= 8) {
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
len -= 8;
|
||
}
|
||
if (len) do {
|
||
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
|
||
} while (--len);
|
||
return crc ^ 0xffffffff;
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
function crc32_array(crc, buf, offset, len)
|
||
{
|
||
if (buf == null) return 0;
|
||
|
||
crc = crc ^ 0xffffffff;
|
||
while (len >= 8) {
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
len -= 8;
|
||
}
|
||
if (len) do {
|
||
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
|
||
} while (--len);
|
||
return crc ^ 0xffffffff;
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
ZLIB.crc32 = function(crc, buf, offset, len)
|
||
{
|
||
if(typeof buf === 'string') {
|
||
return crc32_string(crc, buf, offset, len);
|
||
} else {
|
||
return crc32_array(crc, buf, offset, len);
|
||
}
|
||
};
|
||
|
||
/* ========================================================================= */
|
||
var GF2_DIM = 32; /* dimension of GF(2) vectors (length of CRC) */
|
||
|
||
/* ========================================================================= */
|
||
function gf2_matrix_times(mat, vec)
|
||
{
|
||
var sum;
|
||
var mat_i = 0;
|
||
|
||
sum = 0;
|
||
while (vec) {
|
||
if (vec & 1)
|
||
sum ^= mat[mat_i];
|
||
vec >>= 1;
|
||
mat_i++;
|
||
}
|
||
return sum;
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
function gf2_matrix_square(square, mat)
|
||
{
|
||
var n;
|
||
|
||
for (n = 0; n < GF2_DIM; n++)
|
||
square[n] = gf2_matrix_times(mat, mat[n]);
|
||
}
|
||
|
||
/* ========================================================================= */
|
||
ZLIB.crc32_combine = function(crc1, crc2, len2)
|
||
{
|
||
var n;
|
||
var row;
|
||
var even; /* even-power-of-two zeros operator */
|
||
var odd; /* odd-power-of-two zeros operator */
|
||
|
||
/* degenerate case (also disallow negative lengths) */
|
||
if (len2 <= 0)
|
||
return crc1;
|
||
|
||
even = new Array(GF2_DIM);
|
||
odd = new Array(GF2_DIM);
|
||
|
||
/* put operator for one zero bit in odd */
|
||
odd[0] = 0xedb88320; /* CRC-32 polynomial */
|
||
row = 1;
|
||
for (n = 1; n < GF2_DIM; n++) {
|
||
odd[n] = row;
|
||
row <<= 1;
|
||
}
|
||
|
||
/* put operator for two zero bits in even */
|
||
gf2_matrix_square(even, odd);
|
||
|
||
/* put operator for four zero bits in odd */
|
||
gf2_matrix_square(odd, even);
|
||
|
||
/* apply len2 zeros to crc1 (first square will put the operator for one
|
||
zero byte, eight zero bits, in even) */
|
||
do {
|
||
/* apply zeros operator for this bit of len2 */
|
||
gf2_matrix_square(even, odd);
|
||
if (len2 & 1)
|
||
crc1 = gf2_matrix_times(even, crc1);
|
||
len2 >>= 1;
|
||
|
||
/* if no more bits set, then done */
|
||
if (len2 == 0)
|
||
break;
|
||
|
||
/* another iteration of the loop with odd and even swapped */
|
||
gf2_matrix_square(odd, even);
|
||
if (len2 & 1)
|
||
crc1 = gf2_matrix_times(odd, crc1);
|
||
len2 >>= 1;
|
||
|
||
/* if no more bits set, then done */
|
||
} while (len2 != 0);
|
||
|
||
/* return combined crc */
|
||
crc1 ^= crc2;
|
||
return crc1;
|
||
};
|
||
|
||
}());
|
||
/**
|
||
* @description Intel AMT Redirection Transport Module - using websocket relay
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.1f
|
||
*/
|
||
|
||
// Construct a MeshServer object
|
||
var CreateAmtRedirect = function (module, authCookie) {
|
||
var obj = {};
|
||
obj.m = module; // This is the inner module (Terminal or Desktop)
|
||
module.parent = obj;
|
||
obj.authCookie = authCookie;
|
||
obj.State = 0;
|
||
obj.socket = null;
|
||
// ###BEGIN###{!Mode-Firmware}
|
||
obj.host = null;
|
||
obj.port = 0;
|
||
obj.user = null;
|
||
obj.pass = null;
|
||
obj.authuri = "/RedirectionService";
|
||
obj.tlsv1only = 0;
|
||
obj.inDataCount = 0;
|
||
// ###END###{!Mode-Firmware}
|
||
obj.connectstate = 0;
|
||
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
|
||
obj.debugmode = 0;
|
||
|
||
obj.amtaccumulator = "";
|
||
obj.amtsequence = 1;
|
||
obj.amtkeepalivetimer = null;
|
||
|
||
obj.onStateChanged = null;
|
||
|
||
// Private method
|
||
//obj.Debug = function (msg) { console.log(msg); }
|
||
|
||
obj.Start = function (host, port, user, pass, tls) {
|
||
obj.host = host;
|
||
obj.port = port;
|
||
obj.user = user;
|
||
obj.pass = pass;
|
||
obj.connectstate = 0;
|
||
obj.inDataCount = 0;
|
||
var url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=2&host=" + host + "&port=" + port + "&tls=" + tls + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : ""); // The "p=2" indicates to the relay that this is a REDIRECTION session
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
obj.socket = new WebSocket(url);
|
||
obj.socket.onopen = obj.xxOnSocketConnected;
|
||
obj.socket.onmessage = obj.xxOnMessage;
|
||
obj.socket.onclose = obj.xxOnSocketClosed;
|
||
obj.xxStateChange(1);
|
||
}
|
||
|
||
obj.xxOnSocketConnected = function () {
|
||
//obj.Debug("Redir Socket Connected");
|
||
if (obj.debugmode == 1) { console.log('onSocketConnected'); }
|
||
obj.xxStateChange(2);
|
||
if (obj.protocol == 1) obj.xxSend(obj.RedirectStartSol); // TODO: Put these strings in higher level module to tighten code
|
||
if (obj.protocol == 2) obj.xxSend(obj.RedirectStartKvm); // Don't need these is the feature is not compiled-in.
|
||
if (obj.protocol == 3) obj.xxSend(obj.RedirectStartIder);
|
||
}
|
||
|
||
// Setup the file reader
|
||
var fileReader = new FileReader();
|
||
var fileReaderInuse = false, fileReaderAcc = [];
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReader.onload = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReader.onloadend = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
|
||
}
|
||
|
||
obj.xxOnMessage = function (e) {
|
||
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
|
||
obj.inDataCount++;
|
||
if (typeof e.data == 'object') {
|
||
if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsBinaryString(new Blob([e.data]));
|
||
} else if (f.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
obj.xxOnSocketData(binary);
|
||
}
|
||
} else {
|
||
// If we get a string object, it maybe the WebRTC confirm. Ignore it.
|
||
// obj.debug("MeshDataChannel - OnData - " + typeof e.data + " - " + e.data.length);
|
||
obj.xxOnSocketData(e.data);
|
||
}
|
||
};
|
||
|
||
obj.xxOnSocketData = function (data) {
|
||
if (!data || obj.connectstate == -1) return;
|
||
|
||
if (typeof data === 'object') {
|
||
// This is an ArrayBuffer, convert it to a string array (used in IE)
|
||
var binary = "";
|
||
var bytes = new Uint8Array(data);
|
||
var length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
data = binary;
|
||
}
|
||
else if (typeof data !== 'string') { return; }
|
||
|
||
if ((obj.protocol == 2 || obj.protocol == 3) && obj.connectstate == 1) { return obj.m.ProcessData(data); } // KVM traffic, forward it directly.
|
||
obj.amtaccumulator += data;
|
||
//obj.Debug("Redir Recv(" + obj.amtaccumulator.length + "): " + rstr2hex(obj.amtaccumulator));
|
||
while (obj.amtaccumulator.length >= 1) {
|
||
var cmdsize = 0;
|
||
switch (obj.amtaccumulator.charCodeAt(0)) {
|
||
case 0x11: // StartRedirectionSessionReply (17)
|
||
if (obj.amtaccumulator.length < 4) return;
|
||
var statuscode = obj.amtaccumulator.charCodeAt(1);
|
||
switch (statuscode) {
|
||
case 0: // STATUS_SUCCESS
|
||
if (obj.amtaccumulator.length < 13) return;
|
||
var oemlen = obj.amtaccumulator.charCodeAt(12);
|
||
if (obj.amtaccumulator.length < 13 + oemlen) return;
|
||
// Query for available authentication
|
||
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); // Query authentication support
|
||
cmdsize = (13 + oemlen);
|
||
break;
|
||
default:
|
||
obj.Stop(1);
|
||
break;
|
||
}
|
||
break;
|
||
case 0x14: // AuthenticateSessionReply (20)
|
||
if (obj.amtaccumulator.length < 9) return;
|
||
var authDataLen = ReadIntX(obj.amtaccumulator, 5);
|
||
if (obj.amtaccumulator.length < 9 + authDataLen) return;
|
||
var status = obj.amtaccumulator.charCodeAt(1);
|
||
var authType = obj.amtaccumulator.charCodeAt(4);
|
||
var authData = [];
|
||
for (i = 0; i < authDataLen; i++) { authData.push(obj.amtaccumulator.charCodeAt(9 + i)); }
|
||
var authDataBuf = obj.amtaccumulator.substring(9, 9 + authDataLen);
|
||
cmdsize = 9 + authDataLen;
|
||
if (authType == 0) {
|
||
// Query
|
||
if (authData.indexOf(4) >= 0) {
|
||
// Good Digest Auth (With cnonce and all)
|
||
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04) + IntToStrX(obj.user.length + obj.authuri.length + 8) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00, 0x00));
|
||
}
|
||
else if (authData.indexOf(3) >= 0) {
|
||
// Bad Digest Auth (Not sure why this is supported, cnonce is not used!)
|
||
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x03) + IntToStrX(obj.user.length + obj.authuri.length + 7) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00));
|
||
}
|
||
else if (authData.indexOf(1) >= 0) {
|
||
// Basic Auth (Probably a good idea to not support this unless this is an old version of Intel AMT)
|
||
obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01) + IntToStrX(obj.user.length + obj.pass.length + 2) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(obj.pass.length) + obj.pass);
|
||
}
|
||
else obj.Stop(2);
|
||
}
|
||
else if ((authType == 3 || authType == 4) && status == 1) {
|
||
var curptr = 0;
|
||
|
||
// Realm
|
||
var realmlen = authDataBuf.charCodeAt(curptr);
|
||
var realm = authDataBuf.substring(curptr + 1, curptr + 1 + realmlen);
|
||
curptr += (realmlen + 1);
|
||
|
||
// Nonce
|
||
var noncelen = authDataBuf.charCodeAt(curptr);
|
||
var nonce = authDataBuf.substring(curptr + 1, curptr + 1 + noncelen);
|
||
curptr += (noncelen + 1);
|
||
|
||
// QOP
|
||
var qoplen = 0;
|
||
var qop = null;
|
||
var cnonce = obj.xxRandomNonce(32);
|
||
var snc = '00000002';
|
||
var extra = '';
|
||
if (authType == 4) {
|
||
qoplen = authDataBuf.charCodeAt(curptr);
|
||
qop = authDataBuf.substring(curptr + 1, curptr + 1 + qoplen);
|
||
curptr += (qoplen + 1);
|
||
extra = snc + ":" + cnonce + ":" + qop + ":";
|
||
}
|
||
|
||
var digest = hex_md5(hex_md5(obj.user + ":" + realm + ":" + obj.pass) + ":" + nonce + ":" + extra + hex_md5("POST:" + obj.authuri));
|
||
var totallen = obj.user.length + realm.length + nonce.length + obj.authuri.length + cnonce.length + snc.length + digest.length + 7;
|
||
if (authType == 4) totallen += (qop.length + 1);
|
||
var buf = String.fromCharCode(0x13, 0x00, 0x00, 0x00, authType) + IntToStrX(totallen) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(realm.length) + realm + String.fromCharCode(nonce.length) + nonce + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(cnonce.length) + cnonce + String.fromCharCode(snc.length) + snc + String.fromCharCode(digest.length) + digest;
|
||
if (authType == 4) buf += (String.fromCharCode(qop.length) + qop);
|
||
obj.xxSend(buf);
|
||
}
|
||
else
|
||
if (status == 0) { // Success
|
||
if (obj.protocol == 1) {
|
||
// Serial-over-LAN: Send Intel AMT serial settings...
|
||
var MaxTxBuffer = 10000;
|
||
var TxTimeout = 100;
|
||
var TxOverflowTimeout = 0;
|
||
var RxTimeout = 10000;
|
||
var RxFlushTimeout = 100;
|
||
var Heartbeat = 0;//5000;
|
||
obj.xxSend(String.fromCharCode(0x20, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + ShortToStrX(MaxTxBuffer) + ShortToStrX(TxTimeout) + ShortToStrX(TxOverflowTimeout) + ShortToStrX(RxTimeout) + ShortToStrX(RxFlushTimeout) + ShortToStrX(Heartbeat) + IntToStrX(0));
|
||
}
|
||
if (obj.protocol == 2) {
|
||
// Remote Desktop: Send traffic directly...
|
||
obj.xxSend(String.fromCharCode(0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
|
||
}
|
||
if (obj.protocol == 3) {
|
||
// Remote IDER: Send traffic directly...
|
||
obj.connectstate = 1;
|
||
obj.xxStateChange(3);
|
||
}
|
||
} else obj.Stop(3);
|
||
break;
|
||
case 0x21: // Response to settings (33)
|
||
if (obj.amtaccumulator.length < 23) break;
|
||
cmdsize = 23;
|
||
obj.xxSend(String.fromCharCode(0x27, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + String.fromCharCode(0x00, 0x00, 0x1B, 0x00, 0x00, 0x00));
|
||
if (obj.protocol == 1) { obj.amtkeepalivetimer = setInterval(obj.xxSendAmtKeepAlive, 2000); }
|
||
obj.connectstate = 1;
|
||
obj.xxStateChange(3);
|
||
break;
|
||
case 0x29: // Serial Settings (41)
|
||
if (obj.amtaccumulator.length < 10) break;
|
||
cmdsize = 10;
|
||
break;
|
||
case 0x2A: // Incoming display data (42)
|
||
if (obj.amtaccumulator.length < 10) break;
|
||
var cs = (10 + ((obj.amtaccumulator.charCodeAt(9) & 0xFF) << 8) + (obj.amtaccumulator.charCodeAt(8) & 0xFF));
|
||
if (obj.amtaccumulator.length < cs) break;
|
||
obj.m.ProcessData(obj.amtaccumulator.substring(10, cs));
|
||
cmdsize = cs;
|
||
break;
|
||
case 0x2B: // Keep alive message (43)
|
||
if (obj.amtaccumulator.length < 8) break;
|
||
cmdsize = 8;
|
||
break;
|
||
case 0x41:
|
||
if (obj.amtaccumulator.length < 8) break;
|
||
obj.connectstate = 1;
|
||
obj.m.Start();
|
||
// KVM traffic, forward rest of accumulator directly.
|
||
if (obj.amtaccumulator.length > 8) { obj.m.ProcessData(obj.amtaccumulator.substring(8)); }
|
||
cmdsize = obj.amtaccumulator.length;
|
||
break;
|
||
default:
|
||
console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length);
|
||
obj.Stop(4);
|
||
return;
|
||
}
|
||
if (cmdsize == 0) return;
|
||
obj.amtaccumulator = obj.amtaccumulator.substring(cmdsize);
|
||
}
|
||
}
|
||
|
||
obj.xxSend = function (x) {
|
||
//obj.Debug("Redir Send(" + x.length + "): " + rstr2hex(x));
|
||
if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
|
||
if (obj.debugmode == 1) { console.log('Send', x); }
|
||
var b = new Uint8Array(x.length);
|
||
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
|
||
obj.socket.send(b.buffer);
|
||
}
|
||
}
|
||
|
||
obj.send = function (x) {
|
||
if (obj.socket == null || obj.connectstate != 1) return;
|
||
if (obj.protocol == 1) { obj.xxSend(String.fromCharCode(0x28, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + ShortToStrX(x.length) + x); } else { obj.xxSend(x); }
|
||
}
|
||
|
||
obj.xxSendAmtKeepAlive = function () {
|
||
if (obj.socket == null) return;
|
||
obj.xxSend(String.fromCharCode(0x2B, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++));
|
||
}
|
||
|
||
obj.xxRandomNonceX = "abcdef0123456789";
|
||
obj.xxRandomNonce = function (length) {
|
||
var r = "";
|
||
for (var i = 0; i < length; i++) { r += obj.xxRandomNonceX.charAt(Math.floor(Math.random() * obj.xxRandomNonceX.length)); }
|
||
return r;
|
||
}
|
||
|
||
obj.xxOnSocketClosed = function () {
|
||
if (obj.debugmode == 1) { console.log('onSocketClosed'); }
|
||
//obj.Debug("Redir Socket Closed");
|
||
if ((obj.inDataCount == 0) && (obj.tlsv1only == 0)) {
|
||
obj.tlsv1only = 1;
|
||
obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=2&host=" + obj.host + "&port=" + obj.port + "&tls=" + obj.tls + "&tls1only=1" + ((obj.user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + obj.user) : "")); // The "p=2" indicates to the relay that this is a REDIRECTION session
|
||
obj.socket.onopen = obj.xxOnSocketConnected;
|
||
obj.socket.onmessage = obj.xxOnMessage;
|
||
obj.socket.onclose = obj.xxOnSocketClosed;
|
||
} else {
|
||
obj.Stop(5);
|
||
}
|
||
}
|
||
|
||
obj.xxStateChange = function(newstate) {
|
||
if (obj.State == newstate) return;
|
||
obj.State = newstate;
|
||
obj.m.xxStateChange(obj.State);
|
||
if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
|
||
}
|
||
|
||
obj.Stop = function (x) {
|
||
if (obj.debugmode == 1) { console.log('onSocketStop', x); }
|
||
//obj.Debug("Redir Socket Stopped");
|
||
obj.xxStateChange(0);
|
||
obj.connectstate = -1;
|
||
obj.amtaccumulator = "";
|
||
if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
|
||
if (obj.amtkeepalivetimer != null) { clearInterval(obj.amtkeepalivetimer); obj.amtkeepalivetimer = null; }
|
||
}
|
||
|
||
obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
|
||
obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
|
||
obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @description WSMAN communication using websocket
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.2.0c
|
||
*/
|
||
|
||
// Construct a WSMAN communication object
|
||
var CreateWsmanComm = function (host, port, user, pass, tls) {
|
||
var obj = {};
|
||
obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
|
||
obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
|
||
obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
|
||
obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
|
||
obj.challengeParams = null;
|
||
obj.noncecounter = 1;
|
||
obj.authcounter = 0;
|
||
obj.socket = null;
|
||
obj.socketState = 0;
|
||
obj.host = host;
|
||
obj.port = port;
|
||
obj.user = user;
|
||
obj.pass = pass;
|
||
obj.tls = tls;
|
||
obj.tlsv1only = 1;
|
||
obj.cnonce = Math.random().toString(36).substring(7); // Generate a random client nonce
|
||
|
||
// Private method
|
||
//obj.Debug = function (msg) { console.log(msg); }
|
||
|
||
// Private method
|
||
// pri = priority, if set to 1, the call is high priority and put on top of the stack.
|
||
obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
|
||
if (obj.ActiveAjaxCount < obj.MaxActiveAjaxCount && obj.PendingAjax.length == 0) {
|
||
// There are no pending AJAX calls, perform the call now.
|
||
obj.PerformAjaxEx(postdata, callback, tag, url, action);
|
||
} else {
|
||
// If this is a high priority call, put this call in front of the array, otherwise put it in the back.
|
||
if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
|
||
}
|
||
}
|
||
|
||
// Private method
|
||
obj.PerformNextAjax = function () {
|
||
if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
|
||
var x = obj.PendingAjax.shift();
|
||
obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
|
||
obj.PerformNextAjax();
|
||
}
|
||
|
||
// Private method
|
||
obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
|
||
if (obj.FailAllError != 0) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag, url, action]); return; }
|
||
if (!postdata) postdata = "";
|
||
//console.log("SEND: " + postdata); // DEBUG
|
||
|
||
// We are in a websocket relay environment
|
||
obj.ActiveAjaxCount++;
|
||
return obj.PerformAjaxExNodeJS(postdata, callback, tag, url, action);
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
obj.pendingAjaxCall = [];
|
||
|
||
// Websocket relay specific private method
|
||
obj.PerformAjaxExNodeJS = function (postdata, callback, tag, url, action) { obj.PerformAjaxExNodeJS2(postdata, callback, tag, url, action, 3); }
|
||
|
||
// Websocket relay specific private method
|
||
obj.PerformAjaxExNodeJS2 = function (postdata, callback, tag, url, action, retry) {
|
||
if (retry <= 0 || obj.FailAllError != 0) {
|
||
// Too many retry, fail here.
|
||
obj.ActiveAjaxCount--;
|
||
if (obj.FailAllError != 999) obj.gotNextMessages(null, 'error', { status: ((obj.FailAllError == 0) ? 408 : obj.FailAllError) }, [postdata, callback, tag, url, action]); // 408 is timeout error
|
||
obj.PerformNextAjax();
|
||
return;
|
||
}
|
||
obj.pendingAjaxCall.push([postdata, callback, tag, url, action, retry]);
|
||
if (obj.socketState == 0) { obj.xxConnectHttpSocket(); }
|
||
else if (obj.socketState == 2) { obj.sendRequest(postdata, url, action); }
|
||
}
|
||
|
||
// Websocket relay specific private method (Content Length Encoding)
|
||
obj.sendRequest = function (postdata, url, action) {
|
||
url = url ? url : "/wsman";
|
||
action = action ? action : "POST";
|
||
var h = action + " " + url + " HTTP/1.1\r\n";
|
||
if (obj.challengeParams != null) {
|
||
var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams["realm"] + ':' + obj.pass) + ':' + obj.challengeParams["nonce"] + ':' + obj.noncecounter + ':' + obj.cnonce + ':' + obj.challengeParams["qop"] + ':' + hex_md5(action + ':' + url));
|
||
h += 'Authorization: ' + obj.renderDigest({ "username": obj.user, "realm": obj.challengeParams["realm"], "nonce": obj.challengeParams["nonce"], "uri": url, "qop": obj.challengeParams["qop"], "response": response, "nc": obj.noncecounter++, "cnonce": obj.cnonce }) + '\r\n';
|
||
}
|
||
//h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
|
||
h += 'Host: ' + obj.host + ':' + obj.port + '\r\nTransfer-Encoding: chunked\r\n\r\n' + postdata.length.toString(16).toUpperCase() + '\r\n' + postdata + '\r\n0\r\n\r\n'; // Use Chunked-Encoding
|
||
_Send(h);
|
||
//obj.Debug("SEND: " + h); // Display send packet
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
obj.parseDigest = function (header) {
|
||
var t = header.substring(7).split(',');
|
||
for (i in t) t[i] = t[i].trim();
|
||
return t.reduce(function (obj, s) { var parts = s.split('='); obj[parts[0]] = parts[1].replace(/"/g, ''); return obj; }, {})
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
obj.renderDigest = function (params) {
|
||
var paramsnames = [];
|
||
for (i in params) { paramsnames.push(i); }
|
||
return 'Digest ' + paramsnames.reduce(function (s1, ii) { return s1 + ',' + ii + '="' + params[ii] + '"' }, '').substring(1);
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
obj.xxConnectHttpSocket = function () {
|
||
//obj.Debug("xxConnectHttpSocket");
|
||
obj.socketParseState = 0;
|
||
obj.socketAccumulator = '';
|
||
obj.socketHeader = null;
|
||
obj.socketData = '';
|
||
obj.socketState = 1;
|
||
|
||
console.log(obj.tlsv1only);
|
||
obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=1&host=" + obj.host + "&port=" + obj.port + "&tls=" + obj.tls + "&tlsv1only=" + obj.tlsv1only + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "")); // The "p=1" indicates to the relay that this is a WSMAN session
|
||
obj.socket.onopen = _OnSocketConnected;
|
||
obj.socket.onmessage = _OnMessage;
|
||
obj.socket.onclose = _OnSocketClosed;
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
function _OnSocketConnected() {
|
||
//obj.Debug("xxOnSocketConnected");
|
||
obj.socketState = 2;
|
||
for (i in obj.pendingAjaxCall) { obj.sendRequest(obj.pendingAjaxCall[i][0], obj.pendingAjaxCall[i][3], obj.pendingAjaxCall[i][4]); }
|
||
}
|
||
|
||
// Setup the file reader
|
||
var fileReader = new FileReader();
|
||
var fileReaderInuse = false, fileReaderAcc = [];
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReader.onload = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReader.onloadend = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
|
||
}
|
||
|
||
function _OnMessage(e) {
|
||
if (typeof e.data == 'object') {
|
||
if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsBinaryString(new Blob([e.data]));
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
_OnSocketData(binary);
|
||
}
|
||
} else {
|
||
_OnSocketData(e.data);
|
||
}
|
||
};
|
||
|
||
// Websocket relay specific private method
|
||
function _OnSocketData(data) {
|
||
//obj.Debug("_OnSocketData (" + data.length + "): " + data);
|
||
|
||
if (typeof data === 'object') {
|
||
// This is an ArrayBuffer, convert it to a string array (used in IE)
|
||
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
data = binary;
|
||
}
|
||
else if (typeof data !== 'string') return;
|
||
|
||
//console.log("RECV: " + data); // DEBUG
|
||
|
||
obj.socketAccumulator += data;
|
||
while (true) {
|
||
if (obj.socketParseState == 0) {
|
||
var headersize = obj.socketAccumulator.indexOf("\r\n\r\n");
|
||
if (headersize < 0) return;
|
||
//obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
|
||
obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split("\r\n");
|
||
obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
|
||
obj.socketParseState = 1;
|
||
obj.socketData = '';
|
||
obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
|
||
for (i in obj.socketHeader) {
|
||
if (i != 0) {
|
||
var x2 = obj.socketHeader[i].indexOf(':');
|
||
obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
|
||
}
|
||
}
|
||
}
|
||
if (obj.socketParseState == 1) {
|
||
var csize = -1;
|
||
if ((obj.socketXHeader["connection"] != undefined) && (obj.socketXHeader["connection"].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
|
||
// The body ends with a close, in this case, we will only process the header
|
||
csize = 0;
|
||
} else if (obj.socketXHeader["content-length"] != undefined) {
|
||
// The body length is specified by the content-length
|
||
csize = parseInt(obj.socketXHeader["content-length"]);
|
||
if (obj.socketAccumulator.length < csize) return;
|
||
var data = obj.socketAccumulator.substring(0, csize);
|
||
obj.socketAccumulator = obj.socketAccumulator.substring(csize);
|
||
obj.socketData = data;
|
||
csize = 0;
|
||
} else {
|
||
// The body is chunked
|
||
var clen = obj.socketAccumulator.indexOf("\r\n");
|
||
if (clen < 0) return; // Chunk length not found, exit now and get more data.
|
||
// Chunk length if found, lets see if we can get the data.
|
||
csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
|
||
if (isNaN(csize)) { if (obj.websocket) { obj.websocket.close(); } return; } // Critical error, close the socket and exit.
|
||
if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
|
||
// We got a chunk with all of the data, handle the chunck now.
|
||
var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
|
||
obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
|
||
obj.socketData += data;
|
||
}
|
||
if (csize == 0) {
|
||
//obj.Debug("_OnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
|
||
_ProcessHttpResponse(obj.socketXHeader, obj.socketData);
|
||
obj.socketParseState = 0;
|
||
obj.socketHeader = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
function _ProcessHttpResponse(header, data) {
|
||
//obj.Debug("_ProcessHttpResponse: " + header.Directive[1]);
|
||
|
||
var s = parseInt(header.Directive[1]);
|
||
if (isNaN(s)) s = 602;
|
||
if (s == 401 && ++(obj.authcounter) < 3) {
|
||
obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
|
||
} else {
|
||
var r = obj.pendingAjaxCall.shift();
|
||
// if (s != 200) { obj.Debug("Error, status=" + s + "\r\n\r\nreq=" + r[0] + "\r\n\r\nresp=" + data); } // Debug: Display the request & response if something did not work.
|
||
obj.authcounter = 0;
|
||
obj.ActiveAjaxCount--;
|
||
obj.gotNextMessages(data, 'success', { status: s }, r);
|
||
obj.PerformNextAjax();
|
||
}
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
function _OnSocketClosed(data) {
|
||
//obj.Debug("_OnSocketClosed");
|
||
obj.socketState = 0;
|
||
if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
|
||
if (obj.pendingAjaxCall.length > 0) {
|
||
var r = obj.pendingAjaxCall.shift();
|
||
var retry = r[5];
|
||
obj.PerformAjaxExNodeJS2(r[0], r[1], r[2], r[3], r[4], --retry);
|
||
}
|
||
}
|
||
|
||
// Websocket relay specific private method
|
||
function _Send(x) {
|
||
//console.log("SEND: " + x); // DEBUG
|
||
if (obj.socketState == 2 && obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
|
||
var b = new Uint8Array(x.length);
|
||
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
|
||
try { obj.socket.send(b.buffer); } catch (e) { }
|
||
}
|
||
}
|
||
|
||
// Private method
|
||
obj.gotNextMessages = function (data, status, request, callArgs) {
|
||
if (obj.FailAllError == 999) return;
|
||
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
|
||
if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); return; }
|
||
callArgs[1](data, 200, callArgs[2]);
|
||
}
|
||
|
||
// Private method
|
||
obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
|
||
if (obj.FailAllError == 999) return;
|
||
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
|
||
callArgs[1](obj, null, { Header: { HttpError: request.status } }, request.status, callArgs[2]);
|
||
}
|
||
|
||
// Cancel all pending queries with given status
|
||
obj.CancelAllQueries = function (s) {
|
||
while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
|
||
if (obj.websocket != null) { obj.websocket.close(); obj.websocket = null; obj.socketState = 0; }
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* @description Mesh Agent Transport Module - using websocket relay
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.1f
|
||
*/
|
||
|
||
// Construct a MeshServer agent direction object
|
||
var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, authCookie) {
|
||
var obj = {};
|
||
obj.m = module; // This is the inner module (Terminal or Desktop)
|
||
module.parent = obj;
|
||
obj.meshserver = meshserver;
|
||
obj.authCookie = authCookie;
|
||
obj.State = 0;
|
||
obj.nodeid = null;
|
||
obj.socket = null;
|
||
obj.connectstate = -1;
|
||
obj.tunnelid = Math.random().toString(36).substring(2); // Generate a random client tunnel id
|
||
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
|
||
obj.onStateChanged = null;
|
||
obj.ctrlMsgAllowed = true;
|
||
obj.attemptWebRTC = false;
|
||
obj.webRtcActive = false;
|
||
obj.webSwitchOk = false;
|
||
obj.webchannel = null;
|
||
obj.webrtc = null;
|
||
obj.debugmode = 0;
|
||
|
||
// Private method
|
||
//obj.debug = function (msg) { console.log(msg); }
|
||
|
||
obj.Start = function (nodeid) {
|
||
var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?id=" + obj.tunnelid;
|
||
//if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; }
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
obj.nodeid = nodeid;
|
||
obj.connectstate = 0;
|
||
obj.socket = new WebSocket(url);
|
||
obj.socket.onopen = obj.xxOnSocketConnected;
|
||
obj.socket.onmessage = obj.xxOnMessage;
|
||
//obj.socket.onmessage = function (e) { console.log('Websocket data', e.data); obj.xxOnMessage(e); }
|
||
obj.socket.onerror = function (e) { /* console.error(e); */ }
|
||
obj.socket.onclose = obj.xxOnSocketClosed;
|
||
obj.xxStateChange(1);
|
||
//obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
|
||
obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid });
|
||
//obj.debug("Agent Redir Start: " + url);
|
||
}
|
||
|
||
obj.xxOnSocketConnected = function () {
|
||
if (obj.debugmode == 1) { console.log('onSocketConnected'); }
|
||
//obj.debug("Agent Redir Socket Connected");
|
||
obj.xxStateChange(2);
|
||
}
|
||
|
||
// Called to pass websocket control messages
|
||
obj.xxOnControlCommand = function (msg) {
|
||
var controlMsg;
|
||
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
|
||
if (controlMsg.ctrlChannel != '102938') { obj.xxOnSocketData(msg); return; }
|
||
//console.log(controlMsg);
|
||
if (obj.webrtc != null) {
|
||
if (controlMsg.type == 'answer') {
|
||
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
|
||
} else if (controlMsg.type == 'webrtc0') {
|
||
obj.webSwitchOk = true; // Other side is ready for switch over
|
||
performWebRtcSwitch();
|
||
} else if (controlMsg.type == 'webrtc1') {
|
||
obj.sendCtrlMsg("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}"); // Confirm we got end of data marker, indicates data will no longer be received on websocket.
|
||
} else if (controlMsg.type == 'webrtc2') {
|
||
// TODO: Resume/Start sending data over WebRTC
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.sendCtrlMsg = function (x) { if (obj.ctrlMsgAllowed == true) { if ((typeof args != 'undefined') && args.redirtrace) { console.log('RedirSend', typeof x, x); } try { obj.socket.send(x); } catch (ex) { } } }
|
||
|
||
function performWebRtcSwitch() {
|
||
if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) {
|
||
obj.sendCtrlMsg("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc0\"}"); // Indicate to the meshagent that it can start traffic switchover
|
||
obj.sendCtrlMsg("{\"ctrlChannel\":\"102938\",\"type\":\"webrtc1\"}"); // Indicate to the meshagent that data traffic will no longer be sent over websocket.
|
||
// TODO: Hold/Stop sending data over websocket
|
||
if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
|
||
}
|
||
}
|
||
|
||
obj.xxOnMessage = function (e) {
|
||
//console.log('Recv', e.data, e.data.byteLength, obj.State);
|
||
if (obj.State < 3) {
|
||
if (e.data == 'c') {
|
||
try { obj.socket.send(obj.protocol); } catch (ex) { }
|
||
obj.xxStateChange(3);
|
||
|
||
if (obj.attemptWebRTC == true) {
|
||
// Try to get WebRTC setup
|
||
var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
|
||
if (typeof RTCPeerConnection !== 'undefined') { obj.webrtc = new RTCPeerConnection(configuration); }
|
||
else if (typeof webkitRTCPeerConnection !== 'undefined') { obj.webrtc = new webkitRTCPeerConnection(configuration); }
|
||
if (obj.webrtc != null) {
|
||
obj.webchannel = obj.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
|
||
obj.webchannel.onmessage = obj.xxOnMessage;
|
||
//obj.webchannel.onmessage = function (e) { console.log('WebRTC data', e.data); obj.xxOnMessage(e); }
|
||
obj.webchannel.onopen = function () { obj.webRtcActive = true; performWebRtcSwitch(); };
|
||
obj.webchannel.onclose = function (event) { if (obj.webRtcActive) { obj.Stop(); } }
|
||
obj.webrtc.onicecandidate = function (e) {
|
||
if (e.candidate == null) {
|
||
try { obj.socket.send(JSON.stringify(obj.webrtcoffer)); } catch (ex) { } // End of candidates, send the offer
|
||
} else {
|
||
obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
|
||
}
|
||
}
|
||
obj.webrtc.oniceconnectionstatechange = function () {
|
||
if (obj.webrtc != null) {
|
||
if (obj.webrtc.iceConnectionState == 'disconnected') { if (obj.webRtcActive == true) { obj.Stop(); } else { obj.xxCloseWebRTC(); } }
|
||
else if (obj.webrtc.iceConnectionState == 'failed') { obj.xxCloseWebRTC(); }
|
||
}
|
||
}
|
||
obj.webrtc.createOffer(function (offer) {
|
||
// Got the offer
|
||
obj.webrtcoffer = offer;
|
||
obj.webrtc.setLocalDescription(offer, function () { /*console.log('WebRTC local ok');*/ }, obj.xxCloseWebRTC);
|
||
}, obj.xxCloseWebRTC, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (typeof e.data == 'string') {
|
||
// Control messages, most likely WebRTC setup
|
||
obj.xxOnControlCommand(e.data);
|
||
return;
|
||
}
|
||
|
||
/*
|
||
if (typeof e.data == 'object') {
|
||
var f = new FileReader();
|
||
if (f.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
f.onload = function (e) { obj.xxOnSocketData(e.target.result); }
|
||
f.readAsBinaryString(new Blob([e.data]));
|
||
} else if (f.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
f.onloadend = function (e) { obj.xxOnSocketData(e.target.result); }
|
||
f.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = "";
|
||
var bytes = new Uint8Array(e.data);
|
||
var length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
obj.xxOnSocketData(binary);
|
||
}
|
||
} else {
|
||
// If we get a string object, it maybe the WebRTC confirm. Ignore it.
|
||
obj.xxOnSocketData(e.data);
|
||
}
|
||
*/
|
||
|
||
if (typeof e.data == 'object') {
|
||
if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsBinaryString(new Blob([e.data]));
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
obj.xxOnSocketData(binary);
|
||
}
|
||
} else {
|
||
// If we get a string object, it maybe the WebRTC confirm. Ignore it.
|
||
obj.xxOnSocketData(e.data);
|
||
}
|
||
};
|
||
|
||
// Setup the file reader
|
||
var fileReader = new FileReader();
|
||
var fileReaderInuse = false, fileReaderAcc = [];
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReader.onload = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReader.onloadend = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
|
||
}
|
||
|
||
obj.xxOnSocketData = function (data) {
|
||
if (!data || obj.connectstate == -1) return;
|
||
if (typeof data === 'object') {
|
||
// This is an ArrayBuffer, convert it to a string array (used in IE)
|
||
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
data = binary;
|
||
}
|
||
else if (typeof data !== 'string') return;
|
||
//console.log("xxOnSocketData", rstr2hex(data));
|
||
if ((typeof args != 'undefined') && args.redirtrace) { console.log("RedirRecv", typeof data, data.length, data); }
|
||
return obj.m.ProcessData(data);
|
||
}
|
||
|
||
obj.sendText = function (x) {
|
||
if (typeof x != 'string') { x = JSON.stringify(x); } // Turn into a string if needed
|
||
obj.send(encode_utf8(x)); // Encode UTF8 correctly
|
||
}
|
||
|
||
obj.send = function (x) {
|
||
//obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
|
||
//console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + ((typeof x == 'string')?x:rstr2hex(x)));
|
||
if ((typeof args != 'undefined') && args.redirtrace) { console.log('RedirSend', typeof x, x.length, x); }
|
||
try {
|
||
if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
|
||
if (typeof x == 'string') {
|
||
if (obj.debugmode == 1) {
|
||
var b = new Uint8Array(x.length), c = [];
|
||
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
|
||
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
|
||
//console.log('Send', c);
|
||
} else {
|
||
var b = new Uint8Array(x.length);
|
||
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
|
||
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
|
||
}
|
||
} else {
|
||
//if (obj.debugmode == 1) { console.log('Send', x); }
|
||
if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
|
||
}
|
||
}
|
||
} catch (ex) { }
|
||
}
|
||
|
||
obj.xxOnSocketClosed = function () {
|
||
//obj.debug("Agent Redir Socket Closed");
|
||
//if (obj.debugmode == 1) { console.log('onSocketClosed'); }
|
||
obj.Stop(1);
|
||
}
|
||
|
||
obj.xxStateChange = function(newstate) {
|
||
if (obj.State == newstate) return;
|
||
obj.State = newstate;
|
||
obj.m.xxStateChange(obj.State);
|
||
if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
|
||
}
|
||
|
||
// Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
|
||
obj.xxCloseWebRTC = function () {
|
||
if (obj.webchannel != null) { try { obj.webchannel.close(); } catch (e) { } obj.webchannel = null; }
|
||
if (obj.webrtc != null) { try { obj.webrtc.close(); } catch (e) { } obj.webrtc = null; }
|
||
obj.webRtcActive = false;
|
||
}
|
||
|
||
obj.Stop = function (x) {
|
||
if (obj.debugmode == 1) { console.log('stop', x); }
|
||
|
||
// Clean up WebRTC
|
||
obj.xxCloseWebRTC();
|
||
|
||
//obj.debug("Agent Redir Socket Stopped");
|
||
obj.connectstate = -1;
|
||
if (obj.socket != null) {
|
||
try { if (obj.socket.readyState == 1) { obj.sendCtrlMsg("{\"ctrlChannel\":\"102938\",\"type\":\"close\"}"); obj.socket.close(); } } catch (e) { }
|
||
obj.socket = null;
|
||
}
|
||
obj.xxStateChange(0);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @description Mesh Agent Transport Module - using websocket relay
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.1
|
||
*/
|
||
|
||
// Construct a MeshServer agent direction object
|
||
var CreateKvmDataChannel = function (webchannel, module, keepalive) {
|
||
var obj = {};
|
||
obj.m = module; // This is the inner module (Terminal or Desktop)
|
||
module.parent = obj;
|
||
obj.webchannel = webchannel;
|
||
obj.State = 0;
|
||
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
|
||
obj.onStateChanged = null;
|
||
obj.onControlMsg = null;
|
||
obj.debugmode = 0;
|
||
obj.keepalive = keepalive;
|
||
obj.rtcKeepAlive = null;
|
||
|
||
// Private method
|
||
//obj.debug = function (msg) { console.log(msg); }
|
||
|
||
obj.Start = function () {
|
||
if (obj.debugmode == 1) { console.log('start'); }
|
||
obj.xxStateChange(3);
|
||
obj.webchannel.onmessage = obj.xxOnMessage;
|
||
obj.rtcKeepAlive = setInterval(obj.xxSendRtcKeepAlive, 30000);
|
||
}
|
||
|
||
// Setup the file reader
|
||
var fileReader = new FileReader();
|
||
var fileReaderInuse = false, fileReaderAcc = [];
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReader.onload = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
|
||
} else if (fileReader.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReader.onloadend = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
|
||
}
|
||
|
||
obj.xxOnMessage = function (e) {
|
||
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
|
||
//if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Recv(' + obj.State + '): ', typeof e.data, e.data); }
|
||
if (typeof e.data == 'string') { if (obj.onControlMsg != null) { obj.onControlMsg(e.data); } return; } // If this is a control message, handle it here.
|
||
if (typeof e.data == 'object') {
|
||
if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
|
||
if (fileReader.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsBinaryString(new Blob([e.data]));
|
||
} else if (f.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
fileReaderInuse = true;
|
||
fileReader.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
obj.xxOnSocketData(binary);
|
||
}
|
||
} else {
|
||
// If we get a string object, it maybe the WebRTC confirm. Ignore it.
|
||
//obj.debug("Agent Redir Relay - OnData - " + typeof e.data + " - " + e.data.length);
|
||
obj.xxOnSocketData(e.data);
|
||
}
|
||
};
|
||
|
||
/*
|
||
obj.xxOnMessage = function (e) {
|
||
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
|
||
//if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Recv(' + obj.State + '): ', typeof e.data, e.data); }
|
||
if (typeof e.data == 'string') { if (obj.onControlMsg != null) { obj.onControlMsg(e.data); } return; } // If this is a control message, handle it here.
|
||
if (typeof e.data == 'object') {
|
||
var f = new FileReader();
|
||
if (f.readAsBinaryString) {
|
||
// Chrome & Firefox (Draft)
|
||
f.onload = function (e) { obj.xxOnSocketData(e.target.result); }
|
||
f.readAsBinaryString(new Blob([e.data]));
|
||
} else if (f.readAsArrayBuffer) {
|
||
// Chrome & Firefox (Spec)
|
||
f.onloadend = function (e) { obj.xxOnSocketData(e.target.result); }
|
||
f.readAsArrayBuffer(e.data);
|
||
} else {
|
||
// IE10, readAsBinaryString does not exist, use an alternative.
|
||
var binary = '', bytes = new Uint8Array(e.data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
obj.xxOnSocketData(binary);
|
||
}
|
||
} else {
|
||
// If we get a string object, it maybe the WebRTC confirm. Ignore it.
|
||
//obj.debug("Agent Redir Relay - OnData - " + typeof e.data + " - " + e.data.length);
|
||
obj.xxOnSocketData(e.data);
|
||
}
|
||
};
|
||
*/
|
||
|
||
obj.xxOnSocketData = function (data) {
|
||
if (!data) return;
|
||
if (typeof data === 'object') {
|
||
// This is an ArrayBuffer, convert it to a string array (used in IE)
|
||
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
|
||
for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
|
||
data = binary;
|
||
}
|
||
else if (typeof data !== 'string') return;
|
||
//console.log("xxOnSocketData", rstr2hex(data));
|
||
return obj.m.ProcessData(data);
|
||
}
|
||
|
||
// Send a control message over the WebRTC data channel
|
||
obj.sendCtrlMsg = function (x) {
|
||
if (typeof x == 'string') {
|
||
obj.webchannel.send(x);
|
||
//if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Send(' + obj.State + '): ', typeof x, x); }
|
||
if (obj.keepalive != null) obj.keepalive.sendKeepAlive();
|
||
}
|
||
}
|
||
|
||
// Send a binary message over the WebRTC data channel
|
||
obj.send = function (x) {
|
||
if (typeof x == 'string') { var b = new Uint8Array(x.length); for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } x = b; }
|
||
//if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Send(' + obj.State + '): ', typeof x, x); }
|
||
obj.webchannel.send(x);
|
||
}
|
||
|
||
obj.xxStateChange = function(newstate) {
|
||
if (obj.State == newstate) return;
|
||
obj.State = newstate;
|
||
obj.m.xxStateChange(obj.State);
|
||
if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
|
||
}
|
||
|
||
obj.Stop = function () {
|
||
if (obj.debugmode == 1) { console.log('stop'); }
|
||
if (obj.rtcKeepAlive != null) { clearInterval(obj.rtcKeepAlive); obj.rtcKeepAlive = null; }
|
||
obj.xxStateChange(0);
|
||
}
|
||
|
||
obj.xxSendRtcKeepAlive = function () {
|
||
//if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-SendKeepAlive()'); }
|
||
obj.sendCtrlMsg(JSON.stringify({ action: 'ping' }));
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
/**
|
||
* @description Remote Desktop
|
||
* @author Ylian Saint-Hilaire
|
||
* @version v0.0.2g
|
||
*/
|
||
|
||
// Construct a MeshServer object
|
||
var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||
var obj = {}
|
||
obj.CanvasId = canvasid;
|
||
if (typeof canvasid === 'string') obj.CanvasId = Q(canvasid);
|
||
obj.Canvas = obj.CanvasId.getContext("2d");
|
||
obj.scrolldiv = scrolldiv;
|
||
obj.State = 0;
|
||
obj.PendingOperations = [];
|
||
obj.tilesReceived = 0;
|
||
obj.TilesDrawn = 0;
|
||
obj.KillDraw = 0;
|
||
obj.ipad = false;
|
||
obj.tabletKeyboardVisible = false;
|
||
obj.LastX = 0;
|
||
obj.LastY = 0;
|
||
obj.touchenabled = 0;
|
||
obj.submenuoffset = 0;
|
||
obj.touchtimer = null;
|
||
obj.TouchArray = {};
|
||
obj.connectmode = 0; // 0 = HTTP, 1 = WebSocket, 2 = WebRTC
|
||
obj.connectioncount = 0;
|
||
obj.rotation = 0;
|
||
obj.protocol = 2; // KVM
|
||
obj.debugmode = 0;
|
||
obj.firstUpKeys = [];
|
||
obj.stopInput = false;
|
||
obj.localKeyMap = true;
|
||
|
||
obj.sessionid = 0;
|
||
obj.username;
|
||
obj.oldie = false;
|
||
obj.CompressionLevel = 50;
|
||
obj.ScalingLevel = 1024;
|
||
obj.FrameRateTimer = 50;
|
||
obj.FirstDraw = false;
|
||
|
||
obj.ScreenWidth = 960;
|
||
obj.ScreenHeight = 700;
|
||
obj.width = 960;
|
||
obj.height = 960;
|
||
|
||
obj.onScreenSizeChange = null;
|
||
obj.onMessage = null;
|
||
obj.onConnectCountChanged = null;
|
||
obj.onDebugMessage = null;
|
||
obj.onTouchEnabledChanged = null;
|
||
obj.onDisplayinfo = null;
|
||
obj.accumulator = null;
|
||
|
||
obj.Start = function () {
|
||
obj.State = 0;
|
||
obj.accumulator = null;
|
||
}
|
||
|
||
obj.Stop = function () {
|
||
obj.setRotation(0);
|
||
obj.UnGrabKeyInput();
|
||
obj.UnGrabMouseInput();
|
||
obj.touchenabled = 0;
|
||
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||
obj.Canvas.clearRect(0, 0, obj.CanvasId.width, obj.CanvasId.height);
|
||
}
|
||
|
||
obj.xxStateChange = function (newstate) {
|
||
if (obj.State == newstate) return;
|
||
obj.State = newstate;
|
||
obj.CanvasId.style.cursor = 'default';
|
||
//console.log('xxStateChange', newstate);
|
||
switch (newstate) {
|
||
case 0: {
|
||
// Disconnect
|
||
obj.Stop();
|
||
break;
|
||
}
|
||
case 3: {
|
||
// Websocket connected
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.send = function (x) {
|
||
if (obj.debugmode > 1) { console.log("KSend(" + x.length + "): " + rstr2hex(x)); }
|
||
obj.parent.send(x);
|
||
}
|
||
|
||
// KVM Control.
|
||
// Routines for processing incoming packets from the AJAX server, and handling individual messages.
|
||
obj.ProcessPictureMsg = function (str, X, Y) {
|
||
//if (obj.targetnode != null) obj.Debug("ProcessPictureMsg " + X + "," + Y + " - " + obj.targetnode.substring(0, 8));
|
||
var tile = new Image();
|
||
tile.xcount = obj.tilesReceived++;
|
||
//console.log('Tile #' + tile.xcount);
|
||
var r = obj.tilesReceived;
|
||
tile.src = "data:image/jpeg;base64," + btoa(str.substring(4, str.length));
|
||
tile.onload = function () {
|
||
//console.log('DecodeTile #' + this.xcount);
|
||
if (obj.Canvas != null && obj.KillDraw < r && obj.State != 0) {
|
||
obj.PendingOperations.push([r, 2, tile, X, Y]);
|
||
while (obj.DoPendingOperations()) { }
|
||
}
|
||
}
|
||
tile.error = function () { console.log('DecodeTileError'); }
|
||
}
|
||
|
||
obj.DoPendingOperations = function () {
|
||
if (obj.PendingOperations.length == 0) return false;
|
||
for (var i = 0; i < obj.PendingOperations.length; i++) { // && KillDraw < tilesDrawn
|
||
var Msg = obj.PendingOperations[i];
|
||
if (Msg[0] == (obj.TilesDrawn + 1)) {
|
||
if (Msg[1] == 1) { obj.ProcessCopyRectMsg(Msg[2]); }
|
||
else if (Msg[1] == 2) { obj.Canvas.drawImage(Msg[2], obj.rotX(Msg[3], Msg[4]), obj.rotY(Msg[3], Msg[4])); delete Msg[2]; }
|
||
obj.PendingOperations.splice(i, 1);
|
||
delete Msg;
|
||
obj.TilesDrawn++;
|
||
if (obj.TilesDrawn == obj.tilesReceived && obj.KillDraw < obj.TilesDrawn) { obj.KillDraw = obj.TilesDrawn = obj.tilesReceived = 0; }
|
||
return true;
|
||
}
|
||
}
|
||
if (obj.oldie && obj.PendingOperations.length > 0) { obj.TilesDrawn++; }
|
||
return false;
|
||
}
|
||
|
||
obj.ProcessCopyRectMsg = function (str) {
|
||
var SX = ((str.charCodeAt(0) & 0xFF) << 8) + (str.charCodeAt(1) & 0xFF);
|
||
var SY = ((str.charCodeAt(2) & 0xFF) << 8) + (str.charCodeAt(3) & 0xFF);
|
||
var DX = ((str.charCodeAt(4) & 0xFF) << 8) + (str.charCodeAt(5) & 0xFF);
|
||
var DY = ((str.charCodeAt(6) & 0xFF) << 8) + (str.charCodeAt(7) & 0xFF);
|
||
var WIDTH = ((str.charCodeAt(8) & 0xFF) << 8) + (str.charCodeAt(9) & 0xFF);
|
||
var HEIGHT = ((str.charCodeAt(10) & 0xFF) << 8) + (str.charCodeAt(11) & 0xFF);
|
||
obj.Canvas.drawImage(Canvas.canvas, SX, SY, WIDTH, HEIGHT, DX, DY, WIDTH, HEIGHT);
|
||
}
|
||
|
||
obj.SendUnPause = function () {
|
||
//obj.Debug("SendUnPause");
|
||
//obj.xxStateChange(3);
|
||
obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x00));
|
||
}
|
||
|
||
obj.SendPause = function () {
|
||
//obj.Debug("SendPause");
|
||
//obj.xxStateChange(2);
|
||
obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x01));
|
||
}
|
||
|
||
obj.SendCompressionLevel = function (type, level, scaling, frametimer) {
|
||
if (level) { obj.CompressionLevel = level; }
|
||
if (scaling) { obj.ScalingLevel = scaling; }
|
||
if (frametimer) { obj.FrameRateTimer = frametimer; }
|
||
obj.send(String.fromCharCode(0x00, 0x05, 0x00, 0x0A, type, obj.CompressionLevel) + obj.shortToStr(obj.ScalingLevel) + obj.shortToStr(obj.FrameRateTimer));
|
||
}
|
||
|
||
obj.SendRefresh = function () {
|
||
obj.send(String.fromCharCode(0x00, 0x06, 0x00, 0x04));
|
||
}
|
||
|
||
obj.ProcessScreenMsg = function (width, height) {
|
||
if (obj.debugmode > 0) { console.log("ScreenSize: " + width + " x " + height); }
|
||
obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
|
||
obj.rotation = 0;
|
||
obj.FirstDraw = true;
|
||
obj.ScreenWidth = obj.width = width;
|
||
obj.ScreenHeight = obj.height = height;
|
||
obj.KillDraw = obj.tilesReceived;
|
||
while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); }
|
||
obj.SendCompressionLevel(1);
|
||
obj.SendUnPause();
|
||
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId); }
|
||
}
|
||
|
||
obj.ProcessData = function (str) {
|
||
var ptr = 0;
|
||
//console.log('x0', str.length);
|
||
while (ptr < str.length) {
|
||
//console.log('x1', ptr, str.length);
|
||
ptr += obj.ProcessDataEx(str.substring(ptr));
|
||
//console.log('x2', ptr, str.length);
|
||
}
|
||
}
|
||
|
||
obj.ProcessDataEx = function (str) {
|
||
if (obj.accumulator != null) {
|
||
str = obj.accumulator + str;
|
||
console.log('KVM using accumulated data, total size is now ' + str.length + ' bytes.');
|
||
obj.accumulator = null;
|
||
}
|
||
if (obj.debugmode > 1) { console.log("KRecv(" + str.length + "): " + rstr2hex(str.substring(0, Math.min(str.length, 40)))); }
|
||
if (str.length < 4) return;
|
||
var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2), jumboAdd = 0;
|
||
if ((command == 27) && (cmdsize == 8)) {
|
||
// Jumbo packet
|
||
if (str.length < 12) return;
|
||
command = ReadShort(str, 8)
|
||
cmdsize = ReadInt(str, 4);
|
||
//console.log('JUMBO cmd=' + command + ', cmdsize=' + cmdsize + ', data received=' + str.length);
|
||
if ((cmdsize + 8) > str.length) {
|
||
console.log('KVM accumulator set to ' + str.length + ' bytes, need ' + cmdsize + ' bytes.');
|
||
obj.accumulator = str;
|
||
return;
|
||
}
|
||
str = str.substring(8);
|
||
jumboAdd = 8;
|
||
}
|
||
if ((cmdsize != str.length) && (obj.debugmode > 0)) { console.log(cmdsize, str.length, cmdsize == str.length); }
|
||
if ((command >= 18) && (command != 65)) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, rstr2hex(str.substring(0, 40)) + '...'); return; }
|
||
if (cmdsize > str.length) {
|
||
console.log('KVM accumulator set to ' + str.length + ' bytes, need ' + cmdsize + ' bytes.');
|
||
obj.accumulator = str;
|
||
return;
|
||
}
|
||
//console.log("KVM Command: " + command + " Len:" + cmdsize);
|
||
|
||
if (command == 3 || command == 4 || command == 7) {
|
||
cmdmsg = str.substring(4, cmdsize);
|
||
X = ((cmdmsg.charCodeAt(0) & 0xFF) << 8) + (cmdmsg.charCodeAt(1) & 0xFF);
|
||
Y = ((cmdmsg.charCodeAt(2) & 0xFF) << 8) + (cmdmsg.charCodeAt(3) & 0xFF);
|
||
if (obj.debugmode > 0) { console.log("CMD" + command + " at X=" + X + " Y=" + Y); }
|
||
}
|
||
|
||
switch (command) {
|
||
case 3: // Tile
|
||
if (obj.FirstDraw) obj.onResize();
|
||
obj.ProcessPictureMsg(cmdmsg, X, Y);
|
||
break;
|
||
case 4: // Tile Copy
|
||
if (obj.FirstDraw) obj.onResize();
|
||
if (obj.TilesDrawn == obj.tilesReceived) {
|
||
obj.ProcessCopyRectMsg(cmdmsg);
|
||
} else {
|
||
obj.PendingOperations.push([ ++tilesReceived, 1, cmdmsg ]);
|
||
}
|
||
break;
|
||
case 7: // Screen size
|
||
obj.ProcessScreenMsg(X, Y);
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 16); // Shift
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 17); // Ctrl
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 18); // Alt
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 91); // Left-Windows
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 92); // Right-Windows
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 16); // Shift
|
||
obj.send(String.fromCharCode(0x00, 0x0E, 0x00, 0x04));
|
||
break;
|
||
case 11: // GetDisplays
|
||
var myOptions = [], dcount = ((str.charCodeAt(4) & 0xFF) << 8) + (str.charCodeAt(5) & 0xFF);
|
||
if (dcount > 0) {
|
||
// Many displays present
|
||
var selitem = 0, seldisp = ((str.charCodeAt(6 + (dcount * 2)) & 0xFF) << 8) + (str.charCodeAt(7 + (dcount * 2)) & 0xFF);
|
||
for (var i = 0; i < dcount; i++) {
|
||
var disp = ((str.charCodeAt(6 + (i * 2)) & 0xFF) << 8) + (str.charCodeAt(7 + (i * 2)) & 0xFF);
|
||
if (disp == 65535) { myOptions.push('All Displays'); } else { myOptions.push('Display ' + disp); }
|
||
if (disp == seldisp) selitem = i;
|
||
}
|
||
}
|
||
if (obj.onDisplayinfo != null) { obj.onDisplayinfo(obj, myOptions, selitem); }
|
||
break;
|
||
case 12: // SetDisplay
|
||
//console.log('SetDisplayConfirmed');
|
||
break;
|
||
case 14: // KVM_INIT_TOUCH
|
||
obj.touchenabled = 1;
|
||
obj.TouchArray = {};
|
||
if (obj.onTouchEnabledChanged != null) obj.onTouchEnabledChanged(obj.touchenabled);
|
||
break;
|
||
case 15: // KVM_TOUCH
|
||
obj.TouchArray = {};
|
||
break;
|
||
case 16: // MNG_KVM_CONNECTCOUNT
|
||
obj.connectioncount = ReadInt(str, 4);
|
||
//obj.Debug("Got KVM Connect Count: " + obj.connectioncount);
|
||
if (obj.onConnectCountChanged != null) obj.onConnectCountChanged(obj.connectioncount, obj);
|
||
break;
|
||
case 17: // MNG_KVM_MESSAGE
|
||
//obj.Debug("Got KVM Message: " + str.substring(4, cmdsize));
|
||
if (obj.onMessage != null) obj.onMessage(str.substring(4, cmdsize), obj);
|
||
break;
|
||
case 65: // Alert
|
||
str = str.substring(4);
|
||
if (str[0] != '.') { console.log(str); alert('KVM: ' + str); } else { console.log('KVM: ' + str.substring(1)); }
|
||
break;
|
||
}
|
||
return cmdsize + jumboAdd;
|
||
}
|
||
|
||
// Keyboard and Mouse I/O.
|
||
obj.MouseButton = { "NONE": 0x00, "LEFT": 0x02, "RIGHT": 0x08, "MIDDLE": 0x20 };
|
||
obj.KeyAction = { "NONE": 0, "DOWN": 1, "UP": 2, "SCROLL": 3, "EXUP": 4, "EXDOWN": 5, "DBLCLICK": 6 };
|
||
obj.InputType = { "KEY": 1, "MOUSE": 2, "CTRLALTDEL": 10, "TOUCH": 15 };
|
||
obj.Alternate = 0;
|
||
|
||
var convertKeyCodeTable = {
|
||
"Pause": 19,
|
||
"CapsLock": 20,
|
||
"Space": 32,
|
||
"Quote": 222,
|
||
"Minus": 189,
|
||
"NumpadMultiply": 106,
|
||
"NumpadAdd": 107,
|
||
"PrintScreen": 44,
|
||
"Comma": 188,
|
||
"NumpadSubtract": 109,
|
||
"NumpadDecimal": 110,
|
||
"Period": 190,
|
||
"Slash": 191,
|
||
"NumpadDivide": 111,
|
||
"Semicolon": 186,
|
||
"Equal": 187,
|
||
"OSLeft": 91,
|
||
"BracketLeft": 219,
|
||
"OSRight": 91,
|
||
"Backslash": 220,
|
||
"BracketRight": 221,
|
||
"ContextMenu": 93,
|
||
"Backquote": 192,
|
||
"NumLock": 144,
|
||
"ScrollLock": 145,
|
||
"Backspace": 8,
|
||
"Tab": 9,
|
||
"Enter": 13,
|
||
"NumpadEnter": 13,
|
||
"Escape": 27,
|
||
"Delete": 46,
|
||
"Home": 36,
|
||
"PageUp": 33,
|
||
"PageDown": 34,
|
||
"ArrowLeft": 37,
|
||
"ArrowUp": 38,
|
||
"ArrowRight": 39,
|
||
"ArrowDown": 40,
|
||
"End": 35,
|
||
"Insert": 45,
|
||
"F1": 112,
|
||
"F2": 113,
|
||
"F3": 114,
|
||
"F4": 115,
|
||
"F5": 116,
|
||
"F6": 117,
|
||
"F7": 118,
|
||
"F8": 119,
|
||
"F9": 120,
|
||
"F10": 121,
|
||
"F11": 122,
|
||
"F12": 123,
|
||
"ShiftLeft": 16,
|
||
"ShiftRight": 16,
|
||
"ControlLeft": 17,
|
||
"ControlRight": 17,
|
||
"AltLeft": 18,
|
||
"AltRight": 18,
|
||
"MetaLeft": 91,
|
||
"MetaRight": 92,
|
||
"VolumeMute": 181
|
||
//"LaunchMail":
|
||
//"LaunchApp1":
|
||
//"LaunchApp2":
|
||
//"BrowserStop":
|
||
//"MediaStop":
|
||
//"MediaTrackPrevious":
|
||
//"MediaTrackNext":
|
||
//"MediaPlayPause":
|
||
//"MediaSelect":
|
||
}
|
||
|
||
function convertKeyCode(e) {
|
||
if (e.code.startsWith('Key') && e.code.length == 4) { return e.code.charCodeAt(3); }
|
||
if (e.code.startsWith('Digit') && e.code.length == 6) { return e.code.charCodeAt(5); }
|
||
if (e.code.startsWith('Numpad') && e.code.length == 7) { return e.code.charCodeAt(6) + 48; }
|
||
return convertKeyCodeTable[e.code];
|
||
}
|
||
|
||
obj.SendKeyMsg = function (action, event) {
|
||
if (action == null) return;
|
||
if (!event) { event = window.event; }
|
||
if (event.code && (obj.localKeyMap == false)) {
|
||
// Convert "event.code" into a scancode. This works the same regardless of the keyboard language.
|
||
// Older browsers will not support this.
|
||
var kc = convertKeyCode(event);
|
||
if (kc != null) { obj.SendKeyMsgKC(action, kc); }
|
||
} else {
|
||
// Use this keycode, this works best with "US-EN" keyboards.
|
||
// Older browser support this.
|
||
var kc = event.keyCode;
|
||
if (kc == 0x3B) { kc = 0xBA; } // Fix the ';' key
|
||
obj.SendKeyMsgKC(action, kc);
|
||
}
|
||
}
|
||
|
||
obj.SendMessage = function (msg) {
|
||
if (obj.State == 3) obj.send(String.fromCharCode(0x00, 0x11) + obj.shortToStr(4 + msg.length) + msg); // 0x11 = 17 MNG_KVM_MESSAGE
|
||
}
|
||
|
||
obj.SendKeyMsgKC = function (action, kc) {
|
||
//console.log('SendKeyMsgKC', action, kc);
|
||
if (obj.State != 3) return;
|
||
if (typeof action == 'object') { for (var i in action) { obj.SendKeyMsgKC(action[i][0], action[i][1]); } }
|
||
else { obj.send(String.fromCharCode(0x00, obj.InputType.KEY, 0x00, 0x06, (action - 1), kc)); }
|
||
}
|
||
|
||
obj.sendcad = function() { obj.SendCtrlAltDelMsg(); }
|
||
|
||
obj.SendCtrlAltDelMsg = function () {
|
||
if (obj.State == 3) { obj.send(String.fromCharCode(0x00, obj.InputType.CTRLALTDEL, 0x00, 0x04)); }
|
||
}
|
||
|
||
obj.SendEscKey = function () {
|
||
if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.KEY, 0x00, 0x06, 0x00, 0x1B, 0x00, obj.InputType.KEY, 0x00, 0x06, 0x01, 0x1B));
|
||
}
|
||
|
||
obj.SendStartMsg = function () {
|
||
obj.SendKeyMsgKC(obj.KeyAction.EXDOWN, 0x5B); // L-Windows
|
||
obj.SendKeyMsgKC(obj.KeyAction.EXUP, 0x5B); // L-Windows
|
||
}
|
||
|
||
obj.SendCharmsMsg = function () {
|
||
obj.SendKeyMsgKC(obj.KeyAction.EXDOWN, 0x5B); // L-Windows
|
||
obj.SendKeyMsgKC(obj.KeyAction.DOWN, 67); // C
|
||
obj.SendKeyMsgKC(obj.KeyAction.UP, 67); // C
|
||
obj.SendKeyMsgKC(obj.KeyAction.EXUP, 0x5B); // L-Windows
|
||
}
|
||
|
||
obj.SendTouchMsg1 = function (id, flags, x, y) {
|
||
if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.TOUCH) + obj.shortToStr(14) + String.fromCharCode(0x01, id) + obj.intToStr(flags) + obj.shortToStr(x) + obj.shortToStr(y));
|
||
}
|
||
|
||
obj.SendTouchMsg2 = function (id, flags) {
|
||
var msg = '';
|
||
var flags2;
|
||
var str = "TOUCHSEND: ";
|
||
for (var k in obj.TouchArray) {
|
||
if (k == id) { flags2 = flags; } else {
|
||
if (obj.TouchArray[k].f == 1) { flags2 = 0x00010000 | 0x00000002 | 0x00000004; obj.TouchArray[k].f = 3; str += "START" + k; } // POINTER_FLAG_DOWN
|
||
else if (obj.TouchArray[k].f == 2) { flags2 = 0x00040000; str += "STOP" + k; } // POINTER_FLAG_UP
|
||
else flags2 = 0x00000002 | 0x00000004 | 0x00020000; // POINTER_FLAG_UPDATE
|
||
}
|
||
msg += String.fromCharCode(k) + obj.intToStr(flags2) + obj.shortToStr(obj.TouchArray[k].x) + obj.shortToStr(obj.TouchArray[k].y);
|
||
if (obj.TouchArray[k].f == 2) delete obj.TouchArray[k];
|
||
}
|
||
if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.TOUCH) + obj.shortToStr(5 + msg.length) + String.fromCharCode(0x02) + msg);
|
||
if (Object.keys(obj.TouchArray).length == 0 && obj.touchtimer != null) { clearInterval(obj.touchtimer); obj.touchtimer = null; }
|
||
}
|
||
|
||
obj.SendMouseMsg = function (Action, event) {
|
||
if (obj.State != 3) return;
|
||
if (Action != null && obj.Canvas != null) {
|
||
if (!event) { var event = window.event; }
|
||
var ScaleFactorHeight = (obj.Canvas.canvas.height / obj.CanvasId.clientHeight);
|
||
var ScaleFactorWidth = (obj.Canvas.canvas.width / obj.CanvasId.clientWidth);
|
||
var Offsets = obj.GetPositionOfControl(obj.Canvas.canvas);
|
||
var X = ((event.pageX - Offsets[0]) * ScaleFactorWidth);
|
||
var Y = ((event.pageY - Offsets[1]) * ScaleFactorHeight);
|
||
|
||
if (X >= 0 && X <= obj.Canvas.canvas.width && Y >= 0 && Y <= obj.Canvas.canvas.height) {
|
||
var Button = 0;
|
||
var Delta = 0;
|
||
if (Action == obj.KeyAction.UP || Action == obj.KeyAction.DOWN) {
|
||
if (event.which) { ((event.which == 1) ? (Button = obj.MouseButton.LEFT) : ((event.which == 2) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); }
|
||
else if (event.button) { ((event.button == 0) ? (Button = obj.MouseButton.LEFT) : ((event.button == 1) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); }
|
||
}
|
||
else if (Action == obj.KeyAction.SCROLL) {
|
||
if (event.detail) { Delta = (-1 * (event.detail * 120)); } else if (event.wheelDelta) { Delta = (event.wheelDelta * 3); }
|
||
}
|
||
|
||
var MouseMsg = "";
|
||
if (Action == obj.KeyAction.DBLCLICK) {
|
||
MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0A, 0x00, 0x88, ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF));
|
||
} else if (Action == obj.KeyAction.SCROLL) {
|
||
MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0C, 0x00, 0x00, ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF), ((Delta / 256) & 0xFF), (Delta & 0xFF));
|
||
} else {
|
||
MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0A, 0x00, ((Action == obj.KeyAction.DOWN) ? Button : ((Button * 2) & 0xFF)), ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF));
|
||
}
|
||
|
||
if (obj.Action == obj.KeyAction.NONE) {
|
||
if (obj.Alternate == 0 || obj.ipad) { obj.send(MouseMsg); obj.Alternate = 1; } else { obj.Alternate = 0; }
|
||
} else {
|
||
obj.send(MouseMsg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.GetDisplayNumbers = function () { obj.send(String.fromCharCode(0x00, 0x0B, 0x00, 0x04)); } // Get Terminal display
|
||
obj.SetDisplay = function (number) { obj.send(String.fromCharCode(0x00, 0x0C, 0x00, 0x06, number >> 8, number & 0xFF)); } // Set Terminal display
|
||
obj.intToStr = function (x) { return String.fromCharCode((x >> 24) & 0xFF, (x >> 16) & 0xFF, (x >> 8) & 0xFF, x & 0xFF); }
|
||
obj.shortToStr = function (x) { return String.fromCharCode((x >> 8) & 0xFF, x & 0xFF); }
|
||
|
||
obj.onResize = function () {
|
||
if (obj.ScreenWidth == 0 || obj.ScreenHeight == 0) return;
|
||
if (obj.Canvas.canvas.width == obj.ScreenWidth && obj.Canvas.canvas.height == obj.ScreenHeight) return;
|
||
if (obj.FirstDraw) {
|
||
obj.Canvas.canvas.width = obj.ScreenWidth;
|
||
obj.Canvas.canvas.height = obj.ScreenHeight;
|
||
obj.Canvas.fillRect(0, 0, obj.ScreenWidth, obj.ScreenHeight);
|
||
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||
}
|
||
obj.FirstDraw = false;
|
||
//obj.Debug("onResize: " + obj.ScreenWidth + " x " + obj.ScreenHeight);
|
||
}
|
||
|
||
obj.xxMouseInputGrab = false;
|
||
obj.xxKeyInputGrab = false;
|
||
obj.xxMouseMove = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.NONE, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxMouseUp = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.UP, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxMouseDown = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.DOWN, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxMouseDblClick = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.DBLCLICK, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxDOMMouseScroll = function (e) { if (obj.State == 3) { obj.SendMouseMsg(obj.KeyAction.SCROLL, e); return false; } return true; }
|
||
obj.xxMouseWheel = function (e) { if (obj.State == 3) { obj.SendMouseMsg(obj.KeyAction.SCROLL, e); return false; } return true; }
|
||
obj.xxKeyUp = function (e) { if (obj.State == 3) { obj.SendKeyMsg(obj.KeyAction.UP, e); } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxKeyDown = function (e) { if (obj.State == 3) { obj.SendKeyMsg(obj.KeyAction.DOWN, e); } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
obj.xxKeyPress = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
|
||
// Key handlers
|
||
obj.handleKeys = function (e) { if (obj.stopInput == true || desktop.State != 3) return false; return obj.xxKeyPress(e); }
|
||
obj.handleKeyUp = function (e) {
|
||
if (obj.stopInput == true || desktop.State != 3) return false;
|
||
if (obj.firstUpKeys.length < 5) {
|
||
obj.firstUpKeys.push(e.keyCode);
|
||
if ((obj.firstUpKeys.length == 5)) { var j = obj.firstUpKeys.join(','); if ((j == '16,17,91,91,16') || (j == '16,17,18,91,92')) { obj.stopInput = true; } }
|
||
} return obj.xxKeyUp(e);
|
||
}
|
||
obj.handleKeyDown = function (e) { if (obj.stopInput == true || desktop.State != 3) return false; return obj.xxKeyDown(e); }
|
||
|
||
// Mouse handlers
|
||
obj.mousedblclick = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseDblClick(e); }
|
||
obj.mousedown = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseDown(e); }
|
||
obj.mouseup = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseUp(e); }
|
||
obj.mousemove = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseMove(e); }
|
||
obj.mousewheel = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseWheel(e); }
|
||
|
||
obj.xxMsTouchEvent = function (evt) {
|
||
if (evt.originalEvent.pointerType == 4) return; // If this is a mouse pointer, ignore this event. Touch & pen are ok.
|
||
if (evt.preventDefault) evt.preventDefault();
|
||
if (evt.stopPropagation) evt.stopPropagation();
|
||
if (evt.type == 'MSPointerDown' || evt.type == 'MSPointerMove' || evt.type == 'MSPointerUp') {
|
||
var flags = 0;
|
||
var id = evt.originalEvent.pointerId % 256;
|
||
var X = evt.offsetX * (Canvas.canvas.width / obj.CanvasId.clientWidth);
|
||
var Y = evt.offsetY * (Canvas.canvas.height / obj.CanvasId.clientHeight);
|
||
|
||
if (evt.type == 'MSPointerDown') flags = 0x00010000 | 0x00000002 | 0x00000004; // POINTER_FLAG_DOWN
|
||
else if (evt.type == 'MSPointerMove') {
|
||
//if (obj.TouchArray[id] && MuchTheSame(obj.TouchArray[id].x, X) && MuchTheSame(obj.TouchArray[id].y, Y)) return;
|
||
flags = 0x00020000 | 0x00000002 | 0x00000004; // POINTER_FLAG_UPDATE
|
||
}
|
||
else if (evt.type == 'MSPointerUp') flags = 0x00040000; // POINTER_FLAG_UP
|
||
|
||
if (!obj.TouchArray[id]) obj.TouchArray[id] = { x: X, y : Y };
|
||
obj.SendTouchMsg2(id, flags)
|
||
if (evt.type == 'MSPointerUp') delete obj.TouchArray[id];
|
||
} else {
|
||
alert(evt.type);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
obj.xxTouchStart = function (e) {
|
||
if (obj.State != 3) return;
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (obj.touchenabled == 0 || obj.touchenabled == 1) {
|
||
if (e.originalEvent.touches.length > 1) return;
|
||
var t = e.originalEvent.touches[0];
|
||
e.which = 1;
|
||
obj.LastX = e.pageX = t.pageX;
|
||
obj.LastY = e.pageY = t.pageY;
|
||
obj.SendMouseMsg(KeyAction.DOWN, e);
|
||
} else {
|
||
var Offsets = obj.GetPositionOfControl(Canvas.canvas);
|
||
for (var i in e.originalEvent.changedTouches) {
|
||
if (!e.originalEvent.changedTouches[i].identifier) continue;
|
||
var id = e.originalEvent.changedTouches[i].identifier % 256;
|
||
if (!obj.TouchArray[id]) { obj.TouchArray[id] = { x: (e.originalEvent.touches[i].pageX - Offsets[0]) * (Canvas.canvas.width / obj.CanvasId.clientWidth), y: (e.originalEvent.touches[i].pageY - Offsets[1]) * (Canvas.canvas.height / obj.CanvasId.clientHeight), f: 1 }; }
|
||
}
|
||
if (Object.keys(obj.TouchArray).length > 0 && touchtimer == null) { obj.touchtimer = setInterval(function () { obj.SendTouchMsg2(256, 0); }, 50); }
|
||
}
|
||
}
|
||
|
||
obj.xxTouchMove = function (e) {
|
||
if (obj.State != 3) return;
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (obj.touchenabled == 0 || obj.touchenabled == 1) {
|
||
if (e.originalEvent.touches.length > 1) return;
|
||
var t = e.originalEvent.touches[0];
|
||
e.which = 1;
|
||
obj.LastX = e.pageX = t.pageX;
|
||
obj.LastY = e.pageY = t.pageY;
|
||
obj.SendMouseMsg(obj.KeyAction.NONE, e);
|
||
} else {
|
||
var Offsets = obj.GetPositionOfControl(Canvas.canvas);
|
||
for (var i in e.originalEvent.changedTouches) {
|
||
if (!e.originalEvent.changedTouches[i].identifier) continue;
|
||
var id = e.originalEvent.changedTouches[i].identifier % 256;
|
||
if (obj.TouchArray[id]) {
|
||
obj.TouchArray[id].x = (e.originalEvent.touches[i].pageX - Offsets[0]) * (obj.Canvas.canvas.width / obj.CanvasId.clientWidth);
|
||
obj.TouchArray[id].y = (e.originalEvent.touches[i].pageY - Offsets[1]) * (obj.Canvas.canvas.height / obj.CanvasId.clientHeight);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.xxTouchEnd = function (e) {
|
||
if (obj.State != 3) return;
|
||
if (e.preventDefault) e.preventDefault();
|
||
if (obj.touchenabled == 0 || obj.touchenabled == 1) {
|
||
if (e.originalEvent.touches.length > 1) return;
|
||
e.which = 1;
|
||
e.pageX = LastX;
|
||
e.pageY = LastY;
|
||
obj.SendMouseMsg(KeyAction.UP, e);
|
||
} else {
|
||
for (var i in e.originalEvent.changedTouches) {
|
||
if (!e.originalEvent.changedTouches[i].identifier) continue;
|
||
var id = e.originalEvent.changedTouches[i].identifier % 256;
|
||
if (obj.TouchArray[id]) obj.TouchArray[id].f = 2;
|
||
}
|
||
}
|
||
}
|
||
|
||
obj.GrabMouseInput = function () {
|
||
if (obj.xxMouseInputGrab == true) return;
|
||
var c = obj.CanvasId;
|
||
c.onmousemove = obj.xxMouseMove;
|
||
c.onmouseup = obj.xxMouseUp;
|
||
c.onmousedown = obj.xxMouseDown;
|
||
c.touchstart = obj.xxTouchStart;
|
||
c.touchmove = obj.xxTouchMove;
|
||
c.touchend = obj.xxTouchEnd;
|
||
c.MSPointerDown = obj.xxMsTouchEvent;
|
||
c.MSPointerMove = obj.xxMsTouchEvent;
|
||
c.MSPointerUp = obj.xxMsTouchEvent;
|
||
if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
|
||
obj.xxMouseInputGrab = true;
|
||
}
|
||
|
||
obj.UnGrabMouseInput = function () {
|
||
if (obj.xxMouseInputGrab == false) return;
|
||
var c = obj.CanvasId;
|
||
c.onmousemove = null;
|
||
c.onmouseup = null;
|
||
c.onmousedown = null;
|
||
c.touchstart = null;
|
||
c.touchmove = null;
|
||
c.touchend = null;
|
||
c.MSPointerDown = null;
|
||
c.MSPointerMove = null;
|
||
c.MSPointerUp = null;
|
||
if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
|
||
obj.xxMouseInputGrab = false;
|
||
}
|
||
|
||
obj.GrabKeyInput = function () {
|
||
if (obj.xxKeyInputGrab == true) return;
|
||
document.onkeyup = obj.xxKeyUp;
|
||
document.onkeydown = obj.xxKeyDown;
|
||
document.onkeypress = obj.xxKeyPress;
|
||
obj.xxKeyInputGrab = true;
|
||
}
|
||
|
||
obj.UnGrabKeyInput = function () {
|
||
if (obj.xxKeyInputGrab == false) return;
|
||
document.onkeyup = null;
|
||
document.onkeydown = null;
|
||
document.onkeypress = null;
|
||
obj.xxKeyInputGrab = false;
|
||
}
|
||
|
||
obj.GetPositionOfControl = function (Control) {
|
||
var Position = Array(2);
|
||
Position[0] = Position[1] = 0;
|
||
while (Control) { Position[0] += Control.offsetLeft; Position[1] += Control.offsetTop; Control = Control.offsetParent; }
|
||
return Position;
|
||
}
|
||
|
||
obj.crotX = function (x, y) {
|
||
if (obj.rotation == 0) return x;
|
||
if (obj.rotation == 1) return y;
|
||
if (obj.rotation == 2) return obj.Canvas.canvas.width - x;
|
||
if (obj.rotation == 3) return obj.Canvas.canvas.height - y;
|
||
}
|
||
|
||
obj.crotY = function (x, y) {
|
||
if (obj.rotation == 0) return y;
|
||
if (obj.rotation == 1) return obj.Canvas.canvas.width - x;
|
||
if (obj.rotation == 2) return obj.Canvas.canvas.height - y;
|
||
if (obj.rotation == 3) return x;
|
||
}
|
||
|
||
obj.rotX = function (x, y) {
|
||
if (obj.rotation == 0 || obj.rotation == 1) return x;
|
||
if (obj.rotation == 2) return x - obj.Canvas.canvas.width;
|
||
if (obj.rotation == 3) return x - obj.Canvas.canvas.height;
|
||
}
|
||
|
||
obj.rotY = function (x, y) {
|
||
if (obj.rotation == 0 || obj.rotation == 3) return y;
|
||
if (obj.rotation == 1) return y - obj.Canvas.canvas.width;
|
||
if (obj.rotation == 2) return y - obj.Canvas.canvas.height;
|
||
}
|
||
|
||
obj.tcanvas = null;
|
||
obj.setRotation = function (x) {
|
||
while (x < 0) { x += 4; }
|
||
var newrotation = x % 4;
|
||
if (newrotation == obj.rotation) return true;
|
||
var rw = obj.Canvas.canvas.width;
|
||
var rh = obj.Canvas.canvas.height;
|
||
if (obj.rotation == 1 || obj.rotation == 3) { rw = obj.Canvas.canvas.height; rh = obj.Canvas.canvas.width; }
|
||
|
||
// Copy the canvas, put it back in the correct direction
|
||
if (obj.tcanvas == null) obj.tcanvas = document.createElement('canvas');
|
||
var tcanvasctx = obj.tcanvas.getContext('2d');
|
||
tcanvasctx.setTransform(1, 0, 0, 1, 0, 0);
|
||
tcanvasctx.canvas.width = rw;
|
||
tcanvasctx.canvas.height = rh;
|
||
tcanvasctx.rotate((obj.rotation * -90) * Math.PI / 180);
|
||
if (obj.rotation == 0) tcanvasctx.drawImage(obj.Canvas.canvas, 0, 0);
|
||
if (obj.rotation == 1) tcanvasctx.drawImage(obj.Canvas.canvas, -obj.Canvas.canvas.width, 0);
|
||
if (obj.rotation == 2) tcanvasctx.drawImage(obj.Canvas.canvas, -obj.Canvas.canvas.width, -obj.Canvas.canvas.height);
|
||
if (obj.rotation == 3) tcanvasctx.drawImage(obj.Canvas.canvas, 0, -obj.Canvas.canvas.height);
|
||
|
||
// Change the size and orientation and copy the canvas back into the rotation
|
||
if (obj.rotation == 0 || obj.rotation == 2) { obj.Canvas.canvas.height = rw; obj.Canvas.canvas.width = rh; }
|
||
if (obj.rotation == 1 || obj.rotation == 3) { obj.Canvas.canvas.height = rh; obj.Canvas.canvas.width = rw; }
|
||
obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
|
||
obj.Canvas.rotate((newrotation * 90) * Math.PI / 180);
|
||
obj.rotation = newrotation;
|
||
obj.Canvas.drawImage(obj.tcanvas, obj.rotX(0, 0), obj.rotY(0, 0));
|
||
|
||
obj.ScreenWidth = obj.Canvas.canvas.width;
|
||
obj.ScreenHeight = obj.Canvas.canvas.height;
|
||
if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
|
||
return true;
|
||
}
|
||
|
||
// Private method
|
||
obj.MuchTheSame = function (a, b) { return (Math.abs(a - b) < 4); }
|
||
obj.Debug = function (msg) { console.log(msg); }
|
||
obj.getIEVersion = function () { var r = -1; if (navigator.appName == 'Microsoft Internet Explorer') { var ua = navigator.userAgent; var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if (re.exec(ua) != null) r = parseFloat(RegExp.$1); } return r; }
|
||
obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
|
||
return obj;
|
||
}
|
||
var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c<a.length&&0==a[c];)c++;this.num=new Array(a.length-c+b);for(var d=0;d<a.length-c;d++)this.num[d]=a[d+c]}function j(a,b){this.totalCount=a,this.dataCount=b}function k(){this.buffer=[],this.length=0}function m(){return"undefined"!=typeof CanvasRenderingContext2D}function n(){var a=!1,b=navigator.userAgent;return/android/i.test(b)&&(a=!0,aMat=b.toString().match(/android ([0-9]\.[0-9])/i),aMat&&aMat[1]&&(a=parseFloat(aMat[1]))),a}function r(a,b){for(var c=1,e=s(a),f=0,g=l.length;g>=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=new Array(this.moduleCount);for(var e=0;e<this.moduleCount;e++)this.modules[d][e]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(a,c),this.typeNumber>=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f<this.modules.length;f++)for(var g=f*e,h=0;h<this.modules[f].length;h++){var i=h*e,j=this.modules[f][h];j&&(d.beginFill(0,100),d.moveTo(i,g),d.lineTo(i+e,g),d.lineTo(i+e,g+e),d.lineTo(i,g+e),d.endFill())}return d},setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(var b=8;b<this.moduleCount-8;b++)null==this.modules[6][b]&&(this.modules[6][b]=0==b%2)},setupPositionAdjustPattern:function(){for(var a=f.getPatternPosition(this.typeNumber),b=0;b<a.length;b++)for(var c=0;c<a.length;c++){var d=a[b],e=a[c];if(null==this.modules[d][e])for(var g=-2;2>=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g<a.length&&(j=1==(1&a[g]>>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h<d.length;h++){var i=d[h];g.put(i.mode,4),g.put(i.getLength(),f.getLengthInBits(i.mode,a)),i.write(g)}for(var l=0,h=0;h<e.length;h++)l+=e[h].dataCount;if(g.getLengthInBits()>8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j<b.length;j++){var k=b[j].dataCount,l=b[j].totalCount-k;d=Math.max(d,k),e=Math.max(e,l),g[j]=new Array(k);for(var m=0;m<g[j].length;m++)g[j][m]=255&a.buffer[m+c];c+=k;var n=f.getErrorCorrectPolynomial(l),o=new i(g[j],n.getLength()-1),p=o.mod(n);h[j]=new Array(n.getLength()-1);for(var m=0;m<h[j].length;m++){var q=m+p.getLength()-h[j].length;h[j][m]=q>=0?p.get(q):0}}for(var r=0,m=0;m<b.length;m++)r+=b[m].totalCount;for(var s=new Array(r),t=0,m=0;d>m;m++)for(var j=0;j<b.length;j++)m<g[j].length&&(s[t++]=g[j][m]);for(var m=0;e>m;m++)for(var j=0;j<b.length;j++)m<h[j].length&&(s[t++]=h[j][m]);return s};for(var c={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},d={L:1,M:0,Q:3,H:2},e={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},f={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var b=a<<10;f.getBCHDigit(b)-f.getBCHDigit(f.G15)>=0;)b^=f.G15<<f.getBCHDigit(b)-f.getBCHDigit(f.G15);return(a<<10|b)^f.G15_MASK},getBCHTypeNumber:function(a){for(var b=a<<12;f.getBCHDigit(b)-f.getBCHDigit(f.G18)>=0;)b^=f.G18<<f.getBCHDigit(b)-f.getBCHDigit(f.G18);return a<<12|b},getBCHDigit:function(a){for(var b=0;0!=a;)b++,a>>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<<h;for(var h=8;256>h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;c<this.getLength();c++)for(var d=0;d<a.getLength();d++)b[c+d]^=g.gexp(g.glog(this.get(c))+g.glog(a.get(d)));return new i(b,0)},mod:function(a){if(this.getLength()-a.getLength()<0)return this;for(var b=g.glog(this.get(0))-g.glog(a.get(0)),c=new Array(this.getLength()),d=0;d<this.getLength();d++)c[d]=this.get(d);for(var d=0;d<a.getLength();d++)c[d]^=g.gexp(g.glog(a.get(d))+b);return new i(c,0).mod(a)}},j.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],j.getRSBlocks=function(a,b){var c=j.getRsBlockTable(a,b);if(void 0==c)throw new Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+b);for(var d=c.length/3,e=[],f=0;d>f;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=['<table style="border:0;border-collapse:collapse;">'],h=0;d>h;h++){g.push("<tr>");for(var i=0;d>i;i++)g.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:'+e+"px;height:"+f+"px;background-color:"+(a.isDark(h,i)?b.colorDark:b.colorLight)+';"></td>');g.push("</tr>")}g.push("</table>"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();//Copyright 2014-2015 Google Inc. All rights reserved.
|
||
|
||
//Use of this source code is governed by a BSD-style
|
||
//license that can be found in the LICENSE file or at
|
||
//https://developers.google.com/open-source/licenses/bsd
|
||
|
||
/**
|
||
* @fileoverview The U2F api.
|
||
*/
|
||
'use strict';
|
||
if (!window.u2f) {
|
||
|
||
/**
|
||
* Namespace for the U2F api.
|
||
* @type {Object}
|
||
*/
|
||
var u2f = u2f || {};
|
||
|
||
/**
|
||
* FIDO U2F Javascript API Version
|
||
* @number
|
||
*/
|
||
var js_api_version;
|
||
|
||
/**
|
||
* The U2F extension id
|
||
* @const {string}
|
||
*/
|
||
// The Chrome packaged app extension ID.
|
||
// Uncomment this if you want to deploy a server instance that uses
|
||
// the package Chrome app and does not require installing the U2F Chrome extension.
|
||
u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
|
||
// The U2F Chrome extension ID.
|
||
// Uncomment this if you want to deploy a server instance that uses
|
||
// the U2F Chrome extension to authenticate.
|
||
// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
|
||
|
||
|
||
/**
|
||
* Message types for messsages to/from the extension
|
||
* @const
|
||
* @enum {string}
|
||
*/
|
||
u2f.MessageTypes = {
|
||
'U2F_REGISTER_REQUEST': 'u2f_register_request',
|
||
'U2F_REGISTER_RESPONSE': 'u2f_register_response',
|
||
'U2F_SIGN_REQUEST': 'u2f_sign_request',
|
||
'U2F_SIGN_RESPONSE': 'u2f_sign_response',
|
||
'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
|
||
'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
|
||
};
|
||
|
||
|
||
/**
|
||
* Response status codes
|
||
* @const
|
||
* @enum {number}
|
||
*/
|
||
u2f.ErrorCodes = {
|
||
'OK': 0,
|
||
'OTHER_ERROR': 1,
|
||
'BAD_REQUEST': 2,
|
||
'CONFIGURATION_UNSUPPORTED': 3,
|
||
'DEVICE_INELIGIBLE': 4,
|
||
'TIMEOUT': 5
|
||
};
|
||
|
||
|
||
/**
|
||
* A message for registration requests
|
||
* @typedef {{
|
||
* type: u2f.MessageTypes,
|
||
* appId: ?string,
|
||
* timeoutSeconds: ?number,
|
||
* requestId: ?number
|
||
* }}
|
||
*/
|
||
u2f.U2fRequest;
|
||
|
||
|
||
/**
|
||
* A message for registration responses
|
||
* @typedef {{
|
||
* type: u2f.MessageTypes,
|
||
* responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
|
||
* requestId: ?number
|
||
* }}
|
||
*/
|
||
u2f.U2fResponse;
|
||
|
||
|
||
/**
|
||
* An error object for responses
|
||
* @typedef {{
|
||
* errorCode: u2f.ErrorCodes,
|
||
* errorMessage: ?string
|
||
* }}
|
||
*/
|
||
u2f.Error;
|
||
|
||
/**
|
||
* Data object for a single sign request.
|
||
* @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
|
||
*/
|
||
u2f.Transport;
|
||
|
||
|
||
/**
|
||
* Data object for a single sign request.
|
||
* @typedef {Array<u2f.Transport>}
|
||
*/
|
||
u2f.Transports;
|
||
|
||
/**
|
||
* Data object for a single sign request.
|
||
* @typedef {{
|
||
* version: string,
|
||
* challenge: string,
|
||
* keyHandle: string,
|
||
* appId: string
|
||
* }}
|
||
*/
|
||
u2f.SignRequest;
|
||
|
||
|
||
/**
|
||
* Data object for a sign response.
|
||
* @typedef {{
|
||
* keyHandle: string,
|
||
* signatureData: string,
|
||
* clientData: string
|
||
* }}
|
||
*/
|
||
u2f.SignResponse;
|
||
|
||
|
||
/**
|
||
* Data object for a registration request.
|
||
* @typedef {{
|
||
* version: string,
|
||
* challenge: string
|
||
* }}
|
||
*/
|
||
u2f.RegisterRequest;
|
||
|
||
|
||
/**
|
||
* Data object for a registration response.
|
||
* @typedef {{
|
||
* version: string,
|
||
* keyHandle: string,
|
||
* transports: Transports,
|
||
* appId: string
|
||
* }}
|
||
*/
|
||
u2f.RegisterResponse;
|
||
|
||
|
||
/**
|
||
* Data object for a registered key.
|
||
* @typedef {{
|
||
* version: string,
|
||
* keyHandle: string,
|
||
* transports: ?Transports,
|
||
* appId: ?string
|
||
* }}
|
||
*/
|
||
u2f.RegisteredKey;
|
||
|
||
|
||
/**
|
||
* Data object for a get API register response.
|
||
* @typedef {{
|
||
* js_api_version: number
|
||
* }}
|
||
*/
|
||
u2f.GetJsApiVersionResponse;
|
||
|
||
|
||
//Low level MessagePort API support
|
||
|
||
/**
|
||
* Sets up a MessagePort to the U2F extension using the
|
||
* available mechanisms.
|
||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||
*/
|
||
u2f.getMessagePort = function (callback) {
|
||
if (typeof chrome != 'undefined' && chrome.runtime) {
|
||
// The actual message here does not matter, but we need to get a reply
|
||
// for the callback to run. Thus, send an empty signature request
|
||
// in order to get a failure response.
|
||
var msg = {
|
||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||
signRequests: []
|
||
};
|
||
chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function () {
|
||
if (!chrome.runtime.lastError) {
|
||
// We are on a whitelisted origin and can talk directly
|
||
// with the extension.
|
||
u2f.getChromeRuntimePort_(callback);
|
||
} else {
|
||
// chrome.runtime was available, but we couldn't message
|
||
// the extension directly, use iframe
|
||
u2f.getIframePort_(callback);
|
||
}
|
||
});
|
||
} else if (u2f.isAndroidChrome_()) {
|
||
u2f.getAuthenticatorPort_(callback);
|
||
} else if (u2f.isIosChrome_()) {
|
||
u2f.getIosPort_(callback);
|
||
} else {
|
||
// chrome.runtime was not available at all, which is normal
|
||
// when this origin doesn't have access to any extensions.
|
||
u2f.getIframePort_(callback);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Detect chrome running on android based on the browser's useragent.
|
||
* @private
|
||
*/
|
||
u2f.isAndroidChrome_ = function () {
|
||
var userAgent = navigator.userAgent;
|
||
return userAgent.indexOf('Chrome') != -1 &&
|
||
userAgent.indexOf('Android') != -1;
|
||
};
|
||
|
||
/**
|
||
* Detect chrome running on iOS based on the browser's platform.
|
||
* @private
|
||
*/
|
||
u2f.isIosChrome_ = function () {
|
||
var r = ["iPhone", "iPad", "iPod"];
|
||
for (var i in r) { if (navigator.platform == r[i]) { return true; } }
|
||
return false;
|
||
//return $.inArray(navigator.platform, ["iPhone", "iPad", "iPod"]) > -1;
|
||
};
|
||
|
||
/**
|
||
* Connects directly to the extension via chrome.runtime.connect.
|
||
* @param {function(u2f.WrappedChromeRuntimePort_)} callback
|
||
* @private
|
||
*/
|
||
u2f.getChromeRuntimePort_ = function (callback) {
|
||
var port = chrome.runtime.connect(u2f.EXTENSION_ID,
|
||
{ 'includeTlsChannelId': true });
|
||
setTimeout(function () {
|
||
callback(new u2f.WrappedChromeRuntimePort_(port));
|
||
}, 0);
|
||
};
|
||
|
||
/**
|
||
* Return a 'port' abstraction to the Authenticator app.
|
||
* @param {function(u2f.WrappedAuthenticatorPort_)} callback
|
||
* @private
|
||
*/
|
||
u2f.getAuthenticatorPort_ = function (callback) {
|
||
setTimeout(function () {
|
||
callback(new u2f.WrappedAuthenticatorPort_());
|
||
}, 0);
|
||
};
|
||
|
||
/**
|
||
* Return a 'port' abstraction to the iOS client app.
|
||
* @param {function(u2f.WrappedIosPort_)} callback
|
||
* @private
|
||
*/
|
||
u2f.getIosPort_ = function (callback) {
|
||
setTimeout(function () {
|
||
callback(new u2f.WrappedIosPort_());
|
||
}, 0);
|
||
};
|
||
|
||
/**
|
||
* A wrapper for chrome.runtime.Port that is compatible with MessagePort.
|
||
* @param {Port} port
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
u2f.WrappedChromeRuntimePort_ = function (port) {
|
||
this.port_ = port;
|
||
};
|
||
|
||
/**
|
||
* Format and return a sign request compliant with the JS API version supported by the extension.
|
||
* @param {Array<u2f.SignRequest>} signRequests
|
||
* @param {number} timeoutSeconds
|
||
* @param {number} reqId
|
||
* @return {Object}
|
||
*/
|
||
u2f.formatSignRequest_ =
|
||
function (appId, challenge, registeredKeys, timeoutSeconds, reqId) {
|
||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||
// Adapt request to the 1.0 JS API
|
||
var signRequests = [];
|
||
for (var i = 0; i < registeredKeys.length; i++) {
|
||
signRequests[i] = {
|
||
version: registeredKeys[i].version,
|
||
challenge: challenge,
|
||
keyHandle: registeredKeys[i].keyHandle,
|
||
appId: appId
|
||
};
|
||
}
|
||
return {
|
||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||
signRequests: signRequests,
|
||
timeoutSeconds: timeoutSeconds,
|
||
requestId: reqId
|
||
};
|
||
}
|
||
// JS 1.1 API
|
||
return {
|
||
type: u2f.MessageTypes.U2F_SIGN_REQUEST,
|
||
appId: appId,
|
||
challenge: challenge,
|
||
registeredKeys: registeredKeys,
|
||
timeoutSeconds: timeoutSeconds,
|
||
requestId: reqId
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Format and return a register request compliant with the JS API version supported by the extension..
|
||
* @param {Array<u2f.SignRequest>} signRequests
|
||
* @param {Array<u2f.RegisterRequest>} signRequests
|
||
* @param {number} timeoutSeconds
|
||
* @param {number} reqId
|
||
* @return {Object}
|
||
*/
|
||
u2f.formatRegisterRequest_ =
|
||
function (appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
|
||
if (js_api_version === undefined || js_api_version < 1.1) {
|
||
// Adapt request to the 1.0 JS API
|
||
for (var i = 0; i < registerRequests.length; i++) {
|
||
registerRequests[i].appId = appId;
|
||
}
|
||
var signRequests = [];
|
||
for (var i = 0; i < registeredKeys.length; i++) {
|
||
signRequests[i] = {
|
||
version: registeredKeys[i].version,
|
||
challenge: registerRequests[0],
|
||
keyHandle: registeredKeys[i].keyHandle,
|
||
appId: appId
|
||
};
|
||
}
|
||
return {
|
||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||
signRequests: signRequests,
|
||
registerRequests: registerRequests,
|
||
timeoutSeconds: timeoutSeconds,
|
||
requestId: reqId
|
||
};
|
||
}
|
||
// JS 1.1 API
|
||
return {
|
||
type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
|
||
appId: appId,
|
||
registerRequests: registerRequests,
|
||
registeredKeys: registeredKeys,
|
||
timeoutSeconds: timeoutSeconds,
|
||
requestId: reqId
|
||
};
|
||
};
|
||
|
||
|
||
/**
|
||
* Posts a message on the underlying channel.
|
||
* @param {Object} message
|
||
*/
|
||
u2f.WrappedChromeRuntimePort_.prototype.postMessage = function (message) {
|
||
this.port_.postMessage(message);
|
||
};
|
||
|
||
|
||
/**
|
||
* Emulates the HTML 5 addEventListener interface. Works only for the
|
||
* onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
|
||
* @param {string} eventName
|
||
* @param {function({data: Object})} handler
|
||
*/
|
||
u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
|
||
function (eventName, handler) {
|
||
var name = eventName.toLowerCase();
|
||
if (name == 'message' || name == 'onmessage') {
|
||
this.port_.onMessage.addListener(function (message) {
|
||
// Emulate a minimal MessageEvent object
|
||
handler({ 'data': message });
|
||
});
|
||
} else {
|
||
console.error('WrappedChromeRuntimePort only supports onMessage');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Wrap the Authenticator app with a MessagePort interface.
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_ = function () {
|
||
this.requestId_ = -1;
|
||
this.requestObject_ = null;
|
||
}
|
||
|
||
/**
|
||
* Launch the Authenticator intent.
|
||
* @param {Object} message
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_.prototype.postMessage = function (message) {
|
||
var intentUrl =
|
||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
|
||
';S.request=' + encodeURIComponent(JSON.stringify(message)) +
|
||
';end';
|
||
document.location = intentUrl;
|
||
};
|
||
|
||
/**
|
||
* Tells what type of port this is.
|
||
* @return {String} port type
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_.prototype.getPortType = function () {
|
||
return "WrappedAuthenticatorPort_";
|
||
};
|
||
|
||
|
||
/**
|
||
* Emulates the HTML 5 addEventListener interface.
|
||
* @param {string} eventName
|
||
* @param {function({data: Object})} handler
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function (eventName, handler) {
|
||
var name = eventName.toLowerCase();
|
||
if (name == 'message') {
|
||
var self = this;
|
||
/* Register a callback to that executes when
|
||
* chrome injects the response. */
|
||
window.addEventListener(
|
||
'message', self.onRequestUpdate_.bind(self, handler), false);
|
||
} else {
|
||
console.error('WrappedAuthenticatorPort only supports message');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Callback invoked when a response is received from the Authenticator.
|
||
* @param function({data: Object}) callback
|
||
* @param {Object} message message Object
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
|
||
function (callback, message) {
|
||
var messageObject = JSON.parse(message.data);
|
||
var intentUrl = messageObject['intentURL'];
|
||
|
||
var errorCode = messageObject['errorCode'];
|
||
var responseObject = null;
|
||
if (messageObject.hasOwnProperty('data')) {
|
||
responseObject = /** @type {Object} */ (
|
||
JSON.parse(messageObject['data']));
|
||
}
|
||
|
||
callback({ 'data': responseObject });
|
||
};
|
||
|
||
/**
|
||
* Base URL for intents to Authenticator.
|
||
* @const
|
||
* @private
|
||
*/
|
||
u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
|
||
'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
|
||
|
||
/**
|
||
* Wrap the iOS client app with a MessagePort interface.
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
u2f.WrappedIosPort_ = function () { };
|
||
|
||
/**
|
||
* Launch the iOS client app request
|
||
* @param {Object} message
|
||
*/
|
||
u2f.WrappedIosPort_.prototype.postMessage = function (message) {
|
||
var str = JSON.stringify(message);
|
||
var url = "u2f://auth?" + encodeURI(str);
|
||
location.replace(url);
|
||
};
|
||
|
||
/**
|
||
* Tells what type of port this is.
|
||
* @return {String} port type
|
||
*/
|
||
u2f.WrappedIosPort_.prototype.getPortType = function () {
|
||
return "WrappedIosPort_";
|
||
};
|
||
|
||
/**
|
||
* Emulates the HTML 5 addEventListener interface.
|
||
* @param {string} eventName
|
||
* @param {function({data: Object})} handler
|
||
*/
|
||
u2f.WrappedIosPort_.prototype.addEventListener = function (eventName, handler) {
|
||
var name = eventName.toLowerCase();
|
||
if (name !== 'message') {
|
||
console.error('WrappedIosPort only supports message');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Sets up an embedded trampoline iframe, sourced from the extension.
|
||
* @param {function(MessagePort)} callback
|
||
* @private
|
||
*/
|
||
u2f.getIframePort_ = function (callback) {
|
||
// Create the iframe
|
||
var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
|
||
var iframe = document.createElement('iframe');
|
||
iframe.src = iframeOrigin + '/u2f-comms.html';
|
||
iframe.setAttribute('style', 'display:none');
|
||
document.body.appendChild(iframe);
|
||
|
||
var channel = new MessageChannel();
|
||
var ready = function (message) {
|
||
if (message.data == 'ready') {
|
||
channel.port1.removeEventListener('message', ready);
|
||
callback(channel.port1);
|
||
} else {
|
||
console.error('First event on iframe port was not "ready"');
|
||
}
|
||
};
|
||
channel.port1.addEventListener('message', ready);
|
||
channel.port1.start();
|
||
|
||
iframe.addEventListener('load', function () {
|
||
// Deliver the port to the iframe and initialize
|
||
iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
|
||
});
|
||
};
|
||
|
||
|
||
//High-level JS API
|
||
|
||
/**
|
||
* Default extension response timeout in seconds.
|
||
* @const
|
||
*/
|
||
u2f.EXTENSION_TIMEOUT_SEC = 30;
|
||
|
||
/**
|
||
* A singleton instance for a MessagePort to the extension.
|
||
* @type {MessagePort|u2f.WrappedChromeRuntimePort_}
|
||
* @private
|
||
*/
|
||
u2f.port_ = null;
|
||
|
||
/**
|
||
* Callbacks waiting for a port
|
||
* @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
|
||
* @private
|
||
*/
|
||
u2f.waitingForPort_ = [];
|
||
|
||
/**
|
||
* A counter for requestIds.
|
||
* @type {number}
|
||
* @private
|
||
*/
|
||
u2f.reqCounter_ = 0;
|
||
|
||
/**
|
||
* A map from requestIds to client callbacks
|
||
* @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
|
||
* |function((u2f.Error|u2f.SignResponse)))>}
|
||
* @private
|
||
*/
|
||
u2f.callbackMap_ = {};
|
||
|
||
/**
|
||
* Creates or retrieves the MessagePort singleton to use.
|
||
* @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
|
||
* @private
|
||
*/
|
||
u2f.getPortSingleton_ = function (callback) {
|
||
if (u2f.port_) {
|
||
callback(u2f.port_);
|
||
} else {
|
||
if (u2f.waitingForPort_.length == 0) {
|
||
u2f.getMessagePort(function (port) {
|
||
u2f.port_ = port;
|
||
u2f.port_.addEventListener('message',
|
||
/** @type {function(Event)} */ (u2f.responseHandler_));
|
||
|
||
// Careful, here be async callbacks. Maybe.
|
||
while (u2f.waitingForPort_.length)
|
||
u2f.waitingForPort_.shift()(u2f.port_);
|
||
});
|
||
}
|
||
u2f.waitingForPort_.push(callback);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Handles response messages from the extension.
|
||
* @param {MessageEvent.<u2f.Response>} message
|
||
* @private
|
||
*/
|
||
u2f.responseHandler_ = function (message) {
|
||
var response = message.data;
|
||
var reqId = response['requestId'];
|
||
if (!reqId || !u2f.callbackMap_[reqId]) {
|
||
console.error('Unknown or missing requestId in response.');
|
||
return;
|
||
}
|
||
var cb = u2f.callbackMap_[reqId];
|
||
delete u2f.callbackMap_[reqId];
|
||
cb(response['responseData']);
|
||
};
|
||
|
||
/**
|
||
* Dispatches an array of sign requests to available U2F tokens.
|
||
* If the JS API version supported by the extension is unknown, it first sends a
|
||
* message to the extension to find out the supported API version and then it sends
|
||
* the sign request.
|
||
* @param {string=} appId
|
||
* @param {string=} challenge
|
||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||
* @param {number=} opt_timeoutSeconds
|
||
*/
|
||
u2f.sign = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||
if (js_api_version === undefined) {
|
||
// Send a message to get the extension to JS API version, then send the actual sign request.
|
||
u2f.getApiVersion(
|
||
function (response) {
|
||
js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
|
||
//console.log("Extension JS API Version: ", js_api_version);
|
||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||
});
|
||
} else {
|
||
// We know the JS API version. Send the actual sign request in the supported API version.
|
||
u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Dispatches an array of sign requests to available U2F tokens.
|
||
* @param {string=} appId
|
||
* @param {string=} challenge
|
||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||
* @param {function((u2f.Error|u2f.SignResponse))} callback
|
||
* @param {number=} opt_timeoutSeconds
|
||
*/
|
||
u2f.sendSignRequest = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
|
||
u2f.getPortSingleton_(function (port) {
|
||
var reqId = ++u2f.reqCounter_;
|
||
u2f.callbackMap_[reqId] = callback;
|
||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||
var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
|
||
port.postMessage(req);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Dispatches register requests to available U2F tokens. An array of sign
|
||
* requests identifies already registered tokens.
|
||
* If the JS API version supported by the extension is unknown, it first sends a
|
||
* message to the extension to find out the supported API version and then it sends
|
||
* the register request.
|
||
* @param {string=} appId
|
||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||
* @param {number=} opt_timeoutSeconds
|
||
*/
|
||
u2f.register = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||
if (js_api_version === undefined) {
|
||
// Send a message to get the extension to JS API version, then send the actual register request.
|
||
u2f.getApiVersion(
|
||
function (response) {
|
||
js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
|
||
//console.log("Extension JS API Version: ", js_api_version);
|
||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||
callback, opt_timeoutSeconds);
|
||
});
|
||
} else {
|
||
// We know the JS API version. Send the actual register request in the supported API version.
|
||
u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
|
||
callback, opt_timeoutSeconds);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Dispatches register requests to available U2F tokens. An array of sign
|
||
* requests identifies already registered tokens.
|
||
* @param {string=} appId
|
||
* @param {Array<u2f.RegisterRequest>} registerRequests
|
||
* @param {Array<u2f.RegisteredKey>} registeredKeys
|
||
* @param {function((u2f.Error|u2f.RegisterResponse))} callback
|
||
* @param {number=} opt_timeoutSeconds
|
||
*/
|
||
u2f.sendRegisterRequest = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
|
||
u2f.getPortSingleton_(function (port) {
|
||
var reqId = ++u2f.reqCounter_;
|
||
u2f.callbackMap_[reqId] = callback;
|
||
var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
|
||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
|
||
var req = u2f.formatRegisterRequest_(
|
||
appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
|
||
port.postMessage(req);
|
||
});
|
||
};
|
||
|
||
|
||
/**
|
||
* Dispatches a message to the extension to find out the supported
|
||
* JS API version.
|
||
* If the user is on a mobile phone and is thus using Google Authenticator instead
|
||
* of the Chrome extension, don't send the request and simply return 0.
|
||
* @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
|
||
* @param {number=} opt_timeoutSeconds
|
||
*/
|
||
u2f.getApiVersion = function (callback, opt_timeoutSeconds) {
|
||
u2f.getPortSingleton_(function (port) {
|
||
// If we are using Android Google Authenticator or iOS client app,
|
||
// do not fire an intent to ask which JS API version to use.
|
||
if (port.getPortType) {
|
||
var apiVersion;
|
||
switch (port.getPortType()) {
|
||
case 'WrappedIosPort_':
|
||
case 'WrappedAuthenticatorPort_':
|
||
apiVersion = 1.1;
|
||
break;
|
||
|
||
default:
|
||
apiVersion = 0;
|
||
break;
|
||
}
|
||
callback({ 'js_api_version': apiVersion });
|
||
return;
|
||
}
|
||
var reqId = ++u2f.reqCounter_;
|
||
u2f.callbackMap_[reqId] = callback;
|
||
var req = {
|
||
type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
|
||
timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
|
||
opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
|
||
requestId: reqId
|
||
};
|
||
port.postMessage(req);
|
||
});
|
||
};
|
||
|
||
}
|
||
'use strict';
|
||
var args;
|
||
var autoReconnect = true;
|
||
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
|
||
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
|
||
var sort = 0;
|
||
var searchFocus = 0;
|
||
var mapSearchFocus = 0;
|
||
var userSearchFocus = 0;
|
||
var consoleFocus = 0;
|
||
var showRealNames = false;
|
||
var meshserver = null;
|
||
var meshes = {};
|
||
var meshcount = 0;
|
||
var nodes = null;
|
||
var filetree = {};
|
||
var userinfo = null;
|
||
var serverinfo = null;
|
||
var events = [];
|
||
var users = null;
|
||
var wssessions = null;
|
||
var nodeShortIdent = 0;
|
||
var desktop;
|
||
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, localkeymap: false };
|
||
var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
|
||
var terminal;
|
||
var files;
|
||
var debugLevel = parseInt("{{{debuglevel}}}");
|
||
var features = parseInt("{{{features}}}");
|
||
var sessionTime = parseInt("{{{sessiontime}}}");
|
||
var domain = "{{{domain}}}";
|
||
var domainUrl = "{{{domainurl}}}";
|
||
var authCookie = "{{{authCookie}}}";
|
||
var authCookieRenewTimer = null;
|
||
var multiDesktop = {};
|
||
var multiDesktopFilter = null;
|
||
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
|
||
var amtScanResults = null;
|
||
var debugmode = 0;
|
||
var clickOnce = (((features & 256) != 0) && detectClickOnce());
|
||
var attemptWebRTC = ((features & 128) != 0);
|
||
var webPageFullScreen = getstore('webPageFullScreen', true);
|
||
if (webPageFullScreen == 'false') { webPageFullScreen = false; }
|
||
if (webPageFullScreen == 'true') { webPageFullScreen = true; }
|
||
var passRequirements = "{{{passRequirements}}}";
|
||
if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
|
||
|
||
function startup() {
|
||
if ((features & 32) == 0) {
|
||
// Guard against other site's top frames (web bugs).
|
||
var loc = null;
|
||
try { loc = top.location.toString().toLowerCase(); } catch (e) { }
|
||
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
|
||
}
|
||
|
||
// Check if we are in debug mode
|
||
args = parseUriArgs();
|
||
debugmode = args.debug;
|
||
if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
|
||
QV('p13AutoConnect', debugmode); // Files
|
||
QV('autoconnectbutton2', debugmode); // Terminal
|
||
QV('autoconnectbutton1', debugmode); // Desktop
|
||
//QV('DeskClip', debugmode); // Clipboard feature, not completed so show in in debug mode only.
|
||
|
||
toggleFullScreen();
|
||
|
||
// Setup page visuals
|
||
if (args.hide) {
|
||
var hide = parseInt(args.hide);
|
||
QV('masthead', !(hide & 1));
|
||
QV('topbarmaster', !(hide & 2));
|
||
QV('footer', !(hide & 4));
|
||
QV('p10title', !(hide & 8));
|
||
QV('p11title', !(hide & 8));
|
||
QV('p12title', !(hide & 8));
|
||
QV('p13title', !(hide & 8));
|
||
QV('p14title', !(hide & 8));
|
||
QV('p15title', !(hide & 8));
|
||
QV('p16title', !(hide & 8));
|
||
if (hide & 16) {
|
||
QV('page_leftbar', false);
|
||
QS('page_content').left = '0px';
|
||
}
|
||
}
|
||
|
||
// We are looking at a single device, remove all the back buttons
|
||
if ('{{currentNode}}' != '') {
|
||
QV('p10BackButton', false);
|
||
QV('p11BackButton', false);
|
||
QV('p12BackButton', false);
|
||
QV('p13BackButton', false);
|
||
QV('p14BackButton', false);
|
||
QV('p15BackButton', false);
|
||
QV('p16BackButton', false);
|
||
}
|
||
p1updateInfo();
|
||
|
||
// Setup the context menu
|
||
document.onclick = function (e) { hideContextMenu(); }
|
||
document.onkeypress = ondockeypress;
|
||
document.onkeydown = ondockeydown;
|
||
document.onkeyup = ondockeyup;
|
||
window.onresize = function () { masterUpdate(512); }
|
||
masterUpdate(512);
|
||
|
||
// Connect to the mesh server
|
||
meshserver = MeshServerCreateControl(domainUrl, authCookie);
|
||
meshserver.onStateChanged = onStateChanged;
|
||
meshserver.onMessage = onMessage;
|
||
meshserver.Start();
|
||
|
||
// Setup page controls
|
||
Q('sortselect').selectedIndex = sort = getstore("sort", 0);
|
||
Q('sizeselect').selectedIndex = getstore("viewsize", 1);
|
||
Q('SearchInput').value = getstore("search", "");
|
||
showRealNames = (getstore("showRealNames", 0) == 1);
|
||
Q('RealNameCheckBox').checked = showRealNames;
|
||
Q('viewselect').value = getstore("deviceView", 1);
|
||
Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
|
||
|
||
// Display the page devices
|
||
masterUpdate(3)
|
||
for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
|
||
Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
|
||
|
||
|
||
// Setup upload drag & drop
|
||
Q('p5filetable').addEventListener("drop", p5fileDragDrop, false);
|
||
Q('p5filetable').addEventListener("dragover", p5fileDragOver, false);
|
||
Q('p5filetable').addEventListener("dragleave", p5fileDragLeave, false);
|
||
//Q('p5fileCatchAllInput').addEventListener("drop", p5fileDragDrop, false);
|
||
//Q('p5fileCatchAllInput').addEventListener("dragover", p5fileDragOver, false);
|
||
//Q('p5fileCatchAllInput').addEventListener("dragleave", p5fileDragLeave, false);
|
||
|
||
// Setup upload drag & drop
|
||
Q('p13filetable').addEventListener("drop", p13fileDragDrop, false);
|
||
Q('p13filetable').addEventListener("dragover", p13fileDragOver, false);
|
||
Q('p13filetable').addEventListener("dragleave", p13fileDragLeave, false);
|
||
|
||
// Timeline update interval
|
||
setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
|
||
|
||
// Load desktop settings
|
||
var t = localStorage.getItem('desktopsettings');
|
||
if (t != null) { desktopsettings = JSON.parse(t); }
|
||
t = localStorage.getItem('multidesktopsettings');
|
||
if (t != null) { multidesktopsettings = JSON.parse(t); }
|
||
applyDesktopSettings();
|
||
|
||
// Terminal special keys
|
||
var x = '';
|
||
for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
|
||
QH('specialkeylist', x);
|
||
|
||
// Setup server stats panel
|
||
setupServerStats();
|
||
}
|
||
|
||
// Toggle the web page to full screen
|
||
function toggleFullScreen(toggle) {
|
||
if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
|
||
var hide = 0;
|
||
if (args.hide) { hide = parseInt(args.hide); }
|
||
if (webPageFullScreen == false) {
|
||
QS('container').width = '960px';
|
||
QS('container')['border-right'] = '1px solid #b7b7b7';
|
||
QS('container')['border-left'] = '1px solid #b7b7b7';
|
||
QS('container')['min-width'] = '960px';
|
||
QS('container')['overflow'] = '';
|
||
QS('column_l').width = '930px';
|
||
QS('column_l').height = '';
|
||
QS('column_l')['margin-left'] = '';
|
||
QS('column_l')["overflow-y"] = '';
|
||
QS('column_l')["max-height"] = (xxcurrentView >= 10) ? 'calc(100vh - 159px)' : 'calc(100vh - 135px)';
|
||
QS('container').position = '';
|
||
QS('page_content').position = '';
|
||
QV('MainMenuSpan', true);
|
||
QV('UserDummyMenuSpan', false);
|
||
QV('page_leftbar', false);
|
||
} else {
|
||
QS('container').position = 'absolute';
|
||
QS('container').width = '100%';
|
||
QS('container').top = '0px';
|
||
QS('container').bottom = '0px';
|
||
QS('container')['border-right'] = '0';
|
||
QS('container')['border-left'] = '0';
|
||
QS('container')['min-width'] = '700px';
|
||
QS('container')['overflow'] = 'hidden';
|
||
QS('page_content').position = 'absolute';
|
||
QS('page_content').top = '66px';
|
||
QS('page_content').left = (hide & 16)?'0px':'90px';
|
||
QS('page_content').right = '0px';
|
||
QS('page_content').bottom = '0px';
|
||
QS('column_l').height = 'calc(100vh - 135px)';
|
||
QS('column_l').width = 'calc(100% - 30px)';
|
||
QS('column_l')["overflow-y"] = 'auto';
|
||
QS('column_l')["max-height"] = 'calc(100vh - 135px)';
|
||
QV('MainMenuSpan', false);
|
||
QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
|
||
QV('page_leftbar', !(hide & 16));
|
||
}
|
||
//center();
|
||
masterUpdate(512);
|
||
QV('body', true);
|
||
}
|
||
|
||
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
||
function reload() { window.location.href = window.location.href; }
|
||
|
||
function onStateChanged(server, state, prevState, errorCode) {
|
||
if (state == 0) {
|
||
// Control web socket disconnected
|
||
setDialogMode(0); // Close any dialog boxes if present
|
||
go(0); // Go to disconnection panel
|
||
|
||
// Clean up
|
||
powerTimeline = null;
|
||
powerTimelineReq = null;
|
||
powerTimelineNode = null;
|
||
powerTimelineUpdate = null;
|
||
deleteAllNotifications(); // Close and clear notifications if present
|
||
hideContextMenu(); // Hide the context menu if present
|
||
QV('verifyEmailId2', false);
|
||
QV('logoutControl', false);
|
||
if (errorCode == 'noauth') { QH('p0span', 'Unable to perform authentication'); return; }
|
||
if (prevState == 2) { if (autoReconnect) { setTimeout(serverPoll, 5000); } } else { QH('p0span', 'Unable to connect web socket'); }
|
||
if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
|
||
} else if (state == 2) {
|
||
// Fetch list of meshes, nodes, files
|
||
meshserver.send({ action: 'meshes' });
|
||
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
||
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
||
go(1);
|
||
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
||
}
|
||
}
|
||
|
||
// Poll the server, if it responds, refresh the page.
|
||
function serverPoll() {
|
||
var xdr = null;
|
||
try { xdr = new XDomainRequest(); } catch (e) { }
|
||
if (!xdr) xdr = new XMLHttpRequest();
|
||
xdr.open("HEAD", window.location.href);
|
||
xdr.timeout = 15000;
|
||
xdr.onload = function () { reload(); };
|
||
xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
|
||
xdr.send();
|
||
}
|
||
|
||
// Return true if this browser supports clickonce
|
||
function detectClickOnce() {
|
||
for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == "application/x-ms-application") { return true; } }
|
||
var userAgent = window.navigator.userAgent.toUpperCase();
|
||
return (userAgent.indexOf('.NET CLR 3.5') >= 0) || (userAgent.indexOf('(WINDOWS NT ') >= 0);
|
||
}
|
||
|
||
function updateSiteAdmin() {
|
||
var noServerBackup = "{{{noServerBackup}}}";
|
||
var siteRights = userinfo.siteadmin;
|
||
if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
|
||
|
||
// Update account actions
|
||
QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0)); // Hide Account Security if in single user mode, domain authentication to 2 factor auth not supported.
|
||
QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
|
||
QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
|
||
QV('p2ServerActions', siteRights & 21);
|
||
QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
|
||
QV('MainMenuMyServer', siteRights & 21);
|
||
QV('p2ServerActionsBackup', siteRights & 1);
|
||
QV('p2ServerActionsRestore', siteRights & 4);
|
||
QV('p2ServerActionsVersion', siteRights & 16);
|
||
QV('MainMenuMyFiles', siteRights & 8);
|
||
QV('LeftMenuMyFiles', siteRights & 8);
|
||
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
|
||
if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
|
||
|
||
// Update user management state
|
||
if ((userinfo.siteadmin & 2) != 0)
|
||
{
|
||
// We are user administrator
|
||
if (users == null) { meshserver.send({ action: 'users' }); }
|
||
if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
|
||
} else {
|
||
// We are not user administrator
|
||
users = null;
|
||
wssessions = null;
|
||
updateUsers();
|
||
if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
|
||
}
|
||
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
|
||
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
|
||
if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
|
||
if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
|
||
|
||
// If we are site administrator, register to get server statistics
|
||
if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
|
||
}
|
||
|
||
// To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
|
||
var updateNaggleTimer = null;
|
||
var updateNaggleFlags = 0;
|
||
function masterUpdate(flags) {
|
||
updateNaggleFlags |= flags;
|
||
if (updateNaggleTimer == null) {
|
||
updateNaggleTimer = setTimeout(function () {
|
||
if (updateNaggleFlags & 512) { center(); }
|
||
if (updateNaggleFlags & 1) { onSearchInputChanged(); }
|
||
if (updateNaggleFlags & 2) { onSortSelectChange(true); }
|
||
if (updateNaggleFlags & 128) { updateMeshes(); }
|
||
if (updateNaggleFlags & 4) { updateDevices(); }
|
||
if (updateNaggleFlags & 8) { drawNotifications(); }
|
||
if (updateNaggleFlags & 16) { updateMapMarkers(); }
|
||
if (updateNaggleFlags & 32) { eventsUpdate(); }
|
||
if (updateNaggleFlags & 64) { refreshMap(false, true); }
|
||
if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
|
||
if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
|
||
if (updateNaggleFlags & 2048) { userEventsUpdate(); }
|
||
updateNaggleTimer = null;
|
||
updateNaggleFlags = 0;
|
||
}, 150);
|
||
}
|
||
}
|
||
|
||
function updateSelf() {
|
||
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
|
||
QV('manageOtp', (userinfo.otpsecret == 1) || (userinfo.otphkeys > 0));
|
||
QV('authAppSetupCheck', userinfo.otpsecret == 1);
|
||
QV('authKeySetupCheck', userinfo.otphkeys > 0);
|
||
QV('authCodesSetupCheck', userinfo.otpkeys > 0);
|
||
|
||
if (typeof userinfo.passchange == 'number') {
|
||
if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
|
||
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', ' - Reset on next login.'); }
|
||
else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 60) + ' minute' + addLetterS(Math.floor(seconds / 60)) + '.'); }
|
||
else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 3600) + ' hour' + addLetterS(Math.floor(seconds / 3600)) + '.'); }
|
||
else { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 86400) + ' day' + addLetterS(Math.floor(seconds / 86400)) + '.'); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function addLetterS(x) { return (x > 1) ? 's' : ''; }
|
||
|
||
function onMessage(server, message) {
|
||
switch (message.action) {
|
||
case 'serverstats': {
|
||
updateServerStats(message);
|
||
break;
|
||
}
|
||
case 'authcookie': {
|
||
// Got an authentication cookie refresh
|
||
authCookie = message.cookie;
|
||
break;
|
||
}
|
||
case 'serverinfo': {
|
||
serverinfo = message.serverinfo;
|
||
break;
|
||
}
|
||
case 'userinfo': {
|
||
userinfo = message.userinfo;
|
||
updateSiteAdmin();
|
||
updateSelf();
|
||
break;
|
||
}
|
||
case 'users': {
|
||
users = {};
|
||
for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
|
||
updateUsers();
|
||
break;
|
||
}
|
||
case 'wssessioncount': {
|
||
wssessions = message.wssessions;
|
||
updateUsers();
|
||
break;
|
||
}
|
||
case 'meshes': {
|
||
meshes = {};
|
||
for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
|
||
masterUpdate(4 + 128);
|
||
break;
|
||
}
|
||
case 'files': {
|
||
filetree = setupBackPointers(message.filetree);
|
||
updateFiles();
|
||
d3updatefiles();
|
||
break;
|
||
}
|
||
case 'nodes': {
|
||
nodes = [];
|
||
for (var m in message.nodes) {
|
||
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
|
||
for (var n in message.nodes[m]) {
|
||
if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
|
||
message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
|
||
if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
|
||
message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
|
||
message.nodes[m][n].meshid = m;
|
||
message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
|
||
message.nodes[m][n].desc = message.nodes[m][n].desc;
|
||
message.nodes[m][n].ip = message.nodes[m][n].ip;
|
||
if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
|
||
message.nodes[m][n].ident = ++nodeShortIdent;
|
||
nodes.push(message.nodes[m][n]);
|
||
}
|
||
}
|
||
masterUpdate(1 | 2 | 4 | 64);
|
||
|
||
if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } }
|
||
if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',parseInt('{{viewmode}}'));}
|
||
break;
|
||
}
|
||
case 'powertimeline': {
|
||
if (message.nodeid != powerTimelineReq) break;
|
||
powerTimelineNode = message.nodeid;
|
||
powerTimeline = message.timeline;
|
||
powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
|
||
for (var i in powerTimeline) { if (i % 2 == 1) { powerTimeline[i] = powerTimeline[i] * 1000; } } // Decompress time
|
||
if (currentNode._id == message.nodeid) { masterUpdate(256); }
|
||
break;
|
||
}
|
||
case 'lastconnect': {
|
||
var node = getNodeFromId(message.nodeid);
|
||
if (node != null) {
|
||
node.lastconnect = message.time;
|
||
node.lastaddr = message.addr;
|
||
if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
|
||
QH('MainComputerState', '<span style=font-size:12px>Last seen:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>');
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'msg': {
|
||
// Check if this is a message from a node
|
||
if (message.nodeid != null) {
|
||
var index = -1;
|
||
if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } } }
|
||
if (index != -1) {
|
||
// Node was found, dispatch the message
|
||
if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
|
||
else if (message.type == 'notify') { // This is a notification message.
|
||
var n = { text:message.value };
|
||
if (message.nodeid != null) { n.nodeid = message.nodeid; }
|
||
if (message.tag != null) { n.tag = message.tag; }
|
||
if (message.username != null) { n.username = message.username; }
|
||
addNotification(n);
|
||
} else if (message.type == 'ps') {
|
||
showDeskToolsProcesses(message);
|
||
} else if ((message.type == 'getclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
|
||
Q('d2clipText').value = message.data;
|
||
} else if ((message.type == 'setclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
|
||
// Display success/fail on the clipboard dialog box.
|
||
QH('dlgClipStatus', message.success ? '<span style=color:green>Success</span>' : '<span style=color:red>Failed</span>')
|
||
setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
|
||
}
|
||
}
|
||
} else {
|
||
if (message.type == 'notify') { // This is a notification message.
|
||
var n = { text:message.value };
|
||
if (message.tag != null) { n.tag = message.tag; }
|
||
if (message.username != null) { n.username = message.username; }
|
||
addNotification(n);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'getnetworkinfo': {
|
||
if ((currentNode._id == message.nodeid) && (xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
|
||
if (message.netif == null) {
|
||
QH('d2netinfo', 'No network interface information available for this device.');
|
||
} else {
|
||
var x = '<div style=width:100%;max-height:260px;overflow-x:hidden;overflow-y:auto;line-height:160%>';
|
||
|
||
if (currentNode.lastconnect) { x += addHtmlValue2('Last agent connection', new Date(currentNode.lastconnect).toLocaleString()); }
|
||
if (currentNode.lastaddr) {
|
||
if (isPrivateIP(currentNode.lastaddr)) {
|
||
x += addHtmlValue2('Last agent address', currentNode.lastaddr.split(':')[0]);
|
||
} else {
|
||
x += addHtmlValue2('Last agent address', '<a href="https://iplocation.com/?ip=' + currentNode.lastaddr.split(':')[0] + '" rel="noreferrer noopener" target="MeshIPLoopup">' + currentNode.lastaddr.split(':')[0] + '</a>');
|
||
}
|
||
}
|
||
|
||
x += addHtmlValue2('Last interfaces update', new Date(message.updateTime).toLocaleString());
|
||
for (var i in message.netif) {
|
||
var net = message.netif[i];
|
||
x += '<hr />'
|
||
if (net.name) { x += addHtmlValue2('Name', '<b>' + EscapeHtml(net.name) + '</b>'); }
|
||
if (net.desc) { x += addHtmlValue2('Description', EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
||
if (net.dnssuffix) { x += addHtmlValue2('DNS suffix', EscapeHtml(net.dnssuffix)); }
|
||
if (net.mac) { x += addHtmlValue2('MAC address', '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0,6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a>'); }
|
||
if (net.v4addr) { x += addHtmlValue2('IPv4 address', EscapeHtml(net.v4addr)); }
|
||
if (net.v4mask) { x += addHtmlValue2('IPv4 mask', EscapeHtml(net.v4mask)); }
|
||
if (net.v4gateway) { x += addHtmlValue2('IPv4 gateway', EscapeHtml(net.v4gateway)); }
|
||
if (net.gatewaymac) { x += addHtmlValue2('Gateway MAC', '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a>'); }
|
||
}
|
||
x += '</div>';
|
||
QH('d2netinfo', x);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'serverversion': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
|
||
var x = '<div style=width:100%;max-height:260px;overflow-x:hidden;overflow-y:auto;line-height:160%>';
|
||
if (!message.current) { message.current = 'Unknown'; }
|
||
if (!message.latest) { message.latest = 'Unknown'; }
|
||
x += addHtmlValue2('Current Version', '<b>' + EscapeHtml(message.current) + '</b>');
|
||
x += addHtmlValue2('Latest Version', '<b>' + EscapeHtml(message.latest) + '</b>');
|
||
x += '</div>';
|
||
if ((message.latest.indexOf('.') == -1) || (message.current == message.latest) || ((features & 2048) == 0)) {
|
||
setDialogMode(2, "MeshCentral Version", 1, null, x);
|
||
} else {
|
||
setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x + '<br /><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to start server self-update.</label>');
|
||
server_showVersionDlgUpdate();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'servererrors': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
|
||
if (message.data == null) {
|
||
setDialogMode(2, "MeshCentral Server Errors", 1, null, 'Server has no error log.');
|
||
} else {
|
||
var x = '<div style=width:100%;max-height:260px;overflow-x:hidden;overflow:auto;line-height:160%;font-size:10px><pre>' + message.data + '<pre></div>';
|
||
setDialogMode(2, "MeshCentral Server Errors", 3, server_showErrorsDlgEx, x + '<br /><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to clear error log.</label>');
|
||
server_showVersionDlgUpdate();
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'serverconsole': {
|
||
p15consoleReceive('serverconsole', message.value);
|
||
break;
|
||
}
|
||
case 'events': {
|
||
if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
|
||
currentDeviceEvents = message.events;
|
||
masterUpdate(1024);
|
||
} else if ((message.user != null) && (message.user == currentUser.name)) {
|
||
currentUserEvents = message.events;
|
||
masterUpdate(2048);
|
||
} else {
|
||
events = message.events;
|
||
masterUpdate(32);
|
||
}
|
||
break;
|
||
}
|
||
case 'getcookie': {
|
||
if (message.tag == 'clickonce') {
|
||
var basicPort = "{{{serverRedirPort}}}" == "" ? "{{{serverPublicPort}}}" : "{{{serverRedirPort}}}";
|
||
var rdpurl = "http://" + window.location.hostname + ":" + basicPort + "/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F" + window.location.hostname + "%2Fmeshrelay.ashx%3Fauth=" + message.cookie + "&CH={{{webcerthash}}}&AP=" + message.protocol + ((debugmode == 1) ? "" : "&HOL=1");
|
||
var newWindow = window.open(rdpurl, '_blank');
|
||
newWindow.opener = null;
|
||
}
|
||
break;
|
||
}
|
||
case 'getNotes': {
|
||
var n = Q('d2devNotes');
|
||
if (n && (message.id == decodeURIComponent(n.attributes['noteid'].value))) {
|
||
if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
|
||
var ro = n.attributes['ro'].value == 'true';
|
||
if (ro == false) { // If we have permissions, set read/write on this note.
|
||
n.removeAttribute('readonly');
|
||
QE('idx_dlgOkButton', true);
|
||
QV('idx_dlgOkButton', true);
|
||
focusTextBox('d2devNotes');
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'otpauth-request': {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
|
||
var secret = message.secret;
|
||
if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
|
||
else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
|
||
QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application and scan the barcode, use <a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank> this link</a> or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.<br /><br />Secret<br /><tt id=d2optsecret secret=\"' + message.secret + '\" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />Enter the token here for 2-step login: <input type=text onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
|
||
new QRCode(Q("qrcode"), { text: message.url, width: 128, height: 128, colorDark: "#000000", colorLight: "#EEE", correctLevel: QRCode.CorrectLevel.H });
|
||
QV('idx_dlgOkButton', true);
|
||
QE('idx_dlgOkButton', false);
|
||
Q('d2otpauthinput').focus();
|
||
}
|
||
break;
|
||
}
|
||
case 'otpauth-setup': {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b style=color:green>Authenticator app activation successful</b>. You will now need a valid token to login again." : "<b style=color:red>2-step login activation failed</b>. Clear the secret from the application and try again. You only have a few minutes to enter the proper code.");
|
||
break;
|
||
}
|
||
case 'otpauth-clear': {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b>Authenticator application removed</b>. You can reactivate this feature at any time." : "<b style=color:red>2-step login activation removal failed</b>. Try again.");
|
||
break;
|
||
}
|
||
case 'otpauth-getpasswords': {
|
||
if (xxdialogMode) return;
|
||
var x = "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.";
|
||
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>No Active Tokens';
|
||
}
|
||
x += "</table></div></div><br />";
|
||
x += "<div><input type=button value='Close' onclick=setDialogMode(0) style=float:right></input>";
|
||
x += "<input type=button value='Generate New Tokens' onclick='account_manageOtp(1);'></input>";
|
||
if (message.passwords != null) { x += "<input type=button value='Clear Tokens' onclick='account_manageOtp(2);'></input>"; }
|
||
x += "</div><br />";
|
||
setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
|
||
break;
|
||
}
|
||
case 'otp-hkey-get': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
var start = "<div style='border-radius:6px;border:2px solid #CCC;background-color:#BBB;width:100%;box-sizing:border-box;margin-bottom:6px'><div style='margin:3px;font-family:Arial, Helvetica, sans-serif;font-size:16px;font-weight:bold'><table style=width:100%;text-align:left>";
|
||
var end = "</table></div></div>";
|
||
var x = "<a href='https://www.yubico.com/' rel='noreferrer noopener' target='_blank'>Hardware keys</a> are used as secondary login authentication.";
|
||
x += "<div style='max-height:150px;overflow-y:auto;overflow-x:hidden;margin-top:6px;margin-bottom:6px'>";
|
||
if (message.keys && message.keys.length > 0) {
|
||
for (var i in message.keys) {
|
||
var key = message.keys[i], type = ((key.type == 1)?'U2F':(key.type == 2)?'OTP':'WebAuthn');
|
||
x += start + '<tr style=margin:5px><td style=width:30px><img width=24 height=18 src="images/hardware-key-' + type + '-24.png" style=margin-top:4px><td style=width:250px>' + key.name + "<td><input type=button value='Remove' onclick=account_removehkey(" + key.i + ")></input>" + end;
|
||
}
|
||
} else {
|
||
x += start + '<tr style=text-align:center><td>No Keys Configured' + end;
|
||
}
|
||
x += "</div>";
|
||
x += "<div><input type=button value='Close' onclick=setDialogMode(0) style=float:right></input>";
|
||
if ((features & 0x00020000) == 0) { x += "<input id=d2addkey1 type=button value='Add Key' onclick='account_addhkey(1);'></input>"; }
|
||
if ((features & 0x00020000) != 0) { x += "<input id=d2addkey3 type=button value='Add Key' onclick='account_addhkey(3);'></input>"; }
|
||
if ((features & 0x00004000) != 0) { x += "<input id=d2addkey2 type=button value='Add YubiKey® OTP' onclick='account_addhkey(2);'></input>"; }
|
||
x += "</div><br />";
|
||
setDialogMode(2, "Manage Security Keys", 8, null, x, 'otpauth-hardware-manage');
|
||
if (u2fSupported() == false) { QE('d2addkey1', false); }
|
||
break;
|
||
}
|
||
case 'otp-hkey-yubikey-add': {
|
||
if (message.result) {
|
||
meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
|
||
} else {
|
||
setDialogMode(2, "Add Security Key", 1, null, '<br />Error, Unable to add key.<br /><br />');
|
||
}
|
||
break;
|
||
}
|
||
case 'otp-hkey-setup-request': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
var x = "Press the key button now.<br /><br /><div style=width:100%;text-align:center><img width=120 height=117 src='images/hardware-keypress-120.png' /></div><input id=dp1keyname style=display:none value=" + message.name + " />";
|
||
setDialogMode(2, "Add Security Key", 2, null, x);
|
||
window.u2f.register(message.request.appId, message.request.registerRequests, message.request.registeredKeys, function (registrationResponse) {
|
||
if (registrationResponse.registrationData) {
|
||
meshserver.send({ action: 'otp-hkey-setup-response', response: registrationResponse, name: Q('dp1keyname').value });
|
||
setDialogMode(2, "Add Security Key", 0, null, '<br />Checking...<br /><br /><br />', 'otpauth-hardware-manage');
|
||
} else {
|
||
var errorCodes = ['', 'Unknown error', 'Bad request', 'Unsupported configuration', 'This key was already registered', 'Timeout'];
|
||
setDialogMode(2, "Add Security Key", 1, null, '<br />' + errorCodes[registrationResponse.errorCode] + '.<br /><br />');
|
||
}
|
||
}, message.request.timeoutSeconds);
|
||
break;
|
||
}
|
||
case 'otp-hkey-setup-response': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
if (message.result == true) {
|
||
meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
|
||
} else {
|
||
setDialogMode(2, "Add Security Key", 1, null, '<br />ERROR: Unable to add key.<br /><br />', 'otpauth-hardware-manage');
|
||
}
|
||
break;
|
||
}
|
||
case 'webauthn-startregister': {
|
||
if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
|
||
var x = "Press the key button now.<br /><br /><div style=width:100%;text-align:center><img width=120 height=117 src='images/hardware-keypress-120.png' /></div><input id=dp1keyname style=display:none value=" + message.name + " />";
|
||
setDialogMode(2, "Add Security Key", 2, null, x);
|
||
|
||
var publicKey = message.request;
|
||
message.request.challenge = Uint8Array.from(atob(message.request.challenge), c => c.charCodeAt(0))
|
||
message.request.user.id = Uint8Array.from(atob(message.request.user.id), c => c.charCodeAt(0))
|
||
navigator.credentials.create({ publicKey })
|
||
.then((newCredentialInfo) => {
|
||
// Public key credential
|
||
var r = { rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.rawId))), response: { attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.attestationObject))), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.clientDataJSON))) }, type: newCredentialInfo.type };
|
||
meshserver.send({ action: 'webauthn-endregister', response: r });
|
||
setDialogMode(0);
|
||
}).catch((error) => {
|
||
// Error
|
||
setDialogMode(2, "Add Security Key", 1, null, "ERROR: " + error);
|
||
});
|
||
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
|
||
masterUpdate(32);
|
||
}
|
||
switch (message.event.action) {
|
||
case 'accountcreate':
|
||
case 'accountchange': {
|
||
// An account was created or changed
|
||
if (userinfo.name == message.event.account.name) {
|
||
var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0;
|
||
var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0;
|
||
if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
|
||
userinfo = message.event.account;
|
||
if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
|
||
updateSelf();
|
||
}
|
||
if (users == null) break;
|
||
users[message.event.account._id] = message.event.account;
|
||
updateUsers();
|
||
break;
|
||
}
|
||
case 'accountremove': {
|
||
// An account was removed
|
||
if (users == null) break;
|
||
delete users['user/' + domain + '/' + message.event.username.toLowerCase()];
|
||
updateUsers();
|
||
break;
|
||
}
|
||
case 'createmesh': {
|
||
// A new mesh was created
|
||
if (message.event.links['user/' + domain + '/' + userinfo.name.toLowerCase()] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
|
||
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
|
||
masterUpdate(4 + 128);
|
||
meshserver.send({ action: 'files' });
|
||
}
|
||
break;
|
||
}
|
||
case 'meshchange': {
|
||
// Update mesh information
|
||
if (meshes[message.event.meshid] == null) {
|
||
// This is a new mesh for us
|
||
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
|
||
meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
|
||
} else {
|
||
// This is an existing mesh
|
||
if (message.event.name) { meshes[message.event.meshid].name = message.event.name; }
|
||
if (message.event.desc) { meshes[message.event.meshid].desc = message.event.desc; }
|
||
if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
|
||
if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
|
||
if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; }
|
||
|
||
// Check if we lost rights to this mesh in this change.
|
||
if (meshes[message.event.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()] == null) {
|
||
if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
|
||
delete meshes[message.event.meshid];
|
||
|
||
// Delete all nodes in that mesh
|
||
var newnodes = [];
|
||
for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
|
||
nodes = newnodes;
|
||
|
||
// If we are looking at a node in the deleted mesh, move back to "My Devices"
|
||
if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
|
||
}
|
||
}
|
||
masterUpdate(4 + 128);
|
||
//meshserver.send({ action: 'files' }); // TODO: Why do we need to do this??
|
||
|
||
// If we are looking at a mesh that is now deleted, move back to "My Account"
|
||
if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { p20updateMesh(); }
|
||
break;
|
||
}
|
||
case 'deletemesh': {
|
||
// Delete the mesh
|
||
if (meshes[message.event.meshid]) {
|
||
delete meshes[message.event.meshid];
|
||
masterUpdate(128);
|
||
meshserver.send({ action: 'files' });
|
||
}
|
||
|
||
// Delete all nodes in that mesh
|
||
var newnodes = [];
|
||
if (nodes != null) { for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } } }
|
||
nodes = newnodes;
|
||
masterUpdate(4);
|
||
|
||
// If we are looking at a mesh that is now deleted, move back to "My Account"
|
||
if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
|
||
// If we are looking at a node in the deleted mesh, move back to "My Devices"
|
||
if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
|
||
|
||
break;
|
||
}
|
||
case 'addnode': {
|
||
var node = message.event.node;
|
||
if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
|
||
node.namel = node.name.toLowerCase();
|
||
if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
node.meshnamel = meshes[node.meshid].name.toLowerCase();
|
||
node.state = 0;
|
||
if (!node.icon) node.icon = 1;
|
||
node.ident = ++nodeShortIdent;
|
||
if (nodes == null) { }
|
||
nodes.push(node);
|
||
|
||
// Web page update
|
||
masterUpdate(1 | 2 | 4 | 16);
|
||
|
||
break;
|
||
}
|
||
case 'removenode': {
|
||
var index = -1;
|
||
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
|
||
if (index != -1) {
|
||
var node = nodes[index];
|
||
if (currentNode == node) {
|
||
if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); }
|
||
currentNode = null;
|
||
// TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
|
||
}
|
||
nodes.splice(index, 1);
|
||
|
||
// Web page update
|
||
masterUpdate(4 | 16);
|
||
}
|
||
break;
|
||
}
|
||
case 'changenode': {
|
||
var index = -1;
|
||
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
|
||
if (index != -1) {
|
||
var node = nodes[index];
|
||
|
||
// Change the node
|
||
node.name = message.event.node.name;
|
||
node.rname = message.event.node.rname;
|
||
node.users = message.event.node.users;
|
||
node.host = message.event.node.host;
|
||
node.desc = message.event.node.desc;
|
||
node.ip = message.event.node.ip;
|
||
node.osdesc = message.event.node.osdesc;
|
||
node.publicip = message.event.node.publicip;
|
||
node.iploc = message.event.node.iploc;
|
||
node.wifiloc = message.event.node.wifiloc;
|
||
node.gpsloc = message.event.node.gpsloc;
|
||
node.tags = message.event.node.tags;
|
||
node.userloc = message.event.node.userloc;
|
||
if (message.event.node.agent != null) {
|
||
if (node.agent == null) node.agent = {};
|
||
if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
|
||
if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
|
||
if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
|
||
if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
|
||
node.agent.tag = message.event.node.agent.tag;
|
||
}
|
||
if (message.event.node.intelamt != null) {
|
||
if (node.intelamt == null) node.intelamt = {};
|
||
if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
|
||
if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
|
||
if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
|
||
if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
|
||
if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
|
||
}
|
||
node.namel = node.name.toLowerCase();
|
||
if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
if (message.event.node.icon) { node.icon = message.event.node.icon; }
|
||
|
||
// Web page update
|
||
masterUpdate(2 | 4 | 8 | 16);
|
||
refreshDevice(node._id);
|
||
|
||
if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
|
||
}
|
||
break;
|
||
}
|
||
case 'nodemeshchange': {
|
||
var index = -1;
|
||
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
|
||
if (index != -1) {
|
||
var node = nodes[index];
|
||
if (meshes[message.event.newMeshId] == null) {
|
||
// We don't see the new mesh, remove this device
|
||
|
||
// TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
|
||
if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } currentNode = null; }
|
||
nodes.splice(index, 1);
|
||
masterUpdate(4 | 16);
|
||
} else {
|
||
// We see the new mesh, move this device
|
||
node.meshid = message.event.newMeshId;
|
||
node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
|
||
masterUpdate(1 | 2 | 4);
|
||
}
|
||
refreshDevice(message.event.nodeid);
|
||
} else {
|
||
// This is a new device, add it.
|
||
var node = message.event.node;
|
||
if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
|
||
node.namel = node.name.toLowerCase();
|
||
if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
|
||
node.meshnamel = meshes[node.meshid].name.toLowerCase();
|
||
node.state = 0;
|
||
if (!node.icon) node.icon = 1;
|
||
node.ident = ++nodeShortIdent;
|
||
if (nodes == null) { }
|
||
nodes.push(node);
|
||
|
||
// Web page update
|
||
masterUpdate(1 | 2 | 4 | 16);
|
||
}
|
||
break;
|
||
}
|
||
case 'nodeconnect': {
|
||
// Indicated a node has changed connectivity state
|
||
var index = -1;
|
||
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
|
||
if (index != -1) {
|
||
var node = nodes[index];
|
||
|
||
// Change the node connection state
|
||
node.conn = message.event.conn;
|
||
node.pwr = message.event.pwr;
|
||
|
||
// Web page update
|
||
masterUpdate(4 | 16);
|
||
refreshDevice(node._id);
|
||
}
|
||
break;
|
||
}
|
||
case 'wssessioncount': {
|
||
// Update the active web socket session count for a user
|
||
if (wssessions != null) {
|
||
if (message.event.count == 0 && wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]) {
|
||
delete wssessions['user/' + domain + '/' + message.event.username.toLowerCase()];
|
||
} else {
|
||
wssessions['user/' + domain + '/' + message.event.username.toLowerCase()] = message.event.count;
|
||
}
|
||
updateUsers();
|
||
}
|
||
break;
|
||
}
|
||
case 'clearevents': {
|
||
events = [];
|
||
masterUpdate(32);
|
||
break;
|
||
}
|
||
case 'login': {
|
||
// Update the last login time
|
||
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
|
||
users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
|
||
}
|
||
break;
|
||
}
|
||
case 'scanamtdevice': {
|
||
// Populate the Intel AMT scan dialog box with the result of the RMCP scan
|
||
if ((xxdialogMode == null) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
|
||
var x = '';
|
||
if (message.event.results == null) {
|
||
// The scan could not occur because of an error. Likely the user range was invalid.
|
||
x = '<div style=width:100%;text-align:center;margin-top:12px>Unable to scan this address range.</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>';
|
||
} else {
|
||
// Go thru all the results and populate the dialog box
|
||
amtScanResults = message.event.results;
|
||
for (var i in message.event.results) {
|
||
var r = message.event.results[i], shortname = r.hostname;
|
||
if (shortname.length > 20) { shortname = shortname.substring(0, 20) + '...'; }
|
||
var str = '<b title="' + EscapeHtml(r.hostname) + '">' + EscapeHtml(shortname) + '</b> - v' + r.ver;
|
||
if (r.state == 2) { if (r.tls == 1) { str += ' with TLS.'; } else { str += ' without TLS.'; } } else { str += ' not activated.'; }
|
||
x += '<div style=width:100%;margin-bottom:2px;background-color:lightgray><div style=padding:4px><div style=display:inline-block;margin-right:5px><input class=DevScanCheckbox name=dp1checkbox tag="' + EscapeHtml(i) + '" type=checkbox onclick=addAmtScanToMeshCheckbox() /></div><div class=j1 style=display:inline-block></div><div style=display:inline-block;margin-left:5px;overflow-x:auto;white-space:nowrap>' + str + '</div></div></div>';
|
||
}
|
||
// If no results where found, display a nice message
|
||
if (x == '') { x = '<div style=width:100%;text-align:center;margin-top:12px>Scan returned no results.</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>'; }
|
||
}
|
||
// Set the html in the dialog box and re-enable the scan button
|
||
QH('dp1results', x);
|
||
QE('dp1range', true);
|
||
QE('dp1rangebutton', true);
|
||
break;
|
||
}
|
||
case 'notify': {
|
||
var n = { text: message.event.value };
|
||
if (message.event.tag != null) { n.tag = message.event.tag; }
|
||
addNotification(n);
|
||
break;
|
||
}
|
||
case 'stopped': { // Server is stopping.
|
||
// Disconnect
|
||
//console.log(message.msg);
|
||
break;
|
||
}
|
||
default:
|
||
//console.log('Unknown message.event.action', message.event.action);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case 'stopped': { // Server is stopping.
|
||
// Disconnect
|
||
autoReconnect = false;
|
||
QH('p0span', message.msg);
|
||
break;
|
||
}
|
||
default:
|
||
console.log('Unknown message.action', message.action);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// MY DEVICES
|
||
//
|
||
|
||
function onRealNameCheckBox() {
|
||
showRealNames = Q('RealNameCheckBox').checked;
|
||
putstore("showRealNames", showRealNames ? 1 : 0);
|
||
masterUpdate(6)
|
||
return;
|
||
}
|
||
|
||
function onDeviceViewChange(i) {
|
||
if (i != null) { Q('viewselect').value = i; }
|
||
for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
|
||
Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
|
||
putstore("deviceView", Q('viewselect').value);
|
||
putstore("viewsize", Q('sizeselect').value);
|
||
masterUpdate(4);
|
||
}
|
||
|
||
function ondockeypress(e) {
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].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 > 90)) return false; }
|
||
}
|
||
return desktop.m.handleKeys(e);
|
||
}
|
||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeys(e);
|
||
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
|
||
if (!xxdialogMode && xxcurrentView == 4) {
|
||
if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||
var processed = 0;
|
||
if (e.key) {
|
||
if (e.key.length === 1 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + e.key)); processed = 1; }
|
||
if (e.keyCode == 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = x.substring(0, x.length - 1); processed = 1; }
|
||
if (e.keyCode == 27) { Q('UserSearchInput').value = ''; processed = 1; }
|
||
} else {
|
||
if (e.charCode != 0 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
|
||
}
|
||
if (processed > 0) { if (processed == 1) { onUserSearchInputChanged(); } return haltEvent(e); }
|
||
}
|
||
if (xxdialogMode || xxcurrentView != 1) return;
|
||
if (e.ctrlKey == true && e.charCode == 96) {
|
||
showRealNames = !showRealNames;
|
||
Q('RealNameCheckBox').value = showRealNames;
|
||
putstore("showRealNames", showRealNames ? 1 : 0);
|
||
masterUpdate(6)
|
||
return;
|
||
}
|
||
if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||
if (Q('viewselect').value < 3) {
|
||
var processed = 0;
|
||
if (e.key) {
|
||
if (e.key.length === 1 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + e.key)); processed = 1; }
|
||
if (e.keyCode == 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = x.substring(0, x.length - 1); processed = 1; }
|
||
if (e.keyCode == 27) { Q('SearchInput').value = ''; processed = 1; }
|
||
} else {
|
||
if (e.charCode != 0 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
|
||
}
|
||
if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
|
||
}
|
||
if (Q('viewselect').value == 3) {
|
||
if (e.key) {
|
||
if (e.key.length === 1 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + e.key)); processed = 1; }
|
||
//if (e.keyCode == 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = x.substring(0, x.length - 1); processed = 1; }
|
||
if (e.keyCode == 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
|
||
if (e.keyCode == 13) { getSearchLocation(); }
|
||
} else {
|
||
if (e.charCode != 0 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + String.fromCharCode(e.charCode))); processed = 1; }
|
||
}
|
||
}
|
||
}
|
||
|
||
function ondockeydown(e) {
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].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 > 90)) return false; }
|
||
}
|
||
return desktop.m.handleKeyDown(e);
|
||
}
|
||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyDown(e); }
|
||
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
|
||
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
|
||
if (!xxdialogMode && xxcurrentView == 4) {
|
||
if (e.keyCode === 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
|
||
if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
|
||
if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
|
||
}
|
||
if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||
var processed = 0;
|
||
if (Q('viewselect').value < 3) {
|
||
if (e.keyCode === 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
|
||
if (e.keyCode === 27) { Q('SearchInput').value = ''; processed = 1; }
|
||
if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
|
||
}
|
||
if (Q('viewselect').value == 3) {
|
||
if (e.keyCode === 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
|
||
if (e.keyCode === 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
|
||
}
|
||
}
|
||
|
||
function ondockeyup(e) {
|
||
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
|
||
// Check what keys we are allows to send
|
||
if (currentNode != null) {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].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 > 90)) return false; }
|
||
}
|
||
return desktop.m.handleKeyUp(e);
|
||
}
|
||
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
|
||
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
|
||
if (!xxdialogMode && xxcurrentView == 4) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
|
||
if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
|
||
if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
|
||
if (Q('viewselect').value < 3) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
|
||
if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
|
||
}
|
||
|
||
// Highlights the device being hovered
|
||
function devMouseHover(element, over) {
|
||
var view = Q('viewselect').value;
|
||
if (view == 1) {
|
||
var e = element.children[1].children[1];
|
||
e.children[0].classList.remove('g1s');
|
||
e.children[1].classList.remove('e2s');
|
||
e.children[2].classList.remove('g2s');
|
||
if (over == 1) {
|
||
e.children[0].classList.add('g1s');
|
||
e.children[1].classList.add('e2s');
|
||
e.children[2].classList.add('g2s');
|
||
}
|
||
} else if (view == 2) {
|
||
var e = element;
|
||
e.children[2].classList.remove('g1s');
|
||
e.children[4].classList.remove('e2s');
|
||
e.children[3].classList.remove('g2s');
|
||
if (over == 1) {
|
||
e.children[2].classList.add('g1s');
|
||
e.children[4].classList.add('e2s');
|
||
e.children[3].classList.add('g2s');
|
||
}
|
||
}
|
||
}
|
||
|
||
var deviceHeaderId = 0;
|
||
var deviceHeaderTotal = 0;
|
||
var deviceHeadersTitles = {};
|
||
var deviceHeaderCount;
|
||
var deviceHeaders = {};
|
||
var oldviewmode = 0;
|
||
function updateDevices() {
|
||
if (nodes == null) { return; }
|
||
var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
|
||
QV('xdevices', view < 4);
|
||
QV('xdevicesmap', view == 4);
|
||
QV('devListToolbar', view < 3);
|
||
QV('kvmListToolbar', view == 3);
|
||
QV('devMapToolbar', view == 4);
|
||
QV('devListToolbarSize', view == 3);
|
||
QV('NoMeshesPanel', meshcount == 0);
|
||
//QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
|
||
QV('devListToolbarViewIcons', (meshcount != 0) && (nodes.length > 0));
|
||
QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
|
||
if ((meshcount == 0) || (nodes.length == 0)) { view = 1; sort = 0; }
|
||
if (view == 4) {
|
||
setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
|
||
// TODO
|
||
} else {
|
||
// 3 wide, list view or desktop view
|
||
deviceHeaderId = 0;
|
||
deviceHeaderCount = {};
|
||
deviceHeaderTotal = 0;
|
||
deviceHeaders = {};
|
||
deviceHeadersTitles = {};
|
||
var kvmDivs = [];
|
||
|
||
// Perform node sort
|
||
if (sort == 0) { nodes.sort(meshSort); }
|
||
else if (sort == 1) { nodes.sort(powerSort); }
|
||
else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
|
||
|
||
// Save the list of currently checked nodeid's
|
||
var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
|
||
if ((oldviewmode < 3) && (view == 3)) { multiDesktopFilter = checkedNodeids; }
|
||
else if ((oldviewmode == 3) && (view < 3)) { checkedNodeids = multiDesktopFilter; }
|
||
|
||
// Compute the width of the device view.
|
||
var totalDeviceViewWidth = Q('column_l').clientWidth - 60;
|
||
var deviceBoxWidth = Math.floor(totalDeviceViewWidth / 301);
|
||
deviceBoxWidth = 301 + Math.floor((totalDeviceViewWidth - (deviceBoxWidth * 301)) / deviceBoxWidth);
|
||
|
||
if (view == 2) {
|
||
r += '<table style=width:100%;margin-top:4px cellpadding=0 cellspacing=0><th style=color:gray><th style=color:gray;width:120px>User<th style=color:gray;width:120px>Address<th style=color:gray;width:100px>Connectivity'; //<th style=color:gray;width:100px>State';
|
||
}
|
||
|
||
// Go thru the list of nodes and display them
|
||
for (var i in nodes) {
|
||
var node = nodes[i];
|
||
if (node.v == false) continue;
|
||
var mesh2 = meshes[node.meshid], meshlinks = mesh2.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||
if (meshlinks == null) continue;
|
||
var meshrights = meshlinks.rights;
|
||
if ((view == 3) && (mesh2.mtype == 1)) continue;
|
||
if (sort == 0) {
|
||
// Mesh header
|
||
if (node.meshid != current) {
|
||
deviceHeaderSet();
|
||
var extra = '';
|
||
if (view == 2) { r += '<tr><td colspan=5>'; }
|
||
if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel® AMT only</span>'; }
|
||
if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
|
||
if (view == 2) { r += '<div>'; }
|
||
r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
|
||
r += getMeshActions(mesh2, meshrights);
|
||
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + node.meshid + '")>' + EscapeHtml(meshes[node.meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></div>';
|
||
if (view == 2) { r += '</div>'; }
|
||
current = node.meshid;
|
||
displayedMeshes[current] = 1;
|
||
c = 0;
|
||
}
|
||
} else if (sort == 1) {
|
||
// Power header
|
||
var pwr = node.pwr?node.pwr:0;
|
||
if (pwr !== current) {
|
||
deviceHeaderSet();
|
||
if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
|
||
r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(node.pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></div>';
|
||
current = pwr;
|
||
c = 0;
|
||
}
|
||
} else if (sort == 2) {
|
||
// Device header
|
||
if (current == null) { current = '1'; }
|
||
}
|
||
|
||
count++;
|
||
var title = EscapeHtml(node.name);
|
||
if (title.length == 0) { title = '<i>None</i>'; }
|
||
if ((node.rname != null) && (node.rname.length > 0)) { title += " / " + EscapeHtml(node.rname); }
|
||
var name = EscapeHtml(node.name);
|
||
if (showRealNames == true && node.rname != null) name = EscapeHtml(node.rname);
|
||
if (name.length == 0) { name = '<i>None</i>'; }
|
||
|
||
// Node
|
||
var icon = node.icon;
|
||
if ((!node.conn) || (node.conn == 0)) { icon += ' gray'; }
|
||
if (view == 1) {
|
||
r += '<div id=devs onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + node._id + '\',null,null,event)><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 style=width:' + (deviceBoxWidth - 100) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></div><div class=g2></div></div></div></div>';
|
||
} else if (view == 2) {
|
||
var states = [];
|
||
if (node.conn) {
|
||
if ((node.conn & 1) != 0) { states.push('<span title="Mesh agent is connected and ready for use.">Agent</span>'); }
|
||
if ((node.conn & 2) != 0) { states.push('<span title="Intel® AMT CIRA is connected and ready for use.">CIRA</span>'); }
|
||
else if ((node.conn & 4) != 0) { states.push('<span title="Intel® AMT is routable.">AMT</span>'); }
|
||
if ((node.conn & 8) != 0) { states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>'); }
|
||
}
|
||
r += '<tr><td><div id=devs class=bar18 onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=height:18px;width:100%;font-size:medium>';
|
||
r += '<div style=width:22px;float:left;background-color:white><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div>';
|
||
r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + node._id + '\',null,null,event)><div class=j' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
|
||
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
|
||
r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + node._id + '\',null,null,event)><span style=width:300px>' + name + '</span></div></div></td>';
|
||
r += '<td style=text-align:center>' + getUserShortStr(node);
|
||
r += '<td style=text-align:center>' + (node.ip != null ? node.ip : '');
|
||
r += '<td style=text-align:center>' + states.join(' + ');
|
||
//r += '<td style=text-align:center>' + (node.pwr != null ? powerStateStrings[node.pwr] : '');
|
||
r += '</tr>';
|
||
} else if ((view == 3) && (node.conn & 1) && (((meshrights & 8) || (meshrights & 256)) != 0) && ((node.agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
|
||
if ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + node._id) >= 0)) {
|
||
r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + node._id + '\',11,null,event)>';
|
||
//r += '<input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox style=float:left>';
|
||
r += '<div class="j' + icon + '" style=width:16px;float:left></div> ' + name + '</div>';
|
||
r += '<span onclick=gotoDevice(\'' + node._id + '\',null,null,event)></span><div id=xkvmid_' + node._id.split('/')[2] + '><div id=skvmid_' + node._id.split('/')[2] + ' style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:1000;cursor:default" onclick=toggleKvmDevice(\'' + node._id + '\')>Disconnected</div></div>';
|
||
r += '</div>';
|
||
kvmDivs.push(node._id);
|
||
}
|
||
}
|
||
|
||
// If we are displaying devices by group, put the device in the right group.
|
||
if ((sort == 3) && (r != '')) {
|
||
if (node.tags) {
|
||
for (var j in node.tags) {
|
||
var tag = node.tags[j];
|
||
if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
|
||
if (view == 3) break;
|
||
}
|
||
}
|
||
r = '';
|
||
}
|
||
|
||
deviceHeaderTotal++;
|
||
if (typeof deviceHeaderCount[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
|
||
}
|
||
|
||
// If displaying devices by groups, sort the group names and display the devices.
|
||
if (sort == 3) {
|
||
var groupNames = [];
|
||
for (var i in groups) { groupNames.push(i); }
|
||
groupNames.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
|
||
for (var j in groupNames) {
|
||
var i = groupNames[j]; r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + i + '</span><span class="devHeaderx">, ' + groupCount[i] + ' device' + ((groupCount[i] > 1)?'s':'') + '</span></div>' + groups[i];
|
||
}
|
||
}
|
||
|
||
// If there is nothing to display, explain the problem
|
||
if ((r == '') && (meshcount > 0) && (Q('SearchInput').value != '')) {
|
||
if (sort == 3) {
|
||
r = '<div style="margin:30px">No devices are included in any groups, click on a device\'s \"Groups\" to add to a group.</div>';
|
||
} else {
|
||
r = '<div style="margin:30px">No devices matching this search.</div>';
|
||
}
|
||
}
|
||
|
||
if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
|
||
|
||
// Display all empty meshes, we need to do this because users can add devices to these at any time.
|
||
if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
|
||
for (var i in meshes) {
|
||
var mesh = meshes[i], meshlink = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||
if (meshlink != null) {
|
||
var meshrights = meshlink.rights;
|
||
if (displayedMeshes[mesh._id] == null) {
|
||
if ((current != '') && (r != '')) { r += '</tr></table>'; }
|
||
r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
|
||
r += getMeshActions(mesh, meshrights);
|
||
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
|
||
if (mesh.mtype == 1) {
|
||
r += '<td><div style=padding:10px><i>No Intel® AMT devices in this mesh';
|
||
if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addDeviceToMesh(\"' + mesh._id + '\")>add one</a>'; }
|
||
}
|
||
if (mesh.mtype == 2) {
|
||
r += '<td><div style=padding:10px><i>No devices in this mesh';
|
||
if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addAgentToMesh(\"' + mesh._id + '\")>add one</a>'; }
|
||
}
|
||
r += '.</i></div></td>';
|
||
current = mesh._id;
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
|
||
|
||
// Add a "Add Device Group" option
|
||
r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px>';
|
||
if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += '<a onclick=account_createMesh() title="Create a new group of devices." style=cursor:pointer>Add Device Group</a> '; }
|
||
r += '<a onclick=p10showMeshCmdDialog(0) style=cursor:pointer title="Download MeshCmd, a command line tool that performs many functions.">MeshCmd</a></div>';
|
||
r += '</div><br/>';
|
||
|
||
QH('xdevices', r);
|
||
deviceHeaderSet();
|
||
|
||
// Re-check nodeid's
|
||
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); }
|
||
|
||
for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
|
||
for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
|
||
p1updateInfo();
|
||
|
||
// Take care of KVM surfaces in desktop view mode
|
||
if (view == 3) {
|
||
// Figure out and adjust the size to fill the width of the div
|
||
var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
|
||
//var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
|
||
var realw = vsize.x + 2, tw = totalDeviceViewWidth - 5, xw = Math.floor(tw / realw);
|
||
xw = realw + Math.floor((tw - (xw * realw)) / xw);
|
||
vsize.y = vsize.y * (xw / vsize.x);
|
||
vsize.x = xw;
|
||
|
||
for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
|
||
for (var i in kvmDivs) {
|
||
var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
|
||
if (desk != null) {
|
||
// This device already has a canvas, use it.
|
||
desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
|
||
Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
|
||
delete desk.xxdelete;
|
||
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
|
||
} else {
|
||
var node = getNodeFromId(id);
|
||
if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
|
||
// This device already has a canvas, use it.
|
||
var c = desktop.m.CanvasId;
|
||
c.setAttribute('id', 'kvmid_' + shortid);
|
||
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
|
||
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
|
||
c.removeAttribute('onmousedown');
|
||
c.removeAttribute('onmouseup');
|
||
c.removeAttribute('onmousemove');
|
||
Q('xkvmid_' + shortid).appendChild(c);
|
||
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
|
||
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
|
||
desktop.shortid = shortid;
|
||
desktop.onStateChanged = onMultiDesktopStateChange;
|
||
multiDesktop[id] = desktop;
|
||
desktop = desktopNode = currentNode = null;
|
||
// Setup a replacement desktop
|
||
QH('DeskParent', '<canvas id="Desk" width="640" height="480" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
|
||
} else {
|
||
// This is a new device, create a canvas for it.
|
||
var c = document.createElement('canvas');
|
||
c.setAttribute('id', 'kvmid_' + shortid);
|
||
c.setAttribute('width', 640);
|
||
c.setAttribute('height', 480);
|
||
c.setAttribute('oncontextmenu', 'return false');
|
||
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
|
||
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
|
||
try { Q('xkvmid_' + shortid).appendChild(c); } catch (ex) {}
|
||
// Check if we need to auto-connect
|
||
if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
|
||
}
|
||
}
|
||
}
|
||
for (var i in multiDesktop) {
|
||
// If a device is no longer viewed, disconnect it.
|
||
if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
|
||
else if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
|
||
mdeskAdjust(multiDesktop[i].m, multiDesktop[i].m.ScreenWidth, multiDesktop[i].m.ScreenHeight, multiDesktop[i].m.CanvasId); // Adjust screen size change
|
||
}
|
||
}
|
||
deskAdjust();
|
||
} else {
|
||
disconnectAllKvmFunction();
|
||
Q('autoConnectDesktopCheckbox').checked = false;
|
||
}
|
||
}
|
||
oldviewmode = view;
|
||
}
|
||
|
||
function toggleKvmDevice(nodeid) {
|
||
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
|
||
//var conn = 0;
|
||
//if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
|
||
if (node.conn & 1) { connectMultiDesktop(node, 1); }
|
||
}
|
||
}
|
||
|
||
function getUserShortStr(node) {
|
||
if (node == null || node.users == null || node.users.length == 0) return '';
|
||
if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + node.users.length + ' users</span>'; }
|
||
var u = node.users[0], su = u, i = u.indexOf('\\');
|
||
if (i > 0) { su = u.substring(i + 1); }
|
||
su = EscapeHtml(su);
|
||
if (su.length > 15) { su = su.substring(0, 14) + '…'; }
|
||
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
|
||
}
|
||
|
||
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
|
||
function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
|
||
function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
|
||
function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][state]); } catch (ex) {} }
|
||
|
||
function showMultiDesktopSettings() {
|
||
QV('d7amtkvm', false);
|
||
QV('d7meshkvm', true);
|
||
d7bitmapquality.value = multidesktopsettings.quality;
|
||
d7bitmapscaling.value = multidesktopsettings.scaling;
|
||
if (multidesktopsettings.framerate) { d7framelimiter.value = multidesktopsettings.framerate; } else { d7framelimiter.value = 1000; }
|
||
setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
|
||
}
|
||
|
||
function showMultiDesktopSettingsChanged() {
|
||
multidesktopsettings.quality = d7bitmapquality.value;
|
||
multidesktopsettings.scaling = d7bitmapscaling.value;
|
||
multidesktopsettings.framerate = d7framelimiter.value;
|
||
localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
|
||
// Make changes to all current connections
|
||
for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
|
||
}
|
||
|
||
function connectMultiDesktop(node, contype) {
|
||
var nodeid = node._id, shortid = nodeid.split('/')[2];
|
||
var desk = multiDesktop[nodeid];
|
||
if (desk == null) {
|
||
if (Q('kvmid_' + shortid) == null) return; // Check if this device is being displayed, if not, exit now.
|
||
if (contype == 2) {
|
||
// Setup the Intel AMT remote desktop
|
||
if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
|
||
desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + shortid), authCookie);
|
||
desk.shortid = shortid;
|
||
//desk.debugmode = debugmode;
|
||
desk.onStateChanged = onMultiDesktopStateChange;
|
||
desk.m.bpp = 1;
|
||
desk.m.useZRLE = true;
|
||
desk.m.showmouse = true;
|
||
desk.m.onKvmData = function (data) { console.log('KVM Data received in multi-desktop mode, this is not supported.'); }; // KVM Data Channel not supported in multi-desktop right now.
|
||
//desk.m.onScreenSizeChange = deskAdjust;
|
||
if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
|
||
desk.Start(nodeid, 16994, '*', '*', 0);
|
||
desk.contype = 2;
|
||
multiDesktop[nodeid] = desk;
|
||
} else if (contype == 1) {
|
||
// Setup the Mesh Agent remote desktop
|
||
desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie);
|
||
desk.shortid = shortid;
|
||
desk.attemptWebRTC = attemptWebRTC;
|
||
desk.onStateChanged = onMultiDesktopStateChange;
|
||
desk.m.CompressionLevel = multidesktopsettings.quality;
|
||
desk.m.ScalingLevel = multidesktopsettings.scaling;
|
||
desk.m.FrameRateTimer = multidesktopsettings.framerate;
|
||
//desk.m.onDisplayinfo = deskDisplayInfo;
|
||
//desk.m.onScreenSizeChange = deskAdjust;
|
||
if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
|
||
desk.Start(nodeid);
|
||
desk.contype = 1;
|
||
multiDesktop[nodeid] = desk;
|
||
}
|
||
} else {
|
||
// Disconnect and clean up the remote desktop
|
||
desk.Stop();
|
||
delete multiDesktop[nodeid];
|
||
}
|
||
}
|
||
|
||
function getMeshActions(mesh, meshrights) {
|
||
if ((meshrights & 4) == 0) return '';
|
||
var r = '';
|
||
if ((features & 1024) == 0) { // If CIRA is allowed
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
|
||
}
|
||
if (mesh.mtype == 1) {
|
||
if ((features & 1) == 0) { // If not WAN-Only
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the local network." onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer by scanning the local network." onclick=addAmtScanToMesh(\"' + mesh._id + '\")>Scan Network</a>';
|
||
}
|
||
}
|
||
if (mesh.mtype == 2) {
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
|
||
if (features & 64) {
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Invite someone to install the mesh agent on this mesh." onclick=inviteAgentToMesh(\"' + mesh._id + '\")>Invite</a>';
|
||
}
|
||
}
|
||
return r;
|
||
}
|
||
|
||
function addDeviceToMesh(meshid) {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[meshid];
|
||
var x = "Add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\".<br /><br />";
|
||
x += addHtmlValue('Device Name', '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue('Hostname', '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder="Same as device name" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue('Username', '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder="admin" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue('Password', '<input id=dp1password type=password style=width:230px autocomplete=off maxlength=32 onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
|
||
x += addHtmlValue('Security', '<select id=dp1tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
||
setDialogMode(2, "Add Intel® AMT device", 3, addDeviceToMeshEx, x, meshid);
|
||
validateDeviceToMesh();
|
||
Q('dp1devicename').focus();
|
||
}
|
||
|
||
// Display the Intel AMT scanning dialog box
|
||
function addAmtScanToMesh(meshid) {
|
||
if (xxdialogMode) return;
|
||
var x = "Enter a range of IP addresses to scan for Intel AMT devices.<br /><br />";
|
||
x += addHtmlValue('IP Range', '<input id=dp1range style=width:184px value="192.168.1.0/24" onkeyup=addAmtScanToMeshKeyUp(event) /><input id=dp1rangebutton type=button value=Scan onclick=addAmtScanToMeshButton()></input>');
|
||
x += '<div id=dp1results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
|
||
setDialogMode(2, "Scan for Intel® AMT devices", 3, addAmtScanToMeshEx, x, meshid);
|
||
QE('idx_dlgOkButton', false);
|
||
QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>');
|
||
focusTextBox('dp1range');
|
||
}
|
||
|
||
function addAmtScanToMeshKeyUp(e) {
|
||
if (e.keyCode == 13) { haltEvent(e); addAmtScanToMeshButton(); }
|
||
}
|
||
|
||
// Called when OK is pressed on the Intel AMT scanning box
|
||
function addAmtScanToMeshEx(button, meshid) {
|
||
var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) {
|
||
if (elements[i].checked) {
|
||
var ipaddr = elements[i].getAttribute('tag');
|
||
var amtinfo = amtScanResults[ipaddr];
|
||
meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: ipaddr, hostname: amtinfo.hostname, amtusername: '', amtpassword: '', amttls: amtinfo.tls });
|
||
}
|
||
}
|
||
}
|
||
|
||
// If the user presses the "Scan" button on the Intel AMT scanning dialog box, start a scan.
|
||
function addAmtScanToMeshButton() {
|
||
QE('dp1range', false);
|
||
QE('dp1rangebutton', false);
|
||
QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px>Scanning...</div>');
|
||
meshserver.send({ action: 'scanamtdevice', range: Q('dp1range').value });
|
||
}
|
||
|
||
// Called when a scanned computer is checked or unchecked.
|
||
function addAmtScanToMeshCheckbox() {
|
||
var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked) checkcount++; }
|
||
QE('idx_dlgOkButton', checkcount > 0);
|
||
}
|
||
|
||
function addCiraDeviceToMesh(meshid) {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[meshid];
|
||
|
||
// Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
|
||
var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
|
||
|
||
var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>';
|
||
if ((features & 16) == 0) { y += '<option value=2>Manual Certificate</option></select>'; } // Only display this option if Intel AMT CIRA with Mutual-Auth is allowed.
|
||
|
||
var x = '';
|
||
x += addHtmlValue('Setup Method', y);
|
||
x += '<hr>';
|
||
|
||
// Setup CIRA using a MeshCommander script (Pretty Simple)
|
||
x += "<div id=dlgAddCira0>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, download the following script files and use <a href='http://meshcommander.com' rel='noreferrer noopener' target='_blank'>MeshCommander</a> to run the script to configure computers.<br /><br />";
|
||
//x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" rel="noreferrer noopener" target="_blank">cira_setup.mescript</a>');
|
||
//x += addHtmlValue('Cleanup CIRA', '<a href="mescript.ashx?type=2" rel="noreferrer noopener" target="_blank">cira_clean.mescript</a>');
|
||
x += addHtmlValue('Setup CIRA', '<a style=cursor:pointer onclick=fileDownload("mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '","cira_setup.mescript")>cira_setup.mescript</a>');
|
||
x += addHtmlValue('Cleanup CIRA', '<a style=cursor:pointer onclick=fileDownload("mescript.ashx?type=2","cira_clean.mescript")>cira_clean.mescript</a>');
|
||
x += "</div>";
|
||
|
||
// Setup CIRA with user/pass authentication (Somewhat difficult)
|
||
x += "<div id=dlgAddCira1 style=display:none>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT";
|
||
if (serverinfo.mpspass) { x += " and authenticate to the server using this username and password.<br /><br />"; } else { x += " and authenticate to the server using this username and any password.<br /><br />"; }
|
||
//x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" rel="noreferrer noopener" target="_blank">Root Certificate File</a>');
|
||
x += addHtmlValue('Root Certificate', '<a style=cursor:pointer onclick=fileDownload("MeshServerRootCert.cer","MeshServerRootCert.cer")>Root Certificate File</a>');
|
||
x += addHtmlValue('Username', '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
|
||
if (serverinfo.mpspass) { x += addHtmlValue('Password', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
|
||
if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
|
||
x += "</div>";
|
||
|
||
// Setup CIRA with certificate authentication (Really difficult, only if TLS offload is not used)
|
||
if ((features & 16) == 0) {
|
||
x += "<div id=dlgAddCira2 style=display:none>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT, authenticate using a client certificate with the following common name and connect to the following server.<br /><br />";
|
||
//x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" rel="noreferrer noopener" target="_blank">Root Certificate File</a>');
|
||
x += addHtmlValue('Root Certificate', '<a style=cursor:pointer onclick=fileDownload("MeshServerRootCert.cer","MeshServerRootCert.cer")>Root Certificate File</a>');
|
||
x += addHtmlValue('Organization', '<input style=width:230px readonly value="' + meshidx + '" />');
|
||
if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
|
||
x += "</div>";
|
||
}
|
||
|
||
setDialogMode(2, "Add Intel® AMT CIRA device", 2, null, x, 'fileDownload');
|
||
}
|
||
|
||
function dlgAddCiraSelClick() {
|
||
var val = Q('dlgAddCiraSel').value;
|
||
QV('dlgAddCira0', val == 0);
|
||
QV('dlgAddCira1', val == 1);
|
||
QV('dlgAddCira2', val == 2);
|
||
}
|
||
|
||
// Return true is the input string looks like an email address
|
||
function checkEmail(str) {
|
||
var x = str.split('@');
|
||
var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
|
||
if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
|
||
return ok;
|
||
}
|
||
|
||
function inviteAgentToMesh(meshid) {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[meshid];
|
||
var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".<br /><br />";
|
||
x += addHtmlValue('Name (optional)', '<input id=agentInviteName value="" style=width:230px maxlength=64 />');
|
||
x += addHtmlValue('Email', '<input id=agentInviteEmail style=width:230px placeholder="example@email.com" onkeyup=validateAgentInvite()></input>');
|
||
x += addHtmlValue('Operating System', '<select id=agentInviteNameOs style=width:236px><option value=0>Any supported</option><option value=1>Windows only</option><option value=3>Apple OSX only</option><option value=2>Linux only</option></select>');
|
||
x += addHtmlValue('Installation Type', '<select id=agentInviteType style=width:236px><option value=0>Background and interactive</option><option value=2>Background only</option><option value=1>Interactive only</option></select>');
|
||
x += addHtmlValue('Message<br />(optional)', '<textarea id=agentInviteMessage value="" style=width:230px;height:100px;resize:none maxlength=1024 /></textarea>');
|
||
setDialogMode(2, "Invite", 3, performAgentInvite, x, meshid);
|
||
validateAgentInvite();
|
||
}
|
||
|
||
function validateAgentInvite() {
|
||
QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
|
||
}
|
||
|
||
function performAgentInvite(button, meshid) {
|
||
meshserver.send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value, name: Q('agentInviteName').value, os: Q('agentInviteNameOs').value, flags: Q('agentInviteType').value, msg: Q('agentInviteMessage').value });
|
||
}
|
||
|
||
function addAgentToMesh(meshid) {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[meshid], x = '', installType = 0;
|
||
x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Apple OSX</option><option value=3>Windows (UnInstall)</option><option value=4>Linux (UnInstall)</option></select>');
|
||
x += '<div id=aginsTypeDiv>';
|
||
x += addHtmlValue('Installation Type', '<select id=aginsType onchange=addAgentToMeshClick() style=width:236px><option value=0>Background & interactive</option><option value=2>Background only</option><option value=1>Interactive only</option></select>');
|
||
x += '</div><hr>';
|
||
|
||
// \/:*?"<>|
|
||
var meshfilename = mesh.name
|
||
meshfilename = meshfilename.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join('');
|
||
|
||
// Windows agent install
|
||
//x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
|
||
x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
|
||
//x += addHtmlValue('Mesh Agent', '<a id=aginsw32lnk href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
|
||
//x += addHtmlValue('Mesh Agent', '<a id=aginsw64lnk href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
|
||
x += addHtmlValue('Mesh Agent', '<a id=aginsw32lnk style=cursor:pointer onclick=fileDownload("meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=","MeshAgent-' + meshfilename + '.exe",1) title="32bit version of the MeshAgent">Windows (.exe)</a>');
|
||
x += addHtmlValue('Mesh Agent', '<a id=aginsw64lnk style=cursor:pointer onclick=fileDownload("meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=","MeshAgent-' + meshfilename + '.exe",1) title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
|
||
if (debugmode > 0) { x += addHtmlValue('Settings File', '<a id=aginswmshlnk href="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
|
||
x += "</div>";
|
||
|
||
// Linux agent install
|
||
x += "<div id=agins_linux style=display:none>To add a computer to " + EscapeHtml(mesh.name) + " run the following command. Root credentials will be needed.<br />";
|
||
x += '<textarea id=agins_linux_area rows=2 cols=20 readonly=readonly style=width:100%;resize:none;height:120px;overflow:scroll;font-size:12px readonly></textarea>';
|
||
x += "</div>";
|
||
|
||
// OSX agent install
|
||
x += "<div id=agins_osx style=display:none>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent installer has server and mesh information embedded within it.<br /><br />";
|
||
x += addHtmlValue('Mesh Agent', '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" rel="noreferrer noopener" target="_blank" title="64bit version of OSX Mesh Agent">OSX Agent (64bit)</a>');
|
||
x += "</div>";
|
||
|
||
// Windows agent uninstall
|
||
x += "<div id=agins_windows_un style=display:none>To remove a mesh agent, download the file below, run it and click \"uninstall\".<br /><br />";
|
||
//x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3" rel="noreferrer noopener" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
|
||
//x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=4" rel="noreferrer noopener" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
|
||
x += addHtmlValue('Mesh Agent', '<a style=cursor:pointer onclick=fileDownload("meshagents?id=3","MeshAgent.exe") title="32bit version of the MeshAgent">Windows (.exe)</a>');
|
||
x += addHtmlValue('Mesh Agent', '<a style=cursor:pointer onclick=fileDownload("meshagents?id=4","MeshAgent.exe") title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
|
||
x += "</div>";
|
||
|
||
// Linux agent uninstall
|
||
x += "<div id=agins_linux_un style=display:none>To remove a mesh agent, run the following command. Root credentials will be needed.<br />";
|
||
x += '<textarea id=agins_linux_area_un rows=2 cols=20 readonly=readonly style=width:100%;resize:none;height:120px;overflow:scroll;font-size:12px readonly></textarea>';
|
||
x += "</div>";
|
||
|
||
setDialogMode(2, "Add Mesh Agent", 2, null, x, 'fileDownload');
|
||
var servername = serverinfo.name;
|
||
if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
|
||
|
||
var noProxy = ((features & 0x2000) != 0)?'--no-proxy ':''; // Server asked that agent be installed to preferably not use a HTTP proxy.
|
||
if (serverinfo.https == true) {
|
||
var portStr = (serverinfo.port == 443)?'':(":" + serverinfo.port);
|
||
Q('agins_linux_area').value = "wget https://" + servername + portStr + "/meshagents?script=1 " + noProxy + "--no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + " '" + meshid.split('/')[2] + "'\r\n";
|
||
Q('agins_linux_area_un').value = "wget https://" + servername + portStr + "/meshagents?script=1 " + noProxy + "--no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||
} else {
|
||
var portStr = (serverinfo.port == 80)?'':(":" + serverinfo.port);
|
||
Q('agins_linux_area').value = "wget http://" + servername + portStr + "/meshagents?script=1 " + noProxy + "-O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + " '" + meshid.split('/')[2] + "'\r\n";
|
||
Q('agins_linux_area_un').value = "wget http://" + servername + portStr + "/meshagents?script=1 " + noProxy + "-O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||
}
|
||
Q('aginsSelect').focus();
|
||
addAgentToMeshClick();
|
||
}
|
||
|
||
function fileDownload(path, name, appendFlag) {
|
||
var xdr = null, flag = '';
|
||
if (appendFlag == 1) {
|
||
// Download a agent
|
||
flag = Q('aginsType').value;
|
||
} else if (appendFlag == 2) {
|
||
// Download meshcmd
|
||
flag = Q('aginsSelect').value;
|
||
if (parseInt(flag) >= 5) { name = name.toLowerCase(); } else { name += '.exe'; }
|
||
}
|
||
try { xdr = new XDomainRequest(); } catch (e) { }
|
||
if (!xdr) xdr = new XMLHttpRequest();
|
||
xdr.open("GET", window.location.href + path + flag);
|
||
xdr.timeout = 15000;
|
||
xdr.responseType = "blob";
|
||
xdr.onprogress = function (x) { /*console.log(x);*/ };
|
||
xdr.onload = function (e) { saveAs(new Blob([e.target.response], { type: "application/octet-stream" }), name); if (xxdialogTag == 'fileDownload') { setDialogMode(0); } };
|
||
xdr.onerror = function () { if (xxdialogTag == 'fileDownload') { setDialogMode(0); } alert('Agent downloads timeout.'); };
|
||
xdr.ontimeout = function () { if (xxdialogTag == 'fileDownload') { setDialogMode(0); } alert('Unable to download agent.'); };
|
||
xdr.send();
|
||
}
|
||
|
||
function addAgentToMeshClick() {
|
||
var v = Q('aginsSelect').value;
|
||
QV('agins_windows', v == 0);
|
||
QV('agins_linux', v == 1);
|
||
QV('agins_osx', v == 2);
|
||
QV('agins_windows_un', v == 3);
|
||
QV('agins_linux_un', v == 4);
|
||
QV('aginsTypeDiv', v == 0);
|
||
|
||
// Fix the links if needed
|
||
//Q('aginsw32lnk').href = (Q('aginsw32lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
|
||
//Q('aginsw64lnk').href = (Q('aginsw64lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
|
||
if (debugmode > 0) { Q('aginswmshlnk').href = (Q('aginswmshlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value; }
|
||
}
|
||
|
||
function validateDeviceToMesh() {
|
||
QE('idx_dlgOkButton', (Q('dp1devicename').value.length > 0) && (passwordcheck(Q('dp1password').value)));
|
||
}
|
||
|
||
function addDeviceToMeshEx(button, meshid) {
|
||
var amtuser = Q('dp1username').value;
|
||
if (amtuser == '') amtuser = 'admin';
|
||
var host = Q('dp1hostname').value;
|
||
if (host == '') host = Q('dp1devicename').value;
|
||
meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: Q('dp1devicename').value, hostname: host, amtusername: amtuser, amtpassword: Q('dp1password').value, amttls: Q('dp1tls').value });
|
||
}
|
||
|
||
function deviceHeaderSet() {
|
||
if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
|
||
deviceHeaders["DevxHeader" + deviceHeaderId] = ', ' + deviceHeaderTotal + ((deviceHeaderTotal == 1) ? ' node' : ' nodes');
|
||
//var title = '';
|
||
//for (x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
|
||
//deviceHeadersTitles["DevxHeader" + deviceHeaderId] = title;
|
||
deviceHeaderId++;
|
||
deviceHeaderCount = {};
|
||
deviceHeaderTotal = 0;
|
||
}
|
||
|
||
var powerStateStrings = ['', '<span title="Device is powered on.">Powered</span>', '<span title="Device is in sleep state (S1).">Sleeping</span>', '<span title="Device is in sleep state (S2).">Sleeping</span>', '<span title="Device is in deep sleep state (S3).">Deep Sleep</span>', '<span title="Device is in hibernating state (S4).">Hibernating</span>', '<span title="Device is in powered off state (S5).">Soft-Off</span>', '<span title="Device is detected but power state could not be obtained.">Present</span>'];
|
||
var powerStateStrings2 = ['', 'Device is powered', 'Device is in sleep state (S1)', 'Device is in sleep state (S2)', 'Device is in deep sleep state (S3)', 'Device is hibernating (S4)', 'Device is in soft-off state (S5)', 'Device is present, but power state cannot be determined'];
|
||
var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
|
||
function NodeStateStr(node) {
|
||
var states = [];
|
||
if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
|
||
if (node.conn) {
|
||
if ((node.conn & 1) != 0) { states.push('<span title="Mesh agent is connected and ready for use.">Agent</span>'); }
|
||
if ((node.conn & 2) != 0) { states.push('<span title="Intel® AMT CIRA is connected and ready for use.">CIRA</span>'); }
|
||
else if ((node.conn & 4) != 0) { states.push('<span title="Intel® AMT is routable.">Intel® AMT</span>'); }
|
||
if ((node.conn & 8) != 0) { states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>'); }
|
||
}
|
||
if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
|
||
return states.join(', ');
|
||
}
|
||
|
||
function PowerStateStr(x) {
|
||
if (x < powerStatetable.length) return powerStatetable[x];
|
||
return '';
|
||
}
|
||
|
||
function PowerStateStr2(x) {
|
||
if ((x != 0) && (x < powerStatetable.length)) return powerStatetable[x];
|
||
return 'Unknown';
|
||
}
|
||
|
||
function selectallButtonFunction() {
|
||
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) checkcount++; }
|
||
for (var i=0;i<elements.length;i++) { elements[i].checked = (checkcount == 0); }
|
||
p1updateInfo();
|
||
}
|
||
|
||
function p1updateInfo() {
|
||
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) { checkcount++; } }
|
||
if (checkcount > 0) {
|
||
QE('GroupActionButton', true);
|
||
Q('SelectAllButton').value = 'Select None';
|
||
QV('cxmgroupsplit', true);
|
||
QV('cxmdesktop', true);
|
||
} else {
|
||
QE('GroupActionButton', false);
|
||
Q('SelectAllButton').value = 'Select All';
|
||
QV('cxmgroupsplit', false);
|
||
QV('cxmdesktop', false);
|
||
}
|
||
}
|
||
|
||
function groupActionFunction() {
|
||
var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights.<br /><br />";
|
||
x += addHtmlValue('Operation', '<select id=d2groupop style=float:right;width:250px><option value=100>Wake-up devices</option><option value=4>Sleep devices</option><option value=3>Reset devices</option><option value=2>Power off devices</option><option value=102>Move to device group</option><option value=101>Delete devices</option></select>');
|
||
setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
|
||
}
|
||
|
||
// Get the list of checked devices, removes any duplicates.
|
||
function getCheckedDevices() {
|
||
var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
|
||
for (var i=0;i<elements.length;i++) { if (elements[i].checked) { if (elements[i].value) { var nid = elements[i].value.substring(6); if (nodeids.indexOf(nid) == -1) { nodeids.push(nid); } } } }
|
||
return nodeids;
|
||
}
|
||
|
||
function groupActionFunctionEx() {
|
||
var op = Q('d2groupop').value;
|
||
if (op == 100) {
|
||
// Group wake
|
||
meshserver.send({ action: 'wakedevices', nodeids: getCheckedDevices() });
|
||
} else if (op == 101) {
|
||
// Group delete, ask for confirmation
|
||
var x = "Confirm delete selected devices(s)?<br /><br />";
|
||
x += "<label><input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />Confirm</label>";
|
||
setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
|
||
QE('idx_dlgOkButton', false);
|
||
} else if (op == 102) {
|
||
// Move computers to a different group
|
||
p10showChangeGroupDialog(getCheckedDevices());
|
||
} else {
|
||
// Power operation
|
||
meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: op });
|
||
}
|
||
}
|
||
|
||
function d2groupActionFunctionDelEx() { QE('idx_dlgOkButton', Q('d2check').checked); }
|
||
function groupActionFunctionDelEx() { meshserver.send({ action: 'removedevices', nodeids: getCheckedDevices() }); }
|
||
|
||
function onSortSelectChange(skipsave) {
|
||
sort = document.getElementById("sortselect").selectedIndex;
|
||
if (!skipsave) { putstore("sort", sort); }
|
||
}
|
||
|
||
function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
|
||
function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap > bp) return -1; if (ap < bp) return 1; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
|
||
function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
|
||
function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
|
||
function onSearchFocus(x) { searchFocus = x; }
|
||
function onMapSearchFocus(x) { mapSearchFocus = x; }
|
||
function onUserSearchFocus(x) { userSearchFocus = x; }
|
||
function onConsoleFocus(x) { consoleFocus = x; }
|
||
|
||
function onSearchInputChanged() {
|
||
var x = Q('SearchInput').value.toLowerCase().trim(); putstore("search", x);
|
||
var userSearch = null, ipSearch = null, groupSearch = null;
|
||
if (x.startsWith('user:')) { userSearch = x.substring(5); }
|
||
else if (x.startsWith('u:')) { userSearch = x.substring(2); }
|
||
else if (x.startsWith('ip:')) { ipSearch = x.substring(3); }
|
||
else if (x.startsWith('group:')) { groupSearch = x.substring(6); }
|
||
else if (x.startsWith('g:')) { groupSearch = x.substring(2); }
|
||
|
||
if (x == '') {
|
||
// No search
|
||
for (var d in nodes) { nodes[d].v = true; }
|
||
} else if (ipSearch != null) {
|
||
// IP address search
|
||
for (var d in nodes) { nodes[d].v = ((nodes[d].ip != null) && (nodes[d].ip.indexOf(ipSearch) >= 0)); }
|
||
} else if (groupSearch != null) {
|
||
// Group filter
|
||
for (var d in nodes) { nodes[d].v = (meshes[nodes[d].meshid].name.toLowerCase().indexOf(groupSearch) >= 0); }
|
||
} else if (userSearch != null) {
|
||
// User search
|
||
for (var d in nodes) {
|
||
nodes[d].v = false;
|
||
if (nodes[d].users && nodes[d].users.length > 0) { for (var i in nodes[d].users) { if (nodes[d].users[i].toLowerCase().indexOf(userSearch) >= 0) { nodes[d].v = true; } } }
|
||
}
|
||
} else {
|
||
// Device name search
|
||
try {
|
||
var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception.
|
||
for (var d in nodes) {
|
||
nodes[d].v = (rx.test(nodes[d].name.toLowerCase())) || (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase()));
|
||
if ((nodes[d].v == false) && nodes[d].tags) {
|
||
for (var s in nodes[d].tags) {
|
||
if (rx.test(nodes[d].tags[s].toLowerCase())) {
|
||
nodes[d].v = true;
|
||
break;
|
||
} else {
|
||
nodes[d].v = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
|
||
}
|
||
}
|
||
|
||
var contextelement = null;
|
||
function handleContextMenu(event) {
|
||
hideContextMenu();
|
||
var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
|
||
var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
|
||
var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
|
||
if (elem && elem != null && elem.id == "MxMESH") {
|
||
contextelement = elem;
|
||
var contextmenudiv = document.getElementById("meshContextMenu");
|
||
contextmenudiv.style.left = event.pageX + "px";
|
||
contextmenudiv.style.top = event.pageY + "px";
|
||
contextmenudiv.style.display = "block";
|
||
} else {
|
||
while (elem && elem != null && elem.id != "devs") { elem = elem.parentElement; }
|
||
if (!elem || elem == null) return true;
|
||
contextelement = elem;
|
||
var contextmenudiv = document.getElementById("contextMenu");
|
||
contextmenudiv.style.left = event.pageX + "px";
|
||
contextmenudiv.style.top = event.pageY + "px";
|
||
contextmenudiv.style.display = "block";
|
||
}
|
||
|
||
// Get the node and set the menu options
|
||
var nodeid = contextelement.children[1].attributes.onclick.value;
|
||
var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
|
||
var mesh = meshes[node.meshid];
|
||
var meshlinks = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||
var meshrights = meshlinks.rights;
|
||
var consoleRights = ((meshrights & 16) != 0);
|
||
|
||
// Check if we have terminal and file access
|
||
var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
|
||
var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
|
||
|
||
QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
|
||
QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
|
||
QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
|
||
QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
|
||
QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
|
||
|
||
return haltEvent(event);
|
||
}
|
||
|
||
function cmaction(action,event) {
|
||
var nodeid = contextelement.children[1].attributes.onclick.value;
|
||
nodeid = nodeid.substring(12, nodeid.length - 18);
|
||
if (action == 7) { Q('viewselect').value = 3; Q('viewselect').onchange(); Q('autoConnectDesktopCheckbox').checked = true; Q('autoConnectDesktopCheckbox').onclick(); } // Multi-Desktop
|
||
if ((action > 0) && (action < 7)) {
|
||
var panel = [0, 10, 12, 11, 13, 16, 15][action]; // (invalid), General, Desktop, Terminal, Files, Events, Console
|
||
if (event && (event.shiftKey == true)) {
|
||
// Open the device in a different tab
|
||
window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=' + panel + '&hide=16', 'meshcentral:' + nodeid);
|
||
} else {
|
||
// Go to the right panel
|
||
gotoDevice(nodeid, panel);
|
||
}
|
||
}
|
||
}
|
||
|
||
function cmmeshaction(action) {
|
||
var meshid = contextelement.attributes.onclick.value.substring(32, (32 + 69));
|
||
var elements = document.getElementsByClassName("DeviceCheckbox");
|
||
if (action == 1) { for (var i = 0; i < elements.length; i++) { if ( (elements[i].attributes) && (elements[i].attributes['class']['value'].substring(0, 69) == meshid)) { elements[i].checked = true; } } }
|
||
if (action == 2) { for (var i = 0; i < elements.length; i++) { if ( (elements[i].attributes) && (elements[i].attributes['class']['value'].substring(0, 69) == meshid)) { elements[i].checked = false; } } }
|
||
//if (action == 3) { window.location = "multidesktop.aspx?mesh=" + meshid + "&auto=1"; }
|
||
p1updateInfo();
|
||
}
|
||
|
||
function hideContextMenu() {
|
||
QV('contextMenu', false);
|
||
QV('meshContextMenu', false);
|
||
contextelement = null;
|
||
}
|
||
|
||
//
|
||
// DEVICES MAP
|
||
//
|
||
|
||
// Maps code starts from here. Initialize all the variables
|
||
var xxmap = {
|
||
map: null,
|
||
contextmenu: null,
|
||
activeInteractions: [], // Save Modified features in this list
|
||
showindex: 0,
|
||
markersSource: null, // Initialize a Source Vector
|
||
markersLayer: null,
|
||
mapLayer: null, // Create a tile and use OSM source
|
||
mapView: null, // Sets the initial view
|
||
}
|
||
|
||
// Add a feature for every Node and change style if connection status changes
|
||
function updateMapMarkers(selectedMesh) {
|
||
if ((xxmap != null) && (xxmap.map == null)) { try { loadmap(); } catch (ex) { console.error('loadmap() exception', ex); } }
|
||
if (xxmap == null) return;
|
||
var boundingBox = null;
|
||
for (var i in nodes) {
|
||
try {
|
||
var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
|
||
if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
|
||
var lat = loc[0], lon = loc[1], type = loc[2];
|
||
if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
|
||
if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
|
||
} else {
|
||
if (feature) { xxmap.markersSource.removeFeature(feature); }
|
||
}
|
||
} catch (ex) { console.error('updateMapMarkers() exception', ex, JSON.stringify(nodes[i])); }
|
||
}
|
||
return boundingBox;
|
||
}
|
||
|
||
// Show node details on hovering over a feature
|
||
var map_cm_popup = new ol.Overlay({ element: Q('xmap-info-window'), positioning: 'bottom-center', stopEvent: false });
|
||
|
||
// Edit Marker item
|
||
var map_cm_editMarker = { text: "Modify node location", callback: function (obj) { modifyMarkerloc(obj.data); } };
|
||
|
||
// Clear Marker item
|
||
var map_cm_clearMarker = { text: "Remove node location", callback: function (obj) {
|
||
meshserver.send({ action: 'changedevice', nodeid: obj.data.a, userloc: [] }); // Clear the user position marker
|
||
}};
|
||
|
||
// Save Marker item
|
||
var map_cm_saveMarker = { text: "Save node location", callback: function (obj) { saveMarkerloc(obj.data); } };
|
||
|
||
// Build a context menu for a feature
|
||
var map_cm_nodemenu_items = [
|
||
{ text: "General information", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 10); } } },
|
||
{ text: "Desktop", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 11); } } },
|
||
{ text: "Terminal", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 12); } } },
|
||
{ text: "Intel® AMT", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 14); } } },
|
||
'-',
|
||
{ text: 'Zoom-in to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 19); } },
|
||
{ text: 'Zoom-out to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 2); } }
|
||
];
|
||
|
||
// Context menu for clicks other than on feature
|
||
var contextmenu_items = [
|
||
{ text: 'Refresh', callback: function () { refreshMap(true, true); } },
|
||
{ text: 'Zoom to fit extent', callback: function () { zoomToFitExtent(); } },
|
||
{ text: 'Center map here', callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
|
||
{ text: 'Place node here', callback: function(obj) { placeNode(obj.coordinate); } }
|
||
];
|
||
|
||
function stringToIntHash(str) {
|
||
var hash = 0, i;
|
||
for (i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
|
||
return hash;
|
||
};
|
||
|
||
// Get the lat/lon from a node
|
||
function map_parseNodeLoc(node) {
|
||
var loc = null, t = 0;
|
||
if (node.iploc) { loc = node.iploc; t = 1; }
|
||
if (node.wifiloc) { loc = node.wifiloc; t = 2; }
|
||
if (node.gpsloc) { loc = node.gpsloc; t = 3; }
|
||
if (node.userloc) { loc = node.userloc; t = 4; }
|
||
if ((loc == null) || (typeof loc != 'string')) return null;
|
||
loc = loc.split(',');
|
||
if (t == 1) {
|
||
// If this is IP location, randomize the position a little.
|
||
return [ parseFloat(loc[0]) + (stringToIntHash(node._id.substring(0, 20)) / 100000000000), parseFloat(loc[1]) + (stringToIntHash(node._id.substring(20)) / 100000000000), t ];
|
||
} else {
|
||
// Return the real position
|
||
return [ parseFloat(loc[0]), parseFloat(loc[1]), t ];
|
||
}
|
||
}
|
||
|
||
// Load the entire map
|
||
function loadmap() {
|
||
if (xxmap == null) return;
|
||
if ((features & 0x8000) == 0) { QV('viewselectmapoption', false); QV('devViewButton4', false); xxmap = null; return; } // Geolocation not supported
|
||
try {
|
||
// Initialize a Source Vector
|
||
xxmap.markersSource = new ol.source.Vector();
|
||
|
||
xxmap.markersLayer = new ol.layer.Vector({
|
||
source: xxmap.markersSource
|
||
});
|
||
|
||
// Create a tile and use OSM source
|
||
xxmap.mapLayer = new ol.layer.Tile({ source: new ol.source.OSM() });
|
||
|
||
xxmap.mapView = new ol.View({ // Set the initial view
|
||
center: ol.proj.transform([0, 0], 'EPSG:4326', 'EPSG:3857'),
|
||
zoom: 2,
|
||
minZoom: 2,
|
||
maxZoom: 20,
|
||
extent: ol.proj.transformExtent([-100000, -69.55, 100000, 69.55], 'EPSG:4326', 'EPSG:3857')
|
||
});
|
||
|
||
xxmap.map = new ol.Map({
|
||
target: 'xdevicesmap',
|
||
layers: [xxmap.mapLayer, xxmap.markersLayer],
|
||
view: xxmap.mapView
|
||
});
|
||
|
||
xxmap.map.addOverlay(map_cm_popup);
|
||
|
||
// Goto information tab if a user clicks on a feature
|
||
xxmap.map.on('click', function(evt) {
|
||
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
|
||
if (feature) {
|
||
var nodeid = feature.getId();
|
||
if (nodeid != null) { gotoDevice(nodeid, 10); } // Goto general info tab
|
||
else { // For pointer
|
||
var nodeFeatgoto = getCorrespondingFeature(feature); gotoDevice(nodeFeatgoto.getId(), 10);
|
||
}
|
||
}
|
||
});
|
||
|
||
// On hover feature show the name of the node. Also add pointer style
|
||
xxmap.map.on('pointermove', function(evt) {
|
||
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
|
||
if (feature) {
|
||
xxmap.map.getTargetElement().style.cursor = 'pointer';
|
||
var coord = feature.getGeometry().getCoordinates();
|
||
// map_cm_popup.setPosition(evt.coordinate);
|
||
map_cm_popup.setPosition(coord);
|
||
var featid = feature.getId();
|
||
if (featid) {
|
||
QH('xmap-info-window', feature.get('name'));
|
||
} else {
|
||
var nodeFeat = getCorrespondingFeature(feature); // Return the node feature associated to pointer.
|
||
QH('xmap-info-window', nodeFeat.get('name'));
|
||
}
|
||
} else {
|
||
xxmap.map.getTargetElement().style.cursor = '';
|
||
QH('xmap-info-window', '');
|
||
}
|
||
});
|
||
|
||
// Initialize context menu for openlayers
|
||
var contextmenu = new ContextMenu({
|
||
width: 160,
|
||
defaultItems: false, // defaultItems are Zoom In/Zoom Out
|
||
items: contextmenu_items
|
||
});
|
||
|
||
// On right click open the context menu
|
||
contextmenu.on("open", function (evt) {
|
||
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(ft, l){ return ft; });
|
||
xxmap.contextmenu.clear(); //Clear the context menu
|
||
if (feature) {
|
||
var featId = feature.getId();
|
||
if (featId) { addContextMenuItems(feature); } // Node feature will have an id
|
||
else { // If the feature is a pointer, Get its corresponding Node feature
|
||
var nodeFeature = getCorrespondingFeature(feature); //return the node feature associated to pointer.
|
||
if (nodeFeature) { addContextMenuItems(nodeFeature); }
|
||
else{ xxmap.contextmenu.extend(contextmenu_items); }
|
||
}
|
||
}
|
||
else { xxmap.contextmenu.extend(contextmenu_items); }
|
||
});
|
||
if (xxmap.contextmenu == null) { xxmap.contextmenu = contextmenu; }
|
||
xxmap.map.addControl(xxmap.contextmenu);
|
||
//addMeshOptions(); // Adds Mesh names to mesh dropdown
|
||
} catch (ex) {
|
||
console.log(ex);
|
||
QV('viewselectmapoption', false);
|
||
QV('devViewButton4', false);
|
||
xxmap = null;
|
||
}
|
||
}
|
||
|
||
// Add feature on to Map for a Node
|
||
function addFeature(node, lat, lon) {
|
||
var existingfeature = getModifiedFeature(node._id); // Check if Corresponding feature was Modified ( Modifed feature are in active interactions list)
|
||
if (existingfeature) { xxmap.markersSource.addFeature(existingfeature); } // Add that existing feature
|
||
else { // Add new feature for this node
|
||
if (!lat && !lon) { var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1]; }
|
||
|
||
// Fix the longiture and send an event to patch the db to correct coordinate format. It will cause second unnecessary updateFeature on this node to the map.
|
||
if (lon > 180) { lon = 180 - lon; meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: [ lat, lon ] }); }
|
||
|
||
if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
|
||
var feature = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.transform([lon, lat], 'EPSG:4326','EPSG:3857')), name: node.name, status: node.conn, lat: lat, lon: lon });
|
||
feature.setId(node._id); // Set id for the device as nodeid
|
||
feature.setStyle(markerStyle(node));
|
||
xxmap.markersSource.addFeature(feature); // Add the feature to Marker Source
|
||
}
|
||
}
|
||
}
|
||
|
||
// Removing any feature from map
|
||
function removeFeature(node) {
|
||
var feature = xxmap.markersSource.getFeatureById(node._id);
|
||
if (feature) { xxmap.markersSource.removeFeature(feature); }
|
||
}
|
||
|
||
// Update feature
|
||
function updateFeature(node, feature) {
|
||
if (node.conn != feature.get('status') ) { // Update status if changed
|
||
feature.set('status',node.conn)
|
||
feature.setStyle(markerStyle(node));
|
||
}
|
||
|
||
// Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
|
||
var loc = map_parseNodeLoc(node);
|
||
if (loc != null) {
|
||
var lat = loc[0], lon = loc[1];
|
||
if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
|
||
feature.set('lat', lat); feature.set('lon', lon);
|
||
var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');
|
||
feature.getGeometry().setCoordinates(modifiedCoordinates);
|
||
}
|
||
}
|
||
|
||
if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
|
||
}
|
||
|
||
// Enable dragging of a marker after edit option is clicked in context menu
|
||
function modifyMarkerloc(ft){
|
||
var featid = ft.getId();
|
||
if (featid) {
|
||
ft.setStyle(markerStyle(getNodeFromId(ft.a), 4)); // Switch to a user marker
|
||
if ( !getActiveInteractions(ft)) {
|
||
var dragInteration = new ol.interaction.Modify({
|
||
features: new ol.Collection([ft]),
|
||
pixelTolerance: 10
|
||
});
|
||
xxmap.activeInteractions.push({ featureid: featid, feature:ft, interaction: dragInteration }); // Also keep track of Interactions
|
||
xxmap.map.addInteraction(dragInteration);
|
||
}
|
||
}
|
||
}
|
||
|
||
// This will be called when save location option is clicked in context menu
|
||
function saveMarkerloc(ft){
|
||
var featid = ft.getId()
|
||
if (featid) {
|
||
var actInteraction = getActiveInteractions(ft);
|
||
if (actInteraction) { // Check if the interaction exists
|
||
xxmap.map.removeInteraction(actInteraction); //Clear Interaction for that node
|
||
removeInteraction(featid);
|
||
var coord = ft.getGeometry().getCoordinates();
|
||
var v = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
|
||
if (v[0] > 180) { v[0] = 180 - v[0]; }
|
||
var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
|
||
meshserver.send({ action: 'changedevice', nodeid: featid, userloc: vx }); // Send them to server to save changes
|
||
}
|
||
}
|
||
}
|
||
|
||
// Style the Markers
|
||
function markerStyle(node, type) {
|
||
if (type == null) {
|
||
type = 0;
|
||
if (node.iploc) { type = 1; }
|
||
if (node.wifiloc) { type = 2; }
|
||
if (node.gpsloc) { type = 3; }
|
||
if (node.userloc) { type = 4; }
|
||
}
|
||
var types = ['', '-ip','-wifi','-gps','-user'];
|
||
var color = connStateColor(node);
|
||
var style = new ol.style.Style({
|
||
image: new ol.style.Icon({ color: color, anchor: [0.5, 1], src: 'images/mapmarker' + types[type] + '.png' })
|
||
//stroke: new ol.style.Stroke({ color: '#000', width: 20 })
|
||
//text: new ol.style.Text({ text: 'bob!', textAlign: 'right', offsetX: -10, fill: new ol.style.Fill({ color: '#000' }), stroke: new ol.style.Stroke({ color: '#fff', width: 2 }) })
|
||
});
|
||
|
||
/*
|
||
deviceMark.setStyle(new ol.style.Style({
|
||
text: new ol.style.Text({
|
||
//font: '12px helvetica,sans-serif',
|
||
text: currentNode.name,
|
||
textAlign: 'right',
|
||
offsetX: -10,
|
||
fill: new ol.style.Fill({ color: '#000' }),
|
||
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
|
||
}),
|
||
image: new ol.style.Icon(({ color: [113, 140, 0], src: 'images/dot.png' })) }));
|
||
*/
|
||
|
||
return [ style ];
|
||
}
|
||
|
||
// TODO: Add more connection status types. Currently we only change color if connection status changes
|
||
function connStateColor(nodeConn){
|
||
if (nodeConn.conn == 1 || nodeConn.conn == 3 || nodeConn.conn == 5) { return '#00ffdd'; } // Green for connected devices
|
||
return '#C70039'; // Red if the Agent is not connected
|
||
}
|
||
|
||
// Add save/edit option to context menu
|
||
function addContextMenuItems(feature) {
|
||
if (getActiveInteractions(feature)) { // If this feature is modified then display save option in contextmenu
|
||
map_cm_saveMarker.data = feature;
|
||
xxmap.contextmenu.push(map_cm_saveMarker);
|
||
} else {
|
||
map_cm_editMarker.data = feature;
|
||
xxmap.contextmenu.push(map_cm_editMarker);
|
||
var node = getNodeFromId(feature.a);
|
||
if (node.userloc) {
|
||
map_cm_clearMarker.data = feature;
|
||
xxmap.contextmenu.push(map_cm_clearMarker);
|
||
}
|
||
}
|
||
map_cm_nodemenu_items.forEach(function (item){
|
||
if (item.text == 'Zoom-in to extent' || item.text == 'Zoom-out to extent') { item.data = feature; }
|
||
else { if (item != "-") { item.data = feature.getId(); } }
|
||
});
|
||
xxmap.contextmenu.extend(map_cm_nodemenu_items);
|
||
}
|
||
|
||
// Return a active Interaction if it exists in activeInteractions list
|
||
function getActiveInteractions(feature) {
|
||
var featid = feature.getId();
|
||
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
|
||
if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].interaction; }
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// Return Modified feature based on Id
|
||
function getModifiedFeature(featid) {
|
||
if (featid) {
|
||
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
|
||
if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].feature; }
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// Remove Interaction
|
||
function removeInteraction(ftid) {
|
||
var index = -1;
|
||
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
|
||
if (xxmap.activeInteractions[i].featureid === ftid) { index = i; break; }
|
||
}
|
||
if (index >= 0) { xxmap.activeInteractions.splice(index, 1); }
|
||
}
|
||
|
||
// Check if pointer coordinates are equal to features and return node feature
|
||
function getCorrespondingFeature(pointerFeat) {
|
||
var pointerCoord = pointerFeat.getGeometry().getCoordinates();
|
||
for (var i = 0; i < xxmap.activeInteractions.length ; i++) {
|
||
var modifiedFeatures = xxmap.activeInteractions[i].feature;
|
||
var fearCoord = modifiedFeatures.getGeometry().getCoordinates();
|
||
if (fearCoord[0].toFixed(5) == pointerCoord[0].toFixed(5) && fearCoord[1].toFixed(5) == pointerCoord[1].toFixed(5) ) { return modifiedFeatures; }
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// Refresh the map and clear list
|
||
function refreshMap(reset, rebound){
|
||
if (reset) {
|
||
xxmap.map.setTarget(null);
|
||
xxmap.map = null;
|
||
xxmap.markersSource = null;
|
||
xxmap.mapView = null;
|
||
xxmap.mapLayer = null;
|
||
xxmap.activeInteractions = []; // Clear Active Interaction list
|
||
}
|
||
//clearMeshOptions();
|
||
//onSelectMeshChange();
|
||
var box = updateMapMarkers();
|
||
if ((box != null) && (rebound || (box[4] == 1))) {
|
||
var clat = (box[0] + box[2]) / 2;
|
||
var clon = (box[1] + box[3]) / 2;
|
||
var cscale = Math.max(Math.abs(box[0] - box[2]), Math.abs(box[1] - box[3]));
|
||
var view = xxmap.map.getView();
|
||
view.setCenter(ol.proj.transform([clon, clat], 'EPSG:4326', 'EPSG:3857'));
|
||
var i = 360, j = -2;
|
||
while (i > cscale) { j++; i = i / 2; }
|
||
view.setZoom(j);
|
||
}
|
||
}
|
||
|
||
// Called When Place a node option is clicked from context menu
|
||
function placeNode(coords) {
|
||
if (xxdialogMode) return;
|
||
var x = '<div style=margin-bottom:6px><label for=selectnode-search>Search</label>  <input type=text placeholder="Device name" id="selectnode-search" onchange=onPlaceNodeInputChange() onkeyup=onPlaceNodeInputChange() autocomplete=off style=width:120px></div><div id=placenode style="height:254px;overflow-y:auto;width:100%;margin:12px 1px 4px 1px;"><div id=noNodesMapPlace style=text-align:center;width:100%;display:none>No devices found.</div>';
|
||
for (var i in nodes) {
|
||
x += '<div class=noselect id=' + nodes[i]._id + '-rowid onclick=selectNodeToPlace(event,\''+ nodes[i]._id +'\') style=background-color:lightgray;margin-bottom:4px;border-radius:2px><input name=PlaceMapDeviceCheckbox id=' + nodes[i]._id + '-checkid type=checkbox style=width:16px;display:inline />';
|
||
x += '<div class=j' + nodes[i].icon + ' style=width:16px;height:16px;margin-top:2px;margin-right:4px;display:inline-block></div><div style=width:16px;display:inline>' + nodes[i].name + '</div></div>';
|
||
}
|
||
setDialogMode(2, "Select a node to place", 3, placeNodeEx, x + '</div>', coords);
|
||
onPlaceNodeInputChange();
|
||
}
|
||
|
||
function placeNodeEx(button, coords) {
|
||
var elements = document.getElementsByName("PlaceMapDeviceCheckbox");
|
||
for (var i in elements) {
|
||
if (elements[i].checked) {
|
||
var node = getNodeFromId(elements[i].id.substring(0, elements[i].id.length - 8));
|
||
if (node) {
|
||
var feature = xxmap.markersSource.getFeatureById(i);
|
||
var v = ol.proj.transform(coords, 'EPSG:3857', 'EPSG:4326');
|
||
var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
|
||
if (feature) {
|
||
feature.getGeometry().setCoordinates(coords);
|
||
var activeInteraction = getActiveInteractions(feature);
|
||
if (activeInteraction) {
|
||
saveMarkerloc(feature);
|
||
} else { // If this feature is not saved after its location is changed, then send updated coords to server.
|
||
meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // Send them to server to save changes
|
||
}
|
||
} else {
|
||
meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // This Node is not yet added to maps.
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Called when the user changes the search box
|
||
function onPlaceNodeInputChange() {
|
||
updatePlaceNodeTable(Q('selectnode-search').value.trim().toLowerCase());
|
||
}
|
||
|
||
// Update the list of devices in the "place on map" table
|
||
function updatePlaceNodeTable(inputSearch) {
|
||
var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), count = 0;
|
||
for (var i in nodes) {
|
||
var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.indexOf(inputSearch) >= 0));
|
||
if (visible) { count++; }
|
||
QV(nodes[i]._id + '-rowid', visible);
|
||
}
|
||
QV('noNodesMapPlace', count == 0);
|
||
/*
|
||
console.log(selected);
|
||
for (var i in nodes) {
|
||
if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.toLowerCase().indexOf(inputSearch) >= 0)) {
|
||
console.log(selected.indexOf(nodes[i]._id));
|
||
x += '<div class=noselect id=' + nodes[i]._id + '-rowid onclick=selectNodeToPlace(event,\''+ nodes[i]._id +'\') style=background-color:lightgray;margin-bottom:4px;border-radius:2px><input name=PlaceMapDeviceCheckbox id=' + nodes[i]._id + '-checkid type=checkbox style=width:16px;display:inline ' + ((selected.indexOf(nodes[i]._id) >= 0)?'checked':'') + ' />';
|
||
x += '<div class=j' + nodes[i].icon + ' style=width:16px;height:16px;margin-top:2px;margin-right:4px;display:inline-block></div><div style=width:16px;display:inline>' + nodes[i].name + '</div></div>';
|
||
}
|
||
}
|
||
if (x == '') { x = '<div style=text-align:center;width:100%>No devices found.</div>'; }
|
||
QH('placenode', '');
|
||
*/
|
||
}
|
||
|
||
// Called when a user clicks on a device to toggle selection for placement on map.
|
||
function selectNodeToPlace(e, id) {
|
||
// Toggle checkbox if needed
|
||
if (e.target.name != 'PlaceMapDeviceCheckbox') { var inputElement = Q(id + '-checkid'); inputElement.checked = !inputElement.checked; }
|
||
|
||
// Check button state
|
||
var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), checkcount = 0;
|
||
for (var i in elements) { if (elements[i].checked) checkcount++; }
|
||
QE('idx_dlgOkButton', checkcount > 0);
|
||
}
|
||
|
||
// Add option for available meshes in mesh Dropdown
|
||
function addMeshOptions(addMeshid, meshName) {
|
||
/*
|
||
var meshOptions = Q('select-mesh');
|
||
if (addMeshid && meshName) {
|
||
var option = document.createElement('option');
|
||
option.value =addMeshid;
|
||
option.text = meshName;
|
||
meshOptions.add(option); // Add specific option
|
||
}
|
||
else {
|
||
for (var i in meshes) { // Add all options
|
||
var option = document.createElement('option');
|
||
option.value = i;
|
||
option.text = meshes[i].name;
|
||
meshOptions.add(option);
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
|
||
// Remove/Modify options in Mesh dropdown (if modMeshname is defined then Modify else Remove)
|
||
function meshOptionRmvMod(delMeshid, modMeshname){
|
||
/*
|
||
var meshOptions = Q('select-mesh');
|
||
if (delMeshid) {
|
||
var index=-1;
|
||
for (var i = 1; i < meshOptions.options.length; i++) {
|
||
if (meshOptions[i].value === delMeshid) { index=i; }
|
||
}
|
||
if (index > 0) {
|
||
if (modMeshname) {
|
||
meshOptions[index].innerHTML=modMeshname; // If Mesh name is Modified
|
||
}
|
||
else { meshOptions.remove(index); }
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
|
||
//Check if there is any mesh created
|
||
function meshExists() {
|
||
for (var i in meshes) { if (meshes[i]) { return true; } }
|
||
return false;
|
||
}
|
||
|
||
// Reset Mesh dropdown option to 'All' when a current view mesh is deleted.
|
||
function setMeshView(emeshid) {
|
||
var selectMeshElement=Q("select-mesh");
|
||
var selectedIndex = selectMeshElement.selectedIndex;
|
||
if (selectMeshElement[selectedIndex].value == emeshid) { selectMeshElement[0].selected = true; onSelectMeshChange(); }
|
||
}
|
||
|
||
// Clear all mesh options except 'All'
|
||
function clearMeshOptions() {
|
||
/*
|
||
var meshOptions=Q('select-mesh');
|
||
for(var i = meshOptions.options.length - 1 ; i > 0 ; i--) { meshOptions.remove(i); }
|
||
*/
|
||
}
|
||
|
||
// Make a http get call- Replace this with AJAX get if jquery is used
|
||
function getSearchLocation() {
|
||
try {
|
||
var searchdata = Q('mapSearchLocation').value.trim();
|
||
if (searchdata.length > 0) {
|
||
var xmlhttp = new XMLHttpRequest(); // Compatible with Chrome, Opera, Safari, IE7+, Firefox.
|
||
xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { formatSearchData(xmlhttp.responseText); } }
|
||
xmlhttp.open("GET", 'https://nominatim.openstreetmap.org/search?q=' + searchdata + '&format=json', true); // Get request
|
||
xmlhttp.send();
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
// Format data recieved from nominatim API and display it on content window
|
||
function formatSearchData(data) {
|
||
try {
|
||
QH('xmapSearchResults','');
|
||
var dataInfo = JSON.parse(data), count = 0, x = '<div style="overflow-y:auto;width:100%;max-height:240px">';
|
||
for (var i = 0; i < dataInfo.length; i++) {
|
||
if (dataInfo[i].display_name && dataInfo[i].boundingbox[0] && dataInfo[i].boundingbox[1] && dataInfo[i].boundingbox[2] && dataInfo[i].boundingbox[3]) {
|
||
count++;
|
||
var color = (i % 2 == 0)?'F5F5F5':'EBEBEB';
|
||
x += '<div style=cursor:pointer;padding:5px;background-color:#' + color + ' onclick=mapGotoSelectedLocation(this)><div>' + dataInfo[i].display_name + '</div><div style=display:none>' + dataInfo[i].boundingbox[0] + '!#!' + dataInfo[i].boundingbox[1] + '!#!' + dataInfo[i].boundingbox[2] + '!#!' + dataInfo[i].boundingbox[3] + '</div></div>';
|
||
}
|
||
}
|
||
x += '</div>';
|
||
if (count == 1) {
|
||
// If only one result is returned then zoom to that location
|
||
var extent = [ parseFloat(dataInfo[0].boundingbox[2]), parseFloat(dataInfo[0].boundingbox[0]), parseFloat(dataInfo[0].boundingbox[3]), parseFloat(dataInfo[0].boundingbox[1]) ];
|
||
zoomToExtent(extent);
|
||
} else {
|
||
if (count == 0) { x = '<div style=width:200px>No location found.<div>'; }
|
||
QV('xmapSearchResultsDlg', true);
|
||
}
|
||
QH('xmapSearchResults', x);
|
||
}
|
||
catch (e) {}
|
||
}
|
||
|
||
// Zoom into the bounding box
|
||
function mapGotoSelectedLocation(obj) {
|
||
var objchildren = obj.children;
|
||
var boundingBox = objchildren[1].innerHTML.split('!#!');
|
||
var extent = [parseFloat(boundingBox[2]), parseFloat(boundingBox[0]), parseFloat(boundingBox[3]), parseFloat(boundingBox[1])];
|
||
//Q('search-location').value = objchildren[0].innerHTML;
|
||
zoomToExtent(extent);
|
||
mapCloseSearchWindow();
|
||
}
|
||
|
||
// Close the search window
|
||
function mapCloseSearchWindow() {
|
||
QH('xmapSearchResults', '');
|
||
QV('xmapSearchResultsDlg', false);
|
||
}
|
||
|
||
// Zoom to specific cordinates
|
||
function zoomToLocation(coordinates, zoomVal) {
|
||
var view = xxmap.map.getView();
|
||
view.setCenter(coordinates);
|
||
view.setZoom(zoomVal);
|
||
}
|
||
|
||
function zoomToFitExtent() {
|
||
var features = xxmap.markersSource.getFeatures();
|
||
if (features.length > 0) {
|
||
var extent = xxmap.markersSource.getExtent();
|
||
xxmap.map.getView().fit(extent, xxmap.map.getSize());
|
||
}
|
||
}
|
||
|
||
function zoomToExtent(extent){
|
||
var boundingExtent = ol.proj.transformExtent(extent, ol.proj.get('EPSG:4326'), ol.proj.get('EPSG:3857'));
|
||
xxmap.map.getView().fit(boundingExtent, xxmap.map.getSize());
|
||
}
|
||
|
||
|
||
//
|
||
// MY DEVICE
|
||
//
|
||
|
||
function refreshDevice(nodeid) {
|
||
if (!currentNode || currentNode._id != nodeid) return;
|
||
gotoDevice(nodeid, xxcurrentView, true);
|
||
}
|
||
|
||
function getNodeRights(nodeid) {
|
||
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
|
||
return mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
}
|
||
|
||
var currentNode;
|
||
var powerTimelineNode = null;
|
||
var powerTimelineReq = null;
|
||
var powerTimelineUpdate = null;
|
||
var powerTimeline = null;
|
||
function getCurrentNode() { return currentNode; };
|
||
function gotoDevice(nodeid, panel, refresh, event) {
|
||
|
||
// Check if we are allowed to create a new device group
|
||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "New Device Group", 1, null, "Unable to create a new device group until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||
|
||
if (event && (event.shiftKey == true)) {
|
||
// Open the device in a different tab
|
||
window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=10&hide=16', 'meshcentral:' + nodeid);
|
||
return;
|
||
}
|
||
|
||
//disconnectAllKvmFunction();
|
||
var node = getNodeFromId(nodeid);
|
||
var mesh = meshes[node.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
if (!currentNode || currentNode._id != node._id || refresh == true) {
|
||
currentNode = node;
|
||
|
||
// Add node name
|
||
var nname = EscapeHtml(node.name);
|
||
if (nname.length == 0) { nname = '<i>None</i>'; }
|
||
if ((meshrights & 4) != 0) { nname = '<span title="Click here to edit the server-side device name" onclick=showEditNodeValueDialog(0) style=cursor:pointer>' + nname + ' <img class=hoverButton width=10 height=10 src="images/link5.png" /></span>'; }
|
||
QH('p10deviceName', nname);
|
||
QH('p11deviceName', nname);
|
||
QH('p12deviceName', nname);
|
||
QH('p13deviceName', nname);
|
||
QH('p14deviceName', nname);
|
||
QH('p15deviceName', 'Console - ' + nname);
|
||
QH('p16deviceName', nname);
|
||
|
||
// Node attributes
|
||
var x = '<table style=width:100%>';
|
||
|
||
// Attribute: Mesh
|
||
x += addDeviceAttribute('<span title="The name of the device group this computer belong to.">Group</span>', '<a title="The name of the device group this computer belong to" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
|
||
|
||
// Attribute: Name
|
||
if ((node.rname != null) && (node.name != node.rname)) { x += addDeviceAttribute('<span title="The name of this computer as set in the operating system">Name</span>', '<span title="The name of this computer as set in the operating system">' + EscapeHtml(node.rname) + '</span>'); }
|
||
|
||
// Attribute: Host
|
||
if ((features & 1) == 0) { // If not WAN-only, local hostname is in use
|
||
if ((meshrights & 4) != 0) {
|
||
if (node.host) {
|
||
x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
|
||
} else {
|
||
x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>None</i></span>');
|
||
}
|
||
} else {
|
||
x += addDeviceAttribute('Hostname', EscapeHtml(node.host));
|
||
}
|
||
}
|
||
|
||
// Attribute: Description
|
||
var description = node.desc?EscapeHtml(node.desc):"<i>None</i>";
|
||
if ((meshrights & 4) != 0) {
|
||
x += addDeviceAttribute('Description', '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + ' <img class=hoverButton width=10 height=10 src="images/link5.png" /></span>');
|
||
} else {
|
||
x += addDeviceAttribute('Description', description);
|
||
}
|
||
|
||
// Attribute: Mesh Agent
|
||
var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'OSX 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'OSX 64bit', 'ChromeOS', 'Linux Poky x86-64bit', 'Linux NoKVM x86-32bit', 'Linux NoKVM x86-64bit', 'Windows MinCore console', 'Windows MinCore service', 'NodeJS', 'ARM-Linaro', 'ARMv6l / ARMv7l' ];
|
||
if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
|
||
var str = '';
|
||
if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
|
||
if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
|
||
x += addDeviceAttribute('Mesh Agent', str);
|
||
}
|
||
|
||
// Attribute: Intel AMT
|
||
if (node.intelamt != null) {
|
||
var str = '';
|
||
var provisioningStates = { 0: 'Not Activated (Pre)', 1: 'Not Activated (In)', 2: 'Activated' };
|
||
if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>Unknown State</i>, v' + node.intelamt.ver; } else
|
||
|
||
if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>Activated</i>'; }
|
||
else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>Unknown Version & State</i>'; }
|
||
else {
|
||
str += provisioningStates[node.intelamt.state];
|
||
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { str += ' <span title="Intel AMT is activated in Client Control Mode">CCM</span>'; } else if (node.intelamt.flags & 4) { str += ' <span title="Intel AMT is activated in Admin Control Mode">ACM</span>'; } }
|
||
str += (', v' + node.intelamt.ver);
|
||
}
|
||
|
||
if (node.intelamt.tls == 1) { str += ', <span title="Intel AMT is setup with TLS network security">TLS</span>'; }
|
||
if (node.intelamt.state == 2) {
|
||
if (node.intelamt.user == null || node.intelamt.user == '') {
|
||
if ((meshrights & 4) != 0) {
|
||
str += ', <i style=color:#FF0000;cursor:pointer title="Edit Intel® AMT credentials" onclick=editDeviceAmtSettings("' + node._id + '")>No Credentials</i>';
|
||
} else {
|
||
str += ', <i style=color:#FF0000>No Credentials</i>';
|
||
}
|
||
}
|
||
str += ' ';
|
||
if ((meshrights & 4) != 0) {
|
||
str += '<img src=images/link4.png height=10 width=10 title="Edit Intel® AMT credentials" style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
|
||
}
|
||
}
|
||
x += addDeviceAttribute('Intel® AMT', str);
|
||
}
|
||
|
||
// Attribute: Mesh Agent Tag
|
||
if ((node.agent != null) && (node.agent.tag != null) && (node.agent.tag != 'mailto:')) {
|
||
var tag = EscapeHtml(node.agent.tag);
|
||
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
|
||
x += addDeviceAttribute('Agent Tag', tag);
|
||
}
|
||
|
||
// Attribute: Intel AMT
|
||
//if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel® AMT', node.intelamt.user); }
|
||
|
||
// Operating system description
|
||
if (node.osdesc) { x += addDeviceAttribute('Operating System', node.osdesc); }
|
||
|
||
// Active Users
|
||
if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute('Active User' + ((node.users.length > 1)?'s':''), node.users.join(', ')); }
|
||
|
||
// Attribute: Connectivity (Only show this if more than just the agent is connected).
|
||
var connectivity = node.conn;
|
||
if (connectivity && connectivity > 1) {
|
||
var cstate = [];
|
||
if ((node.conn & 1) != 0) cstate.push('<span title="Mesh agent is connected and ready for use.">Mesh Agent</span>');
|
||
if ((node.conn & 2) != 0) cstate.push('<span title="Intel® AMT CIRA is connected and ready for use.">Intel® AMT CIRA</span>');
|
||
else if ((node.conn & 4) != 0) cstate.push('<span title="Intel® AMT is routable and ready for use.">Intel® AMT</span>');
|
||
if ((node.conn & 8) != 0) cstate.push('<span title="Mesh agent is reachable using another agent as relay.">Mesh Relay</span>');
|
||
x += addDeviceAttribute('Connectivity', cstate.join(', '));
|
||
}
|
||
|
||
// Node grouping tags
|
||
var groupingTags = '<i>None</i>';
|
||
if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span style="background-color:lightgray;padding:3px;margin-right:4px;border-radius:5px">' + node.tags[i] + '</span>'; } }
|
||
x += addDeviceAttribute('Tags', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton width=10 height=10 src="images/link5.png" /></span>');
|
||
|
||
x += '</table><br />';
|
||
// Show action button, only show if we have permissions 4, 8, 64
|
||
if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
|
||
x += '<input type=button value=Notes title="View notes about this device" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
|
||
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="Display a text message of the remote device" onclick=deviceToastFunction() />'; }
|
||
QH('p10html', x);
|
||
|
||
// Show node last 7 days timeline
|
||
masterUpdate(256);
|
||
|
||
// Show bottom buttons
|
||
x = '<div style=float:right;font-size:x-small>';
|
||
if ((meshrights & 4) != 0) {
|
||
// TODO: Show change group only if there is another mesh of the same type.
|
||
x += ' <a style=cursor:pointer onclick=p10showChangeGroupDialog(["' + node._id + '"]) title="Move this device to a different device group">Change Group</a>';
|
||
x += ' <a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '") title="Remove this device">Delete Device</a>';
|
||
}
|
||
x += '</div><div style=font-size:x-small>';
|
||
if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '") title="Show device network interface information">Interfaces</a> ';
|
||
if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '") title="Show device locations information">Location</a> ';
|
||
if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a style=cursor:pointer onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a> ';
|
||
|
||
// RDP link, show this link only of the remote machine is Windows.
|
||
if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
|
||
if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","RDP2",3389) title="Requires Microsoft ClickOnce support in your browser.">RDP</a> '; }
|
||
if (node.agent.id > 4) {
|
||
x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","PSSH",22) title="Requires Microsoft ClickOnce support in your browser.">Putty</a> ';
|
||
x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","WSCP",22) title="Requires Microsoft ClickOnce support in your browser.">WinSCP</a> ';
|
||
}
|
||
}
|
||
x += '</div><br>'
|
||
|
||
QH('p10html3', x);
|
||
|
||
// Set the node power state
|
||
var powerstate = PowerStateStr(node.state);
|
||
//if (node.state == 0) { powerstate = 'Unknown State'; }
|
||
if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Agent connected">Agent connected</span>'; }
|
||
if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT connected">Intel® AMT connected</span>'; }
|
||
else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT detected">Intel® AMT detected</span>'; }
|
||
if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>Last seen:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>'; }
|
||
QH('MainComputerState', powerstate);
|
||
|
||
// Set the node icon
|
||
Q('MainComputerImage').setAttribute("src", "images/icons200-" + node.icon + "-1.jpg");
|
||
Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
|
||
|
||
// Check if we have terminal and file access
|
||
var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
|
||
var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
|
||
var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0));
|
||
|
||
// Setup/Refresh the desktop tab
|
||
if (terminalAccess) { setupTerminal(); }
|
||
if (fileAccess) { setupFiles(); }
|
||
var consoleRights = ((meshrights & 16) != 0);
|
||
if (consoleRights) { setupConsole(); } else { if (panel == 15) { panel = 10; } }
|
||
|
||
// Show or hide the tabs
|
||
// mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
|
||
// node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
|
||
QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
|
||
QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
|
||
QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
|
||
QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8) && amtAccess);
|
||
QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
|
||
QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
|
||
QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
|
||
|
||
// Setup/Refresh Intel AMT tab
|
||
var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
|
||
if ((amtFrameNode != null) && (amtFrameNode._id != currentNode._id)) { Q('p14iframe').contentWindow.disconnect(); }
|
||
var online = ((node.conn & 6) != 0)?true:false; // If CIRA (2) or AMT (4) connected, enable Commander
|
||
Q('p14iframe').contentWindow.setConnectionState(online);
|
||
Q('p14iframe').contentWindow.setFrameHeight('650px');
|
||
Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
|
||
|
||
// Display "action" button on desktop/terminal/files
|
||
QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
|
||
QV('termActionsBtn', (meshrights & 72) != 0);
|
||
QV('filesActionsBtn', (meshrights & 72) != 0);
|
||
|
||
// Request the power timeline
|
||
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) {
|
||
QH('p10html2', '');
|
||
powerTimelineReq = currentNode._id;
|
||
meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
|
||
meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
|
||
}
|
||
|
||
// Reset the desktop tools
|
||
QV('DeskTools', false);
|
||
showDeskToolsProcesses();
|
||
|
||
// Ask for device events
|
||
refreshDeviceEvents();
|
||
|
||
// Update the web page title
|
||
if ((currentNode) && (xxcurrentView >= 10) && (xxcurrentView < 20)) { document.title = 'MeshCentral - ' + currentNode.name; } else { document.title = 'MeshCentral'; }
|
||
}
|
||
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
|
||
if (!panel) panel = 10;
|
||
go(panel);
|
||
}
|
||
|
||
function showNotes(readonly, noteid) {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Notes", 2, showNotesEx, '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>Notes can be viewed and changed by other administrators.<span>', noteid);
|
||
meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
|
||
}
|
||
|
||
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
|
||
|
||
function deviceChat() {
|
||
if (xxdialogMode) return;
|
||
var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
window.open(url, 'meshmessenger:' + currentNode._id);
|
||
meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
|
||
}
|
||
|
||
function deviceUrlFunction() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Open Page on Device", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
|
||
}
|
||
|
||
function deviceUrlFunctionEx() {
|
||
meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
|
||
}
|
||
|
||
function deviceToastFunction() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Device Notification", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
|
||
}
|
||
|
||
function deviceToastFunctionEx() {
|
||
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
|
||
}
|
||
|
||
function deviceActionFunction() {
|
||
if (xxdialogMode) return;
|
||
var meshrights = meshes[currentNode.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
var x = "Select an operation to perform on this device.<br /><br />";
|
||
var y = '<select id=d2deviceop style=float:right;width:250px>';
|
||
if ((meshrights & 64) != 0) { y += '<option value=100>Wake-up</option>'; } // Wake-up permission
|
||
if ((meshrights & 8) != 0) { y += '<option value=4>Sleep</option><option value=3>Reset</option><option value=2>Power off</option>'; } // Remote control permission
|
||
y += '</select>';
|
||
x += addHtmlValue('Operation', y);
|
||
setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
|
||
}
|
||
|
||
function deviceActionFunctionEx() {
|
||
var op = Q('d2deviceop').value;
|
||
if (op == 100) {
|
||
// Device wake
|
||
meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
|
||
} else {
|
||
// Power operation
|
||
meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: op });
|
||
}
|
||
}
|
||
|
||
// Called when MeshCommander needs new credentials or updated credentials.
|
||
function updateAmtCredentials(forceDialog) {
|
||
var node = getNodeFromId(currentNode._id);
|
||
if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
|
||
editDeviceAmtSettings(currentNode._id, updateAmtCredentialsEx);
|
||
} else {
|
||
Q('p14iframe').contentWindow.connectButtonfunctionEx();
|
||
}
|
||
}
|
||
|
||
function updateAmtCredentialsEx(button, tag) {
|
||
Q('p14iframe').contentWindow.connectButtonfunctionEx();
|
||
}
|
||
|
||
// Look to see if we need to update the device timeline
|
||
function updateDeviceTimeline() {
|
||
if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
|
||
if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) {
|
||
powerTimelineUpdate = null;
|
||
meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
|
||
meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
|
||
}
|
||
}
|
||
|
||
// Draw device power bars. The bars are 766px wide.
|
||
function drawDeviceTimeline() {
|
||
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19)) return;
|
||
var timeline = null, now = Date.now();
|
||
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
||
|
||
// Calculate when the timeline starts
|
||
var d = new Date();
|
||
d.setHours(0, 0, 0, 0);
|
||
d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
|
||
var timelineStart = d.getTime();
|
||
|
||
// De-compact the timeline
|
||
var timeline2 = [];
|
||
if (timeline != null && timeline.length > 1) {
|
||
timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
|
||
var ct = timeline[1];
|
||
for (var i = 2; i < timeline.length; i += 2) {
|
||
var power = timeline[i], dt = now;
|
||
if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
|
||
timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
|
||
ct = ct + dt;
|
||
}
|
||
}
|
||
|
||
// Draw the timeline
|
||
var x = '', count = 1, date = new Date();
|
||
var totalWidth = Q('masthead').offsetWidth - (160 + 9 + 9 + 14); // Compute the total width of the power bar
|
||
date.setHours(0, 0, 0, 0);
|
||
for (var i = 0; i < 7; i++) {
|
||
var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
|
||
for (var j in timeline2) {
|
||
var block = timeline2[j];
|
||
if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
|
||
var ts = Math.max(start, block[0]);
|
||
var te = Math.min(Math.min(end, block[1]), now);
|
||
var width = Math.round(((te - ts) * totalWidth) / 86400000);
|
||
if (width > 0) {
|
||
var title = powerStateStrings2[block[2]] + ' from ' + new Date(ts).toLocaleTimeString() + ' to ' + new Date(te).toLocaleTimeString() + '.';
|
||
datavalue += '<div title="' + title + '" style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>';
|
||
}
|
||
}
|
||
}
|
||
x += '<tr style=' + (((count % 2) == 0)?'background-color:#DDD':'') + '><td><div> ' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
|
||
++count;
|
||
date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
|
||
}
|
||
QH('p10html2', '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:center;width:150px>Day</th><th scope=col style=text-align:center><img style=float:right;cursor:pointer;padding:3px onclick=p10downloadPowerEvents() title="Download power events" src="images/link4.png" />7 Day Power State</th></tr>' + x + '</tbody></table>');
|
||
}
|
||
|
||
// Download the power events for the current device
|
||
function p10downloadPowerEvents() {
|
||
console.log("devicepowerevents?id=" + currentNode._id);
|
||
fileDownload("devicepowerevents.ashx?id=" + currentNode._id, "powerevents-" + currentNode.name + ".csv");
|
||
}
|
||
|
||
// Return a color for the given power state
|
||
function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'yellow'; }
|
||
|
||
// Return true if the time block is visible within the start/end period
|
||
function isTimeBlockInside(start, end, blockStart, blockEnd) {
|
||
if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
|
||
if ((blockStart > start) && (blockStart < end)) return true;
|
||
if ((blockEnd > start) && (blockEnd < end)) return true;
|
||
return false;
|
||
}
|
||
|
||
function addDeviceAttribute(name, value) { return '<tr><td class=style7 style=width:180px>' + name + '</td><td class=style9 style=max-width:400px;overflow:hidden>' + value + '</td></tr>'; }
|
||
|
||
function editDeviceAmtSettings(nodeid, func) {
|
||
if (xxdialogMode) return;
|
||
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
||
if ((meshrights & 4) == 0) return;
|
||
x += addHtmlValue('Username', '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
||
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
|
||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
|
||
Q('dp10tls').value = node.intelamt.tls;
|
||
validateDeviceAmtSettings();
|
||
}
|
||
|
||
function validateDeviceAmtSettings() {
|
||
QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
|
||
}
|
||
|
||
function editDeviceAmtSettingsEx(button, tag) {
|
||
if (button == 2) {
|
||
// Delete button pressed, remove credentials
|
||
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
|
||
} else {
|
||
// Change Intel AMT credentials
|
||
var amtuser = Q('dp10username').value;
|
||
if (amtuser == '') amtuser = 'admin';
|
||
var amtpass = Q('dp10password').value;
|
||
if (amtpass == '') amtuser = '';
|
||
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
|
||
tag.node.intelamt.user = amtuser;
|
||
tag.node.intelamt.tls = Q('dp10tls').value;
|
||
if (tag.func) { setTimeout(tag.func, 300); }
|
||
}
|
||
}
|
||
|
||
function p10showChangeGroupDialog(nodeids) {
|
||
if (xxdialogMode) return;
|
||
var targetMeshId = null;
|
||
if (nodeids.length == 1) { try { targetMeshId = meshes[getNodeFromId(nodeids[0])]._id; } catch (ex) { } }
|
||
|
||
// List all available alternative groups
|
||
var y = "<select id=p10newGroup style=width:236px>", count = 0;
|
||
for (var i in meshes) {
|
||
var meshrights = meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
if ((meshes[i]._id != targetMeshId) && (meshrights & 4)) { count++; y += "<option value='" + meshes[i]._id + "'>" + meshes[i].name + "</option>"; }
|
||
}
|
||
y += "</select>";
|
||
|
||
if (count > 0) {
|
||
var x = (nodeids.length == 1) ? "Select a new group for this device<br /><br />" : "Select a new group for selected devices<br /><br />";
|
||
x += addHtmlValue('New Device Group', y);
|
||
setDialogMode(2, "Change Group", 3, p10showChangeGroupDialogEx, x, nodeids);
|
||
} else {
|
||
setDialogMode(2, "Change Group", 1, null, "No other device group of same type exists.");
|
||
}
|
||
}
|
||
|
||
function p10showChangeGroupDialogEx(b, nodeids) {
|
||
meshserver.send({ action: 'changeDeviceMesh', nodeids: nodeids, meshid: Q('p10newGroup').value });
|
||
}
|
||
|
||
function p10showDeleteNodeDialog(nodeid) {
|
||
if (xxdialogMode) return;
|
||
var x = "Are you sure you want to delete node \"" + EscapeHtml(currentNode.name) + "\"?<br /><br />";
|
||
x += "<label><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />Confirm</label>";
|
||
setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, x, nodeid);
|
||
p10validateDeleteNodeDialog();
|
||
}
|
||
|
||
function p10validateDeleteNodeDialog() {
|
||
QE('idx_dlgOkButton', Q('p10check').checked);
|
||
}
|
||
|
||
function p10showDeleteNodeDialogEx(buttons, nodeid) {
|
||
meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] });
|
||
}
|
||
|
||
function p10clickOnce(nodeid, protocol, port) {
|
||
meshserver.send({ action: 'getcookie', nodeid: nodeid, tcpport: port, tag: 'clickonce', protocol: protocol });
|
||
}
|
||
|
||
// Show current location
|
||
var d2map = null;
|
||
function p10showNodeLocationDialog() {
|
||
if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return; }
|
||
var markers = [], types = ['iploc', 'wifiloc', 'gpsloc', 'userloc'], boundingBox = null;
|
||
|
||
for (var loctype in types) {
|
||
if (currentNode[types[loctype]] != null) {
|
||
var loc = currentNode[types[loctype]].split(','), lat = parseFloat(loc[0]), lon = parseFloat(loc[1]);
|
||
if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
|
||
var deviceMark = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat])) });
|
||
deviceMark.setStyle(markerStyle(currentNode, parseInt(loctype) + 1));
|
||
markers.push(deviceMark);
|
||
|
||
if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
|
||
}
|
||
}
|
||
}
|
||
|
||
// Setup the device mark layer
|
||
var vectorSource = new ol.source.Vector({ features: markers });
|
||
var vectorLayer = new ol.layer.Vector({ source: vectorSource });
|
||
|
||
//var x = '<div><a href="https://www.google.com/maps/preview/@' + lat + ',' + lng + ',12z" rel="noreferrer noopener" target=_blank>Open in Google maps</a></div>';
|
||
var x = '<div id=d2map style=width:100%;height:300px></div>';
|
||
setDialogMode(2, "Device Location", 1, null, x, '@xxmap');
|
||
|
||
var clng = 0, clat = 0, zoom = 8;
|
||
if (boundingBox != null) {
|
||
var clat = (boundingBox[0] + boundingBox[2]) / 2;
|
||
var clng = (boundingBox[1] + boundingBox[3]) / 2;
|
||
var cscale = Math.max(Math.abs(boundingBox[0] - boundingBox[2]), Math.abs(boundingBox[1] - boundingBox[3]));
|
||
var i = 360, zoom = -2;
|
||
while (i > cscale) { zoom++; i = i / 2; }
|
||
}
|
||
|
||
if (markers.length == 1) { zoom = 8; }
|
||
|
||
// Setup the map
|
||
d2map = new ol.Map({
|
||
target: 'd2map',
|
||
interactions: ol.interaction.defaults({dragPan:false, mouseWheelZoom:false}),
|
||
layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer ],
|
||
view: new ol.View({ center: ol.proj.fromLonLat([clng, clat]), zoom: zoom })
|
||
});
|
||
}
|
||
|
||
// Show network interfaces
|
||
function p10showNodeNetInfoDialog() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Network Interfaces", 1, null, "<div id=d2netinfo>Loading...</div>", 'if' + currentNode._id );
|
||
meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id });
|
||
}
|
||
|
||
// Show router dialog
|
||
function p10showMeshCmdDialog(mode, nodeid) {
|
||
if (xxdialogMode) return;
|
||
var y = "<select id=aginsSelect onclick=meshCmdOsClick() style=width:236px>";
|
||
y += "<option value=3>Windows (32bit)</option>";
|
||
y += "<option value=4>Windows (64bit)</option>";
|
||
y += "<option value=5>Linux x86 (32bit)</option>";
|
||
y += "<option value=6>Linux x86 (64bit)</option>";
|
||
y += "<option value=25>Linux ARM, Raspberry Pi (32bit)</option>";
|
||
y += "</select>";
|
||
|
||
var x = "";
|
||
if (mode == 0) { x += '<div>MeshCmd is a command line tool that performs lots of different operations. The action file can optionally be downloaded and edited to provide server information and credentials.<br /><br />'; }
|
||
if (mode == 1) { x += '<div>Download "meshcmd" with an action file to route traffic thru this server to this device. Make sure to edit meshaction.txt and add your account password or make any changes needed.<br /><br />'; }
|
||
x += addHtmlValue('Operating System', y);
|
||
//x += addHtmlValue('MeshCmd', '<a id=meshcmddownloadid href="meshagents?meshcmd=3" rel="noreferrer noopener" target="_blank"></a>');
|
||
//if (mode == 0) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=generic" rel="noreferrer noopener" target="_blank">MeshAction (.txt)</a>'); }
|
||
//if (mode == 1) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=route&nodeid=' + nodeid + '" rel="noreferrer noopener" target="_blank">MeshAction (.txt)</a>'); }
|
||
x += addHtmlValue('MeshCmd', '<a id=meshcmddownloadid style=cursor:pointer onclick=fileDownload("meshagents?meshcmd=","MeshCmd",2)></a>');
|
||
if (mode == 0) { x += addHtmlValue('Action File', '<a style=cursor:pointer onclick=fileDownload("meshagents?meshaction=generic","MeshAction.txt")>MeshAction (.txt)</a>'); }
|
||
if (mode == 1) { x += addHtmlValue('Action File', '<a style=cursor:pointer onclick=fileDownload("meshagents?meshaction=route&nodeid=' + nodeid + '","MeshAction.txt")>MeshAction (.txt)</a>'); }
|
||
x += "</div>";
|
||
setDialogMode(2, ["Download MeshCmd","Network Router"][mode], 9, null, x, "fileDownload");
|
||
meshCmdOsClick();
|
||
}
|
||
|
||
function meshCmdOsClick() {
|
||
var os = Q('aginsSelect').value, osn = '';
|
||
//Q('meshcmddownloadid').href = "meshagents?meshcmd=" + os;
|
||
if (os == 3) { osn = 'MeshCmd (Win32 executable)'; }
|
||
if (os == 4) { osn = 'MeshCmd (Win64 executable)'; }
|
||
if (os == 5) { osn = 'MeshCmd (Linux x86, 32bit)'; }
|
||
if (os == 6) { osn = 'MeshCmd (Linux x86, 64bit)'; }
|
||
if (os == 25) { osn = 'MeshCmd (Linux ARM, 32bit)'; }
|
||
QH('meshcmddownloadid', osn);
|
||
}
|
||
|
||
function p10showiconselector() {
|
||
if (xxdialogMode) return;
|
||
var mesh = meshes[currentNode.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
if ((meshrights & 4) == 0) return;
|
||
|
||
var x = '<br><div style=display:inline-block;width:40px></div>';
|
||
x += '<div style=display:inline-block class=i1 onclick=p10setIcon(1)></div>';
|
||
x += '<div style=display:inline-block class=i2 onclick=p10setIcon(2)></div>';
|
||
x += '<div style=display:inline-block class=i3 onclick=p10setIcon(3)></div>';
|
||
x += '<div style=display:inline-block class=i4 onclick=p10setIcon(4)></div>';
|
||
x += '<div style=display:inline-block class=i5 onclick=p10setIcon(5)></div>';
|
||
x += '<div style=display:inline-block class=i6 onclick=p10setIcon(6)></div><br><br>';
|
||
setDialogMode(2, "Icon Selection", 0, null, x);
|
||
QV('id_dialogclose', true);
|
||
}
|
||
|
||
function p10setIcon(icon) {
|
||
setDialogMode(0);
|
||
meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
|
||
}
|
||
|
||
var showEditNodeValueDialog_modes = ['Device Name', 'Hostname', 'Description', 'Tags'];
|
||
var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
|
||
var showEditNodeValueDialog_modes3 = ['', '', '', 'Tag1, Tag2, Tag3'];
|
||
function showEditNodeValueDialog(mode) {
|
||
if (xxdialogMode) return;
|
||
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
|
||
setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
|
||
var v = currentNode[showEditNodeValueDialog_modes2[mode]];
|
||
if (v == null) v = '';
|
||
if (Array.isArray(v)) { v = v.join(', '); }
|
||
Q('dp10devicevalue').value = v;
|
||
p10editdevicevalueValidate();
|
||
Q('dp10devicevalue').focus();
|
||
}
|
||
|
||
function showEditNodeValueDialogEx(button, mode) {
|
||
var x = { action: 'changedevice', nodeid: currentNode._id };
|
||
x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
|
||
meshserver.send(x);
|
||
}
|
||
|
||
function p10editdevicevalueValidate(mode, e) {
|
||
var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
|
||
QE('idx_dlgOkButton', x);
|
||
if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
|
||
}
|
||
|
||
//
|
||
// DESKTOP
|
||
//
|
||
|
||
var desktopNode;
|
||
function setupDesktop() {
|
||
// Setup the remote desktop
|
||
if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); desktopNode = null; desktop = null; }
|
||
|
||
// If the device desktop is already connected in multi-desktop, use that.
|
||
if ((desktopNode != currentNode) || (desktop == null)) {
|
||
var xdesk = multiDesktop[currentNode._id];
|
||
if (xdesk != null) {
|
||
// This device already has a canvas, use it.
|
||
QH('DeskParent', '');
|
||
var c = xdesk.m.CanvasId;
|
||
c.setAttribute('id', 'Desk');
|
||
c.setAttribute('style', 'width:100%;-ms-touch-action:none;margin-left:0px');
|
||
c.setAttribute('onmousedown', 'dmousedown(event)');
|
||
c.setAttribute('onmouseup', 'dmouseup(event)');
|
||
c.setAttribute('onmousemove', 'dmousemove(event)');
|
||
c.removeAttribute('onclick');
|
||
Q('DeskParent').appendChild(c);
|
||
desktop = xdesk;
|
||
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
|
||
desktop.onStateChanged = onDesktopStateChange;
|
||
desktopNode = currentNode;
|
||
onDesktopStateChange(desktop, desktop.State);
|
||
delete multiDesktop[currentNode._id];
|
||
} else {
|
||
// Device is not already connected, just setup a blank canvas
|
||
QH('DeskParent', '<canvas id=Desk width=640 height=480 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();
|
||
deskAdjust();
|
||
|
||
// On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
|
||
if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
|
||
}
|
||
|
||
// Show and enable the right buttons
|
||
function updateDesktopButtons() {
|
||
var mesh = meshes[currentNode.meshid];
|
||
var deskState = 0;
|
||
if (desktop != null) { deskState = desktop.State; }
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
|
||
// Show the right buttons
|
||
QV('disconnectbutton1span', (deskState != 0));
|
||
QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
|
||
QV('connectbutton1hspan', (deskState == 0) && (meshrights & 8) && ((currentNode.intelamt != null) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
|
||
|
||
// Show the right settings
|
||
QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
|
||
QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
|
||
|
||
// Enable buttons
|
||
var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
|
||
var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
|
||
QE('connectbutton1', online);
|
||
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
|
||
QE('connectbutton1h', hwonline);
|
||
QE('deskSaveBtn', deskState == 3);
|
||
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
|
||
QV('DeskCAD', inputAllowed);
|
||
QE('DeskCAD', deskState == 3);
|
||
QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS
|
||
QE('DeskClip', deskState == 3);
|
||
QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
|
||
QE('DeskWD', deskState == 3);
|
||
QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
|
||
QE('deskkeys', deskState == 3);
|
||
|
||
QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskChatButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskNotifyButton', (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
|
||
|
||
QV('DeskControlSpan', inputAllowed)
|
||
QV('deskActionsBtn', (browserfullscreen == false));
|
||
QV('deskActionsSettings', (browserfullscreen == false));
|
||
if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
|
||
if (online == false) QV('DeskTools', false);
|
||
}
|
||
|
||
// Debug
|
||
var autoConnectDesktopTimer = null;
|
||
function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(connectDesktop, 100); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
|
||
|
||
function connectDesktop(e, contype) {
|
||
if (desktop == null) {
|
||
desktopNode = currentNode;
|
||
if (contype == 2) {
|
||
// Setup the Intel AMT remote desktop
|
||
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
|
||
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
||
desktop.debugmode = debugmode;
|
||
desktop.onStateChanged = onDesktopStateChange;
|
||
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
|
||
desktop.m.useZRLE = (desktopsettings.encoding < 3);
|
||
desktop.m.localKeyMap = desktopsettings.localkeymap;
|
||
desktop.m.showmouse = desktopsettings.showmouse;
|
||
desktop.m.onScreenSizeChange = deskAdjust;
|
||
desktop.m.onKvmData = function (x) {
|
||
//console.log('onKvmData (' + x.length + '): ' + x);
|
||
// Send the presense probe only once if needed.
|
||
if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
|
||
var data = null;
|
||
try { data = JSON.parse(x); } catch (e) { }
|
||
if ((data != null) && (data.action != null)) {
|
||
if (data.action == 'restart') {
|
||
// Clear WebRTC channel
|
||
webRtcDesktopReset();
|
||
desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
|
||
} else if ((data.action == 'present') && (webRtcDesktop == null)) {
|
||
// Setup WebRTC channel
|
||
webRtcDesktop = { platform: data.platform };
|
||
var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
|
||
if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
|
||
else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }
|
||
|
||
webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
|
||
webRtcDesktop.webchannel.onopen = function () {
|
||
// Switch to software KVM
|
||
//if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
|
||
console.log('WebRTC Data Channel Open');
|
||
Q('deskstatus').textContent = StatusStrs[desktop.State] + ', Soft-KVM';
|
||
desktop.m.hold(true);
|
||
webRtcDesktop.webRtcActive = true;
|
||
webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
|
||
webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
|
||
webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
|
||
if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
|
||
if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
|
||
webRtcDesktop.softdesktop.Start();
|
||
|
||
// Check if we can get remote file access
|
||
// ###BEGIN###{DesktopInbandFiles}
|
||
/*
|
||
QV('go24', true); // Files
|
||
downloadFile = null;
|
||
p24files = webRtcDesktop.softdesktop;
|
||
p24targetpath = '';
|
||
webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
|
||
webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
|
||
*/
|
||
// ###END###{DesktopInbandFiles}
|
||
}
|
||
webRtcDesktop.webchannel.onclose = function (event) {
|
||
//if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); }
|
||
console.log('WebRTC Data Channel Closed');
|
||
webRtcDesktopReset();
|
||
}
|
||
webRtcDesktop.webrtc.onicecandidate = function (e) {
|
||
if (e.candidate == null) {
|
||
desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
|
||
} else {
|
||
webRtcDesktop.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
|
||
}
|
||
}
|
||
webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
|
||
if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
|
||
}
|
||
webRtcDesktop.webrtc.createOffer(function (offer) {
|
||
// Got the offer
|
||
webRtcDesktop.webrtcoffer = offer;
|
||
webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
|
||
}, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
|
||
} else if ((data.action == 'answer') && (webRtcDesktop != null)) {
|
||
// Complete the WebRTC channel
|
||
webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
|
||
}
|
||
}
|
||
};
|
||
desktop.Start(desktopNode._id, 16994, '*', '*', 0);
|
||
desktop.contype = 2;
|
||
} else {
|
||
// Setup the Mesh Agent remote desktop
|
||
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie);
|
||
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();
|
||
webRtcDesktopReset();
|
||
desktopNode = desktop = null;
|
||
}
|
||
}
|
||
|
||
var webRtcDesktop = null;
|
||
function webRtcDesktopReset() {
|
||
if (webRtcDesktop == null) return;
|
||
if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
|
||
if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
|
||
if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
|
||
webRtcDesktop = null;
|
||
// Switch back to hardware KVM
|
||
if (desktop && desktop.m) {
|
||
desktop.m.hold(false);
|
||
Q('deskstatus').textContent = StatusStrs[desktop.State];
|
||
}
|
||
// ###BEGIN###{DesktopInbandFiles}
|
||
/*
|
||
p24files = null;
|
||
p24downloadFileCancel() // If any downloads are in process, cancel them.
|
||
p24uploadFileCancel(); // If any uploads are in process, cancel them.
|
||
QV('go24', false); // Files
|
||
if (currentView == 24) { go(14); }
|
||
*/
|
||
// ###END###{DesktopInbandFiles}
|
||
}
|
||
|
||
function onDesktopStateChange(xdesktop, state) {
|
||
var xstate = state;
|
||
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
|
||
var str = StatusStrs[xstate];
|
||
if ((desktop != null) && (desktop.webRtcActive == true)) { str += ', WebRTC'; }
|
||
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
|
||
QH('deskstatus', str);
|
||
switch (state) {
|
||
case 0:
|
||
// Disconnect and clean up the remote desktop
|
||
desktop.Stop();
|
||
desktopNode = desktop = null;
|
||
QV('DeskFocus', false);
|
||
QV('termdisplays', false);
|
||
deskFocusBtn.value = 'All Focus';
|
||
if (fullscreen == true) { deskToggleFull(); }
|
||
webRtcDesktopReset();
|
||
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, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
|
||
}
|
||
|
||
function showDesktopSettingsChanged() {
|
||
desktopsettings.encoding = d7desktopmode.value;
|
||
desktopsettings.showfocus = d7showfocus.checked;
|
||
desktopsettings.showmouse = d7showcursor.checked;
|
||
desktopsettings.quality = d7bitmapquality.value;
|
||
desktopsettings.scaling = d7bitmapscaling.value;
|
||
desktopsettings.framerate = d7framelimiter.value;
|
||
desktopsettings.localkeymap = d7localKeyMap.checked;
|
||
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
|
||
applyDesktopSettings();
|
||
if (desktop) {
|
||
if (desktop.contype == 1) {
|
||
if (desktop.State != 0) {
|
||
desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
|
||
}
|
||
}
|
||
if (desktop.contype == 2) {
|
||
if (desktopsettings.showfocus == false) { desktop.m.focusmode = 0; deskFocusBtn.value = 'All Focus'; }
|
||
if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
|
||
}
|
||
}
|
||
}
|
||
|
||
function applyDesktopSettings() {
|
||
var r = '', ops = (features & 512)?[90,80,70,60,50,40,30,20,10,5,1]:[60,50,40,30,20,10,5,1];
|
||
for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
|
||
QH('d7bitmapquality', r);
|
||
d7desktopmode.value = desktopsettings.encoding;
|
||
d7showfocus.checked = desktopsettings.showfocus;
|
||
d7showcursor.checked = desktopsettings.showmouse;
|
||
d7bitmapquality.value = 40; // Default value
|
||
if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
|
||
d7bitmapscaling.value = desktopsettings.scaling;
|
||
if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
|
||
if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
|
||
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
|
||
}
|
||
|
||
// Enter browser fullscreen
|
||
function enterBrowserFullscreen(elem) {
|
||
if (elem.requestFullscreen) { elem.requestFullscreen(); }
|
||
else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); }
|
||
else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); }
|
||
else if (elem.webkitRequestFullscreen) { elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); }
|
||
}
|
||
|
||
// Exit browser fullscreen
|
||
function exitBrowserFullscreen() {
|
||
if (document.exitFullscreen) { document.exitFullscreen(); }
|
||
else if (document.msExitFullscreen) { document.msExitFullscreen(); }
|
||
else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); }
|
||
else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); }
|
||
}
|
||
|
||
// Return true if the browser is fullscreen. This is a delayed method that will return true/false late. Not very useful.
|
||
function isBrowserFullscreen() {
|
||
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) { return false; } else { return true; }
|
||
}
|
||
|
||
var fullscreen = false;
|
||
var browserfullscreen = false;
|
||
function deskToggleFull(e) {
|
||
fullscreen = !fullscreen;
|
||
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);
|
||
QV('page_leftbar', !fullscreen);
|
||
if (fullscreen) {
|
||
// If shift is pressed, enter browser full screen.
|
||
if (e.shiftKey == true) { enterBrowserFullscreen(Q('deskarea0')); browserfullscreen = true; }
|
||
QS('column_l').width = '930px';
|
||
QS('column_l').height = '';
|
||
QS('column_l')['margin-left'] = '';
|
||
QS('column_l')['overflow-y'] = '';
|
||
QS('container').position = '';
|
||
QS('page_content').position = '';
|
||
QV('MainMenuSpan', true);
|
||
QS('container').width = '100%';
|
||
QS('container')['border-right'] = '0';
|
||
QS('container')['border-left'] = '0';
|
||
QS('column_l').padding = '0';
|
||
QS('column_l').width = '100%';
|
||
QS('column_l')["max-height"] = '';
|
||
} else {
|
||
exitBrowserFullscreen();
|
||
browserfullscreen = false;
|
||
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();
|
||
deskAdjust();
|
||
updateDesktopButtons();
|
||
}
|
||
|
||
function deskToggleFocus() {
|
||
desktop.m.focusmode = (desktop.m.focusmode + 64) % 192;
|
||
Q('deskFocusBtn').value = ['All Focus', 'Small Focus', 'Large Focus'][desktop.m.focusmode / 64];
|
||
}
|
||
|
||
function deskAdjust() {
|
||
var x = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('Desk').clientHeight + Q('deskarea4').clientHeight + 2)) / 2;
|
||
if (fullscreen) {
|
||
document.documentElement.style.overflow = 'hidden';
|
||
QS('deskarea3x').height = null;
|
||
if (x < 0) {
|
||
var mh = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('deskarea4').clientHeight));
|
||
var mw = 9999;
|
||
if (desktop) { mw = (desktop.m.width / desktop.m.height) * mh; }
|
||
if (webRtcDesktop && webRtcDesktop.softdesktop) { mw = (webRtcDesktop.softdesktop.m.width / webRtcDesktop.softdesktop.m.height) * mh; }
|
||
QS('Desk')['max-height'] = mh + 'px';
|
||
QS('Desk')['max-width'] = mw + 'px';
|
||
x = 0;
|
||
} else {
|
||
QS('Desk')['max-height'] = null;
|
||
QS('Desk')['max-width'] = null;
|
||
}
|
||
QS('Desk')['margin-top'] = x + 'px';
|
||
QS('Desk')['margin-bottom'] = x + 'px';
|
||
} else {
|
||
var mw = 9999, mh = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (webPageFullScreen?276:290));
|
||
if (desktop) { mw = (desktop.m.width / desktop.m.height) * mh; }
|
||
if (webRtcDesktop && webRtcDesktop.softdesktop) { mw = (webRtcDesktop.softdesktop.m.width / webRtcDesktop.softdesktop.m.height) * mh; }
|
||
document.documentElement.style.overflow = 'auto';
|
||
QS('Desk')['max-height'] = mh + 'px';
|
||
QS('Desk')['max-width'] = mw + 'px';
|
||
QS('Desk')['margin-top'] = '0';
|
||
QS('Desk')['margin-bottom'] = '0';
|
||
}
|
||
}
|
||
|
||
function mdeskAdjust(mod, sw, sh, cv) {
|
||
if (!mod || !sw || !sh || !cv) return;
|
||
|
||
// Check if we are in single desktop mode
|
||
if (cv.id == "Desk") { deskAdjust(); return; }
|
||
|
||
// Figure out and adjust the size to fill the width of the div
|
||
var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
|
||
var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
|
||
xw = realw + Math.floor((tw - (xw * realw)) / xw);
|
||
vsize.y = vsize.y * (xw / vsize.x);
|
||
vsize.x = xw;
|
||
var mh = vsize.y, mw = vsize.x;
|
||
if (mod.State != 0) { mh = vsize.y; mw = (sw / sh) * vsize.y; }
|
||
QS(cv.id)['max-height'] = mh + 'px';
|
||
QS(cv.id)['max-width'] = mw + 'px';
|
||
QS(cv.id)['margin-top'] = '0';
|
||
QS(cv.id)['margin-bottom'] = '0';
|
||
}
|
||
|
||
// Remote desktop special key combos for Windows
|
||
function deskSendKeys() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
var ks = Q('deskkeys').value;
|
||
if (ks == 0) { // WIN+Down arrow
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0xff54,1],[0xff54,0],[0xffe7,0]]); // Intel AMT: Meta-left down, Down arrow press, Down arrow release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,40],[desktop.m.KeyAction.UP,40],[desktop.m.KeyAction.EXUP,0x5B]]); // Agent: L-Winkey press, Down arrow press, Down arrow release, L-Winkey release
|
||
}
|
||
} else if (ks == 1) { // WIN+Up arrow
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0xff52,1],[0xff52,0],[0xffe7,0]]); // Intel AMT: Meta-left down, Up arrow press, Up arrow release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,38],[desktop.m.KeyAction.UP,38],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, Up arrow press, Up arrow release, L-Winkey release
|
||
}
|
||
} else if (ks == 2) { // WIN+L arrow
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0x6c,1],[0x6c,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
|
||
} else {
|
||
desktop.sendCtrlMsg('{"action":"lock"}');
|
||
//desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,76],[desktop.m.KeyAction.UP,76],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'L' press, 'L' release, L-Winkey release
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
|
||
//desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
|
||
}
|
||
} else if (ks == 3) { // WIN+M arrow
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0x6d,1],[0x6d,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,77],[desktop.m.KeyAction.UP,77],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'M' press, 'M' release, L-Winkey release
|
||
}
|
||
} else if (ks == 4) { // Shift+WIN+M arrow
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe1,1],[0xffe7,1],[0x6d,1],[0x6d,0],[0xffe7,0],[0xffe1,0]]); // Intel AMT: Shift-left down, Meta-left down, 'm' press, 'm' release, Meta-left release, Shift-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN,16],[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,77],[desktop.m.KeyAction.UP,77],[desktop.m.KeyAction.EXUP,0x5B],[desktop.m.KeyAction.UP, 16]]); // MeshAgent: L-shift press, L-Winkey press, 'M' press, 'M' release, L-Winkey release, L-shift release
|
||
}
|
||
} else if (ks == 5) { // WIN
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7,1],[0xffe7,0]]); // Intel AMT: Meta-left down, Meta-left release
|
||
} else {
|
||
desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B], [desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
|
||
}
|
||
} else if (ks == 6) { // WIN+R
|
||
if (desktop.contype == 2) {
|
||
desktop.m.sendkey([[0xffe7, 1], [0x72, 1], [0x72, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'l' press, 'l' 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
|
||
}
|
||
}
|
||
}
|
||
|
||
// Show clipboard dialog
|
||
function showDeskClip() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
Q('DeskClip').blur();
|
||
var x = '';
|
||
x += '<input id=dlgClipGet type=button value="Get Clipboard" style=width:120px onclick=showDeskClipGet()>';
|
||
x += '<input id=dlgClipSet type=button value="Set Clipboard" style=width:120px onclick=showDeskClipSet()>';
|
||
x += '<div id=dlgClipStatus style="display:inline-block;margin-left:8px" ></div>';
|
||
x += '<textarea id=d2clipText style="width:100%;height:184px;resize:none" maxlength=65535></textarea>';
|
||
x += '<input type=button value="Close" style=width:80px;float:right onclick=dialogclose(0)><div style=height:26px;margin-top:3px><span id=linuxClipWarn style=display:none>Remote clipboard is valid for 60 seconds.</span> </div><div></div>';
|
||
setDialogMode(2, "Remote Clipboard", 8, null, x, 'clipboard');
|
||
Q('d2clipText').focus();
|
||
}
|
||
|
||
function showDeskClipGet() {
|
||
if (desktop == null || desktop.State != 3) return;
|
||
meshserver.send({ action: 'msg', type: 'getclip', nodeid: currentNode._id });
|
||
}
|
||
|
||
function showDeskClipSet() {
|
||
if (desktop == null || desktop.State != 3) return;
|
||
meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
|
||
QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22));
|
||
}
|
||
|
||
// Send CTRL-ALT-DEL
|
||
function sendCAD() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
desktop.m.sendcad();
|
||
}
|
||
|
||
// Show process dialogs
|
||
function toggleDeskTools() {
|
||
if (xxdialogMode) return;
|
||
if (QS('DeskTools').display == 'none') {
|
||
QV('DeskTools', true);
|
||
Q('DeskTools').nodeid = currentNode._id;
|
||
refreshDeskTools();
|
||
} else {
|
||
QV('DeskTools', false);
|
||
}
|
||
}
|
||
|
||
// Refresh all of the desktop tool panels
|
||
function refreshDeskTools() {
|
||
QV('DeskToolsRefreshButton', false);
|
||
setTimeout(refreshDeskToolsEx, 500);
|
||
meshserver.send({ action: 'msg', type:'ps', nodeid: currentNode._id });
|
||
}
|
||
function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
|
||
var deskTools = { sort: 1, msg: null };
|
||
function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
|
||
function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return 0; }
|
||
function sortProcessName(a, b) { if (a.d > b.d) return 1; if (a.d < b.d) return (-1); return 0; }
|
||
function showDeskToolsProcesses(message) {
|
||
deskTools.msg = message;
|
||
if (message == null) { QH('DeskToolsProcesses', ''); return; }
|
||
if (Q('DeskTools').nodeid != message.nodeid) return;
|
||
var p = [], processes = null;
|
||
try { processes = JSON.parse(message.value); } catch (e) { }
|
||
if (processes != null) {
|
||
for (var pid in processes) { p.push( { p:parseInt(pid), c:processes[pid].cmd, d:processes[pid].cmd.toLowerCase(), u: processes[pid].user } ); }
|
||
if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
|
||
var x = '';
|
||
for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u?p[i].u:'') + '</div><div>' + p[i].c + '</div></div>'; } }
|
||
QH('DeskToolsProcesses', x);
|
||
}
|
||
}
|
||
|
||
// Toggle mouse and keyboard input
|
||
function toggleKvmControl() { putstore('DeskControl', (Q("DeskControl").checked?1:0)); }
|
||
|
||
// Save the desktop image to file
|
||
function deskSaveImage() {
|
||
if (xxdialogMode || desktop == null || desktop.State != 3) return;
|
||
var d = new Date(), n = 'Desktop-' + currentNode.name + '-' + d.getFullYear() + "-" + ("0" + (d.getMonth() + 1)).slice(-2) + "-" + ("0" + d.getDate()).slice(-2) + "-" + ("0" + d.getHours()).slice(-2) + "-" + ("0" + d.getMinutes()).slice(-2);
|
||
Q("Desk")['toBlob'](function (blob) { saveAs(blob, n + ".jpg"); });
|
||
}
|
||
|
||
function deskDisplayInfo(sender, info, selDisplay, selItem) {
|
||
var txt = Q('termdisplays').value;
|
||
if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x])?' selected':'') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
|
||
QV('termdisplays', info.length > 0);
|
||
}
|
||
|
||
function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
|
||
|
||
function deskSetDisplay(e) {
|
||
var display = 0, txt = Q('termdisplays').value;
|
||
if (txt == "All Displays") display = 65535; else display = parseInt(txt.substring(8));
|
||
desktop.m.SetDisplay(display);
|
||
}
|
||
|
||
// Double click detection. This is important for MacOS.
|
||
var dblClickDetectArgs = { t:0, x:0, y:0 };
|
||
function dblClickDetect(e) {
|
||
if (e.buttons != 1) return;
|
||
var t = Date.now();
|
||
if (((t - dblClickDetectArgs.t) < 250) && (Math.abs(e.clientX - dblClickDetectArgs.x) < 2) && (Math.abs(e.clientY - dblClickDetectArgs.y) < 2)) {
|
||
if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedblclick(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedblclick(e); } }
|
||
}
|
||
dblClickDetectArgs.t = t;
|
||
dblClickDetectArgs.x = e.clientX;
|
||
dblClickDetectArgs.y = e.clientY;
|
||
}
|
||
|
||
function dmousedown(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedown(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedown(e); } } dblClickDetect(e); }
|
||
function dmouseup(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mouseup(e); desktop.m.sendKeepAlive(); } else { desktop.m.mouseup(e); } }
|
||
function dmousemove(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousemove(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousemove(e); } } }
|
||
function dmousewheel(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousewheel(e); desktop.m.sendKeepAlive(); } else { if (desktop.m.mousewheel) { desktop.m.mousewheel(e); } } haltEvent(e); return true; } return false; }
|
||
function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
|
||
function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); }
|
||
function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type:'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
|
||
|
||
//
|
||
// TERMINAL
|
||
//
|
||
|
||
var terminalNode;
|
||
function setupTerminal() {
|
||
// Setup the terminal
|
||
if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); terminal = null; }
|
||
terminalNode = currentNode;
|
||
updateTerminalButtons();
|
||
}
|
||
|
||
// Show and enable the right buttons
|
||
function updateTerminalButtons() {
|
||
var mesh = meshes[terminalNode.meshid];
|
||
var termState = ((terminal != null) && (terminal.state != 0));
|
||
|
||
// Show the right buttons
|
||
QV('disconnectbutton2span', (termState == true));
|
||
QV('connectbutton2span', (termState == false) && (mesh.mtype == 2) && (currentNode.agent.caps & 2));
|
||
QV('connectbutton2hspan', (termState == false) && ((terminalNode.intelamt != null) && (mesh.mtype == 1 || terminalNode.intelamt.state == 2) && ((terminalNode.intelamt.ver != null) || (mesh.mtype == 1))));
|
||
|
||
// Enable buttons
|
||
var online = ((terminalNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
|
||
QE('connectbutton2', online);
|
||
var hwonline = ((terminalNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
|
||
QE('connectbutton2h', hwonline);
|
||
|
||
// Key buttons
|
||
QE('ctrlcbutton', termState);
|
||
QE('ctrlxbutton', termState);
|
||
QE('escbutton', termState);
|
||
QE('bsbutton', termState);
|
||
QE('pastebutton', termState);
|
||
QE('specialkeylist', termState);
|
||
QE('specialkeylistinput', termState);
|
||
|
||
// Terminal settings
|
||
QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
|
||
if (terminal) {
|
||
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
|
||
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n')?'CR+LF':'LF';
|
||
}
|
||
}
|
||
|
||
// Called when the terminal state changes
|
||
function onTerminalStateChange(xterminal, state) {
|
||
var xstate = state;
|
||
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
|
||
var str = StatusStrs[xstate];
|
||
if (terminal.webRtcActive == true) { str += ', WebRTC'; }
|
||
QH('termstatus', str);
|
||
switch (state) {
|
||
case 0:
|
||
// Disconnected, clear the terminal
|
||
xterminal.m.TermResetScreen();
|
||
xterminal.m.TermDraw();
|
||
if (terminal != null) {
|
||
terminal.Stop();
|
||
terminal = null;
|
||
}
|
||
break;
|
||
case 3:
|
||
break;
|
||
default:
|
||
//console.log('Unhandled onTerminalStateChange state', state);
|
||
break;
|
||
}
|
||
updateTerminalButtons();
|
||
}
|
||
|
||
// DEBUG
|
||
var autoConnectTerminalTimer = null;
|
||
function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } }
|
||
|
||
function connectTerminal(e, contype) {
|
||
if (!terminal) {
|
||
if (contype == 2) {
|
||
// Setup the Intel AMT terminal
|
||
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
|
||
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term'), authCookie);
|
||
terminal.debugmode = debugmode;
|
||
terminal.m.debugmode = debugmode;
|
||
terminal.onStateChanged = onTerminalStateChange;
|
||
terminal.Start(terminalNode._id, 16994, '*', '*', 0);
|
||
terminal.contype = 2;
|
||
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||
} else {
|
||
// Setup a mesh agent terminal
|
||
terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term'), serverPublicNamePort, authCookie);
|
||
terminal.debugmode = debugmode;
|
||
terminal.m.debugmode = debugmode;
|
||
terminal.m.lineFeed = ([1,2,3,4,21,22].indexOf(currentNode.agent.id) >= 0)?'\r\n':'\n'; // On windows, send \r\n, on Linux only \n
|
||
terminal.attemptWebRTC = attemptWebRTC;
|
||
terminal.onStateChanged = onTerminalStateChange;
|
||
terminal.Start(terminalNode._id);
|
||
terminal.contype = 1;
|
||
terminal.m.terminalEmulation = 0;
|
||
terminal.m.fxEmulation = 0;
|
||
Q('id_ttypebutton').value = terminalEmulations[0];
|
||
}
|
||
} else {
|
||
//QH('Term', '');
|
||
terminal.Stop();
|
||
terminal = null;
|
||
}
|
||
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
|
||
}
|
||
|
||
var terminalEmulations = ['UTF8 Terminal', 'Extended ASCII', 'Intel ASCII'];
|
||
function termToggleType() {
|
||
if (!terminal || xxdialogMode) return;
|
||
terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
|
||
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
|
||
Q('id_ttypebutton').blur(); // Deselect the connect button so the button does not get key presses.
|
||
}
|
||
|
||
var fxEmulations = ['Intel (F10 = ESC+[OM)', 'Alternate (F10 = ESC+0)', 'VT100+ (F10 = ESC+[OY)'];
|
||
function termToggleFx() {
|
||
if (!terminal || xxdialogMode) return;
|
||
terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3;
|
||
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
|
||
Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
|
||
}
|
||
|
||
function termToggleCr() {
|
||
if (!terminal || xxdialogMode) return;
|
||
if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
|
||
Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? 'CR+LF' : 'LF';
|
||
}
|
||
|
||
function termSendKey(key, id) {
|
||
if (!terminal || xxdialogMode) return;
|
||
terminal.m.TermSendKey(key);
|
||
Q(id).blur(); // Deselect the connect button so the button does not get key presses.
|
||
}
|
||
|
||
function showTermPasteDialog() {
|
||
if (!terminal || xxdialogMode) return;
|
||
Q('pastebutton').blur();
|
||
setDialogMode(2, "Paste", 3, showTermPasteDialogEx, '<textarea id=d2pasteText style="width:100%;height:184px;resize:none"></textarea>');
|
||
Q('d2pasteText').focus();
|
||
}
|
||
|
||
function showTermPasteDialogEx() {
|
||
if (!terminal) return;
|
||
terminal.m.TermSendKeys(Q('d2pasteText').value);
|
||
}
|
||
|
||
// Send special key
|
||
function sendSpecialKey() {
|
||
terminal.m.TermSendKey(Q('specialkeylist').value);
|
||
Q('specialkeylist').blur();
|
||
Q('specialkeylistinput').blur();
|
||
}
|
||
|
||
//
|
||
// FILES
|
||
//
|
||
|
||
var filesNode;
|
||
function setupFiles() {
|
||
// Setup the files tab
|
||
var samenode = (filesNode == currentNode);
|
||
filesNode = currentNode;
|
||
var online = ((filesNode.conn & 1) != 0)?true:false; // If Agent (1) connected, enable Terminal
|
||
QE('p13Connect', online);
|
||
if (((samenode == false) || (online == false)) && files) { files.Stop(); files = null; }
|
||
}
|
||
|
||
function onFilesStateChange(xfiles, state) {
|
||
p13Connect.value = (state == 0) ? 'Connect' : 'Disconnect';
|
||
var str = StatusStrs[state];
|
||
if (files.webRtcActive == true) { str += ', WebRTC'; }
|
||
Q('p13Status').textContent = str;
|
||
switch (state) {
|
||
case 0:
|
||
// Disconnected, clear the files
|
||
QH('p13files', '');
|
||
p13filetree = null;
|
||
p13filetreelocation = [];
|
||
QH('p13currentpath', '');
|
||
QE('p13FolderUp', false);
|
||
p13setActions();
|
||
if (files != null) { files.Stop(); 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);
|
||
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) {
|
||
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)>Root</a>', fullPath = 'Root';
|
||
|
||
// Work on parsing the file path
|
||
var x = p13filetree.path.split('\\');
|
||
p13filetreelocation = [];
|
||
for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces
|
||
for (var i in p13filetreelocation) { displayPath += ' / <a style=cursor:pointer onclick=p13folderup(' + (parseInt(i) + 1) + ')>' + p13filetreelocation[i] + '</a>' } // Setup the path we display
|
||
var newlinkpath = p13filetreelocation.join('/');
|
||
|
||
// Sort the files
|
||
var filetreexx = p13sort_files(p13filetree.dir);
|
||
|
||
// Display all files and folders at this location
|
||
for (var i in filetreexx) {
|
||
// Figure out the name and shortname
|
||
var f = filetreexx[i], name = f.n, shortname;
|
||
shortname = name;
|
||
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
|
||
name = EscapeHtml(name);
|
||
|
||
// Figure out the date
|
||
var fdatestr = '';
|
||
if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
|
||
|
||
// Figure out the size
|
||
var fsize = '';
|
||
if (f.s != null) { fsize = getFileSizeStr(f.s); }
|
||
|
||
var h = '';
|
||
if (f.t < 3) {
|
||
var right = '', title = '';
|
||
h = "<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value='" + f.nx + "'> <span style=float:right title=\"" + title + "\">" + right + "</span><span><div class=fileIcon" + f.t + " onclick=p13folderset(\"" + encodeURIComponent(f.nx) + "\")></div><a 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 class=fsize>" + fdatestr + "</span><span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
|
||
}
|
||
|
||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||
}
|
||
|
||
// Display the files and path
|
||
QH('p13files', html1 + html2);
|
||
QH('p13currentpath', displayPath);
|
||
QE('p13FolderUp', p13filetreelocation.length != 0);
|
||
|
||
// Re-check all boxes if needed using names
|
||
if (checkedNames != null) { var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkedNames.indexOf(p13filetree.dir[checkboxes[i].value].n) >= 0) { checkboxes[i].checked = true; } } }
|
||
|
||
// Update the actions buttons
|
||
p13setActions();
|
||
}
|
||
|
||
function p13folderset(x) {
|
||
p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
|
||
files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
|
||
}
|
||
|
||
function p13folderup(x) {
|
||
if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
|
||
p13targetpath = p13filetreelocation.join('/');
|
||
files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
|
||
}
|
||
|
||
var p13sortorder;
|
||
function p13sort_filename(a, b) { if (a.ln > b.ln) return (1 * p13sortorder); if (a.ln < b.ln) return (-1 * p13sortorder); return 0; }
|
||
function p13sort_timestamp(a, b) { if (a.d > b.d) return (1 * p13sortorder); if (a.d < b.d) return (-1 * p13sortorder); return 0; }
|
||
function p13sort_bysize(a, b) { if (a.s == b.s) return p13sort_filename(a, b); return (((a.s - b.s)) * p13sortorder); }
|
||
|
||
function p13sort_files(files) {
|
||
var r = [], sortselection = Q('p13sortdropdown').value;
|
||
for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
|
||
p13sortorder = 1;
|
||
if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
|
||
if (sortselection == 1) { r.sort(p13sort_filename); }
|
||
else if (sortselection == 2) { r.sort(p13sort_bysize); }
|
||
else if (sortselection == 3) { r.sort(p13sort_timestamp); }
|
||
return r;
|
||
}
|
||
|
||
function p13setActions() {
|
||
if (p13filetree == null) {
|
||
QE('p13DeleteFileButton', false);
|
||
QE('p13NewFolderButton', false);
|
||
QE('p13UploadButton', false);
|
||
QE('p13RenameFileButton', false);
|
||
QE('p13SelectAllButton', false);
|
||
Q('p13SelectAllButton').value = 'Select All';
|
||
QE('p13RefreshButton', false);
|
||
QE('p13CutButton', false);
|
||
QE('p13CopyButton', false);
|
||
QE('p13PasteButton', false);
|
||
} else {
|
||
var cc = p13getFileSelCount(), tc = p13getFileCount(), sfc = p13getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
|
||
var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
|
||
QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13NewFolderButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13RenameFileButton', (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13SelectAllButton', tc > 0);
|
||
Q('p13SelectAllButton').value = (cc > 0 ? 'Select None' : 'Select All');
|
||
QE('p13RefreshButton', true);
|
||
QE('p13CutButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13CopyButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
|
||
QE('p13PasteButton', ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
|
||
}
|
||
}
|
||
|
||
function p13getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
|
||
function 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, "New Folder", 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 /><input type=checkbox id=p13recdeleteinput>Recursive delete<br>" : "<input type=checkbox id=p13recdeleteinput style='display:none'>"; setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1) ? ('Delete ' + cc + ' selected items?' + rec) : ('Delete selected item?' + 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, "Rename", 3, p13renamefileEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile}); focusTextBox('p13renameinput'); p13fileNameCheck(); }
|
||
function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.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, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
|
||
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
|
||
|
||
var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
|
||
function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); }
|
||
function p13pasteFile() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Confim ' + (p13clipboardCut == 0?'copy':'move') + ' of ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p13pasteFileEx, x); }
|
||
function p13pasteFileEx() { files.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)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' for ' + (p13clipboardCut == 0?'copy':'move') + ', <a onclick=p13clearClip() style=cursor:pointer>Clear</a>.' } QH('p13bottomstatus', x); p13setActions(); }
|
||
function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); }
|
||
|
||
function p13fileDragDrop(e) {
|
||
haltEvent(e);
|
||
QV('p13bigfail', false);
|
||
QV('p13bigok', false);
|
||
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || p13filetree == null) return;
|
||
p13doUploadFiles(e.dataTransfer.files);
|
||
}
|
||
|
||
var p13dragtimer = null;
|
||
function p13fileDragOver(e) {
|
||
haltEvent(e);
|
||
if (p13dragtimer != null) { clearTimeout(p13dragtimer); p13dragtimer = null; }
|
||
var ac = (p13filetree != null); // Set to true if we can accept the file
|
||
QV('p13bigok', ac);
|
||
QV('p13bigfail', !ac);
|
||
}
|
||
|
||
function p13fileDragLeave(e) {
|
||
haltEvent(e);
|
||
if (e.target.id != "p13filetable") {
|
||
QV('p13bigfail', false);
|
||
QV('p13bigok', false);
|
||
} else {
|
||
p13dragtimer = setTimeout(function () { QV('p13bigfail',false); QV('p13bigok',false); p13dragtimer=null; }, 10);
|
||
}
|
||
}
|
||
|
||
//
|
||
// FILES DOWNLOAD
|
||
//
|
||
|
||
var downloadFile; // Global state for file download
|
||
|
||
// Called by the html page to start a download, arguments are: path, file name and file size.
|
||
function p13downloadfile(x, y, z) {
|
||
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, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
|
||
}
|
||
|
||
// Called by the html page to cancel the download
|
||
function p13downloadFileCancel() { setDialogMode(0); files.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); // 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, "Upload File", 10, p13uploadFileCancel, '<div id=p13dfileName>Connecting...</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
|
||
p13uploadReconnect();
|
||
}
|
||
|
||
function onFileUploadStateChange(xdownloadFile, state) {
|
||
switch (state) {
|
||
case 0:
|
||
p13folderup(9999);
|
||
break;
|
||
case 3:
|
||
p13uploadNextFile();
|
||
break;
|
||
default:
|
||
console.log('Unknown onFileUploadStateChange state', state);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Connect again
|
||
function p13uploadReconnect() {
|
||
uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie);
|
||
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(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
|
||
};
|
||
uploadFile.xreader.readAsArrayBuffer(file);
|
||
} else {
|
||
p13uploadFileCancel();
|
||
}
|
||
}
|
||
|
||
// Used to cancel the entire transfer.
|
||
function p13uploadFileCancel(button, tag) {
|
||
if (uploadFile != null) {
|
||
if (uploadFile.ws != null) {
|
||
uploadFile.ws.Stop();
|
||
uploadFile.ws = null;
|
||
}
|
||
uploadFile = null;
|
||
}
|
||
setDialogMode(0); // Close any dialog boxes if present
|
||
}
|
||
|
||
// Receive upload ack from the mesh agent, use this to keep sending more data
|
||
function p13gotUploadData(data) {
|
||
var cmd = JSON.parse(data);
|
||
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
|
||
|
||
if (cmd.action == 'uploadstart') {
|
||
p13uploadNextPart(false);
|
||
for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
|
||
} else if (cmd.action == 'uploadack') {
|
||
p13uploadNextPart(false);
|
||
} else if (cmd.action == 'uploaderror') {
|
||
p13uploadFileCancel();
|
||
}
|
||
}
|
||
|
||
// Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
|
||
function p13uploadNextPart(dataPriming) {
|
||
var data = uploadFile.xdata;
|
||
var start = uploadFile.xptr;
|
||
var end = uploadFile.xptr + 4096;
|
||
if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
|
||
if (start == data.byteLength) {
|
||
if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
|
||
if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
|
||
} else {
|
||
var datapart = data.slice(start, end);
|
||
uploadFile.ws.send(datapart);
|
||
uploadFile.xptr = end;
|
||
Q('d2progressBar').value = end;
|
||
}
|
||
}
|
||
|
||
//
|
||
// DEVICE EVENTS
|
||
//
|
||
|
||
var currentDeviceEvents = null;
|
||
function deviceEventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in currentDeviceEvents) {
|
||
var event = currentDeviceEvents[i];
|
||
var time = new Date(event.time);
|
||
if (time.toLocaleDateString() != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt colspan=4>' + time.toLocaleDateString() + '</td></tr>';
|
||
dateHeader = time.toLocaleDateString();
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = event.msg.split('(R)').join('®');
|
||
//if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
|
||
x += '<tr><td style=width:18px><div class=' + icon + '></div></td><td class=g1 style=float:none> </td><td style=background-color:#C9C9C9>' + time.toLocaleTimeString() + ' - ' + msg + '</td><td class=g2 style=float:none> </td></tr><tr style=height:2px></tr>';
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = "<br><i>No Events Found</i><br><br>";
|
||
QH('p16events', x);
|
||
}
|
||
|
||
/*
|
||
function showDeleteAllEventsDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = "Delete all events in the server event log?<br /><br />";
|
||
x += "<input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm";
|
||
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
|
||
validateDeleteAllEventsDialog();
|
||
}
|
||
|
||
function validateDeleteAllEventsDialog() {
|
||
QE('idx_dlgOkButton', Q('p3check').checked);
|
||
}
|
||
|
||
function showDeleteAllEventsDialogEx(buttons, tag) {
|
||
meshserver.send({ action: 'clearevents' });
|
||
}
|
||
*/
|
||
|
||
function refreshDeviceEvents() {
|
||
//currentDeviceEvents = null;
|
||
//QH('p16events', '');
|
||
meshserver.send({ action: 'events', nodeid: currentNode._id, limit: parseInt(p16limitdropdown.value) });
|
||
}
|
||
|
||
//
|
||
// CONSOLE
|
||
//
|
||
|
||
function agentConsoleHandleKeys(e) {
|
||
if ((e.ctrlKey) || (e.altKey)) { return true; }
|
||
var processed = 0, box = Q('p15consoleText');
|
||
if (e.key) {
|
||
if (e.keyCode == 13 && consoleFocus == 0) { p15consoleSend(e); processed = 1; }
|
||
else if (e.keyCode == 8 && consoleFocus == 0) { var x = box.value; box.value = x.substring(0, x.length - 1); processed = 1; }
|
||
else if (e.keyCode == 27) { box.value = ''; processed = 1; }
|
||
else if ((e.keyCode == 38) || (e.keyCode == 40)) { // Arrow up || Arrow down
|
||
var hindex = consoleHistory.indexOf(box.value);
|
||
//console.log(hindex, consoleHistory);
|
||
if ((e.keyCode == 38) && ((consoleHistory.length - 1) > hindex)) { box.value = consoleHistory[hindex + 1]; }
|
||
else if ((e.keyCode == 40) && (hindex > 0)) { box.value = consoleHistory[hindex - 1]; }
|
||
else if ((e.keyCode == 40) && (hindex == 0)) { box.value = ''; }
|
||
processed = 1;
|
||
}
|
||
else if (e.key.length === 1) {
|
||
//box.value = ((box.value + e.key));
|
||
insertTextAtCursor(box, e.key);
|
||
processed = 1;
|
||
}
|
||
} else {
|
||
if (e.charCode != 0 && consoleFocus == 0) { box.value = ((box.value + String.fromCharCode(e.charCode))); processed = 1; }
|
||
}
|
||
if (processed > 0) { return haltEvent(e); }
|
||
}
|
||
|
||
// Insert text at the cursor location on the
|
||
function insertTextAtCursor(ctrl, val) {
|
||
if (document.selection) { ctrl.focus(); sel = document.selection.createRange(); sel.text = val; }
|
||
else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
|
||
var start = ctrl.selectionStart, end = ctrl.selectionEnd;
|
||
ctrl.value = ctrl.value.substring(0, start) + val + ctrl.value.substring(end, ctrl.value.length);
|
||
ctrl.setSelectionRange(end + 1, end + 1);
|
||
} else { ctrl.value += myValue; }
|
||
}
|
||
|
||
var consoleNode;
|
||
var consoleServerText = '';
|
||
function setupConsole() {
|
||
if (xxcurrentView == 115) {
|
||
// Setup server console
|
||
var samenode = (consoleNode == 'server');
|
||
consoleNode = 'server';
|
||
|
||
QH('p15deviceName', 'My Server Console');
|
||
QE('p15consoleText', true);
|
||
QH('p15statetext', '');
|
||
QH('p15coreName', '');
|
||
|
||
if (samenode == false) {
|
||
QH('p15agentConsoleText', consoleServerText);
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
} else {
|
||
// Setup the console
|
||
var samenode = (consoleNode == currentNode);
|
||
consoleNode = currentNode;
|
||
|
||
var mesh = meshes[consoleNode.meshid];
|
||
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
if ((meshrights & 16) != 0) {
|
||
if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
|
||
if (samenode == false) {
|
||
QH('p15agentConsoleText', consoleNode.consoleText);
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
var online = ((consoleNode.conn & 1) != 0) ? true : false;
|
||
QH('p15statetext', online ? "Agent is online" : "Agent is offline");
|
||
QE('p15consoleText', online);
|
||
QE('p15uploadCore', online);
|
||
} else {
|
||
QH('p15statetext', 'Access Denied');
|
||
QE('p15consoleText', false);
|
||
QE('p15uploadCore', false);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Clear the console for this node
|
||
function p15consoleClear() {
|
||
QH('p15agentConsoleText', '');
|
||
Q('id_p15consoleClear').blur();
|
||
if (xxcurrentView == 115) {
|
||
consoleServerText = '';
|
||
} else {
|
||
consoleNode.consoleText = '';
|
||
}
|
||
}
|
||
|
||
// Send a command to the agent
|
||
var consoleHistory = [];
|
||
function p15consoleSend(e) {
|
||
if (e && e.keyCode != 13) return;
|
||
var v = Q('p15consoleText').value, t = '<div style=color:green>> ' + EscapeHtml(Q('p15consoleText').value) + '<br/></div>';
|
||
Q('p15agentConsoleText').innerHTML += t;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
Q('p15consoleText').value = '';
|
||
|
||
if (xxcurrentView == 115) {
|
||
// Send the command to the server - TODO: In the future, we may support multiple servers.
|
||
consoleServerText += t;
|
||
meshserver.send({ action: 'serverconsole', value: v });
|
||
} else {
|
||
// Send the command to the mesh agent
|
||
consoleNode.consoleText += t;
|
||
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value: v });
|
||
}
|
||
|
||
// Add command to history list
|
||
if (v.length > 0) {
|
||
// Move this command to the top if it already exists
|
||
var j = consoleHistory.indexOf(v);
|
||
if (j >= 0) { consoleHistory.splice(j, 1); }
|
||
consoleHistory.unshift(v);
|
||
consoleHistory.splice(10);
|
||
}
|
||
}
|
||
|
||
// Handle Mesh Agent console data
|
||
function p15consoleReceive(node, data) {
|
||
data = '<div>' + data + '</div>'
|
||
if (node === 'serverconsole') {
|
||
// Server console data
|
||
consoleServerText += data;
|
||
if (consoleNode == 'server') {
|
||
Q('p15agentConsoleText').innerHTML += data;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
} else {
|
||
// Agent console data
|
||
if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
|
||
if (consoleNode == node) {
|
||
Q('p15agentConsoleText').innerHTML += data;
|
||
Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Called then user presses the "Change Core" button
|
||
function p15uploadCore(e) {
|
||
if (xxdialogMode) return;
|
||
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'default' }); } // Upload default core
|
||
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' }); } // Clear the core
|
||
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
||
else { setDialogMode(2, "Change Mesh Agent Core", 3, p15uploadCoreEx, '<select id=d3coreMode style=float:right;width:260px><option value=1>Upload default server core</option><option value=2>Clear the core</option><option value=6>Upload recovery core</option><option value=3>Upload a core file</option><option value=4>Soft disconnect agent</option><option value=5>Hard disconnect agent</option></select><div>Change Core</div>'); }
|
||
}
|
||
|
||
function p15uploadCoreEx() {
|
||
if (Q('d3coreMode').value == 1) {
|
||
// Upload default core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'default' });
|
||
} else if (Q('d3coreMode').value == 2) {
|
||
// Clear the core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' });
|
||
} else if (Q('d3coreMode').value == 3) {
|
||
// Upload file as core
|
||
p15uploadCore2();
|
||
} else if (Q('d3coreMode').value == 4) {
|
||
// Soft disconnect the mesh agent
|
||
meshserver.send({ action: 'agentdisconnect', nodeid: consoleNode._id, disconnectMode: 1 });
|
||
} else if (Q('d3coreMode').value == 5) {
|
||
// Hard disconnect the mesh agent
|
||
meshserver.send({ action: 'agentdisconnect', nodeid: consoleNode._id, disconnectMode: 2 });
|
||
} else if (Q('d3coreMode').value == 6) {
|
||
// Upload a recovery core
|
||
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type:'recovery' });
|
||
}
|
||
}
|
||
|
||
// Called then user opts to upload a file as core
|
||
function p15uploadCore2() {
|
||
if (xxdialogMode) return;
|
||
Q('d3localmodeform').action = 'uploadmeshcorefile.ashx';
|
||
Q('d3attrib').value = currentNode._id;
|
||
setDialogMode(3, "Upload Mesh Agent Core", 3, p15uploadCoreEx2);
|
||
d3init();
|
||
}
|
||
|
||
function p15uploadCoreEx2() {
|
||
var mode = Q('d3uploadMode').value;
|
||
if (mode == 1) {
|
||
// Upload local mesh agent core
|
||
Q('d3submit').click();
|
||
} else {
|
||
// Upload server mesh agent code
|
||
var files = d3getFileSel();
|
||
if (files.length == 1) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'custom', path: d3filetreelocation.join('/') + '/' + files[0] }); }
|
||
}
|
||
}
|
||
|
||
//
|
||
// MY ACCOUNT
|
||
//
|
||
|
||
function account_manageAuthApp() {
|
||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||
if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
|
||
}
|
||
|
||
function account_addOtp() {
|
||
if (xxdialogMode || (userinfo.otpsecret == 1) || ((features & 4096) == 0)) return;
|
||
setDialogMode(2, "Authenticator App", 2, function () { meshserver.send({ action: 'otpauth-setup', secret: Q('d2optsecret').attributes.secret.value, token: Q('d2otpauthinput').value }); }, "<div id=d2optinfo>Loading...</div>", 'otpauth-request');
|
||
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, "Authenticator App", 3, function () { meshserver.send({ action: 'otpauth-clear' }); }, "Confirm removal of authenticator application 2-step login?");
|
||
}
|
||
|
||
function account_manageOtp(action) {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-manage')) { dialogclose(0); }
|
||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||
if ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)) { meshserver.send({ action: 'otpauth-getpasswords', subaction: action }); }
|
||
}
|
||
|
||
function account_manageHardwareOtp() {
|
||
if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-hardware-manage')) { dialogclose(0); }
|
||
if (xxdialogMode || ((features & 4096) == 0)) return;
|
||
meshserver.send({ action: 'otp-hkey-get' });
|
||
}
|
||
|
||
function account_addhkey(type) {
|
||
if (type == 1 || type == 3) {
|
||
var x = "Type in the name of the key to add.<br /><br />";
|
||
x += addHtmlValue('Key Name', '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off placeholder="MyKey" onkeyup=account_addhkeyValidate(event,2) />');
|
||
} else if (type == 2) {
|
||
var x = "Type in a key name, select the OTP box and press the button on the YubiKey™.<br /><br />";
|
||
x += addHtmlValue('Key Name', '<input id=dp1keyname style=width:230px maxlength=20 autocomplete=off placeholder="MyKey" onkeyup=account_addhkeyValidate(event,1) />');
|
||
x += addHtmlValue('YubiKey™ OTP', '<input id=dp1key style=width:230px autocomplete=off onkeyup=account_addhkeyValidate(event,2) />');
|
||
}
|
||
setDialogMode(2, "Add Security Key", 3, account_addhkeyEx, x, type);
|
||
Q('dp1keyname').focus();
|
||
}
|
||
|
||
function account_addhkeyValidate(e,action) {
|
||
if ((e != null) && (e.keyCode == 13)) { if (action == 2) { dialogclose(1); } else { Q('dp1key').focus(); } }
|
||
}
|
||
|
||
function account_addhkeyEx(button, type) {
|
||
var name = Q('dp1keyname').value;
|
||
if (name == '') { name = 'MyKey'; }
|
||
if (type == 1) {
|
||
meshserver.send({ action: 'otp-hkey-setup-request', name: name });
|
||
} else if (type == 2) {
|
||
meshserver.send({ action: 'otp-hkey-yubikey-add', name: name, otp: Q('dp1key').value });
|
||
setDialogMode(2, "Add Security Key", 0, null, "<br />Checking...<br /><br /><br />", 'otpauth-hardware-manage');
|
||
} else if (type == 3) {
|
||
meshserver.send({ action: 'webauthn-startregister', name: name });
|
||
}
|
||
}
|
||
|
||
function account_removehkey(index) {
|
||
meshserver.send({ action: 'otp-hkey-remove', index: index });
|
||
meshserver.send({ action: 'otp-hkey-get' });
|
||
}
|
||
|
||
function account_showVerifyEmail() {
|
||
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
|
||
var x = "Click ok to send a verification mail to:<br /><div style=padding:8px><b>" + EscapeHtml(userinfo.email) + "</b></div>Please wait a few minute to receive the verification.";
|
||
setDialogMode(2, "Email Verification", 3, account_showVerifyEmailEx, x);
|
||
}
|
||
|
||
function account_showVerifyEmailEx() {
|
||
meshserver.send({ action: 'verifyemail', email: userinfo.email });
|
||
}
|
||
|
||
function account_showChangeEmail() {
|
||
if (xxdialogMode) return;
|
||
var x = "Change your account email address here.<br /><br />";
|
||
x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=256 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
|
||
setDialogMode(2, "Email Address Change", 3, account_changeEmail, x);
|
||
if (userinfo.email != null) { Q('dp2email').value = userinfo.email; }
|
||
account_validateEmail();
|
||
Q('dp2email').focus();
|
||
}
|
||
|
||
function account_validateEmail(e, email) {
|
||
QE('idx_dlgOkButton', validateEmail(Q('dp2email').value) && (Q('dp2email').value != userinfo.email));
|
||
if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
|
||
}
|
||
|
||
function account_changeEmail() {
|
||
meshserver.send({ action: 'changeemail', email: Q('dp2email').value });
|
||
}
|
||
|
||
function account_showDeleteAccount() {
|
||
if (xxdialogMode) return;
|
||
var x = "To delete this account, type in the account password in both boxes below and hit ok.<br /><br />";
|
||
x += "<form action='" + domainUrl + "deleteaccount' method=post><table style=margin-left:80px><tr>";
|
||
x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>";
|
||
x += "</tr><tr><td align=right>Password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>";
|
||
x += '</tr></table><br /><div style=padding:10px;margin-bottom:4px>';
|
||
x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
|
||
x += '<input id=account_dlgOkButton type=submit value=OK style="float:right;width:80px" onclick=dialogclose(1)>';
|
||
x += '</div><br /></form>';
|
||
setDialogMode(2, "Delete Account", 0, null, x);
|
||
account_validateDeleteAccount();
|
||
Q('apassword1').focus();
|
||
}
|
||
|
||
function account_showChangePassword() {
|
||
if (xxdialogMode) return;
|
||
var x = "Change your account password by entering the old password and new password twice in the boxes below. Password hint can be used but is not recommanded.<br /><br />";
|
||
//x += "<form action='" + domainUrl + "changepassword' method=post>";
|
||
x += "<table style=margin-left:60px>";
|
||
x += "<tr><td align=right>Old password:</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>";
|
||
x += "<tr><td align=right>New password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>";
|
||
x += "<tr><td align=right>New password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>";
|
||
if (features & 0x00010000) { x += "<tr><td align=right>Password hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>"; }
|
||
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>Requirements: ' + r.join(', ') + '.</span>'; }
|
||
}
|
||
x += '<br />';
|
||
//x += '<br /><div style=padding:10px;margin-bottom:4px>';
|
||
//x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
|
||
//x += '<input id=account_dlgOkButton type=submit value=OK style="float:right;width:80px" onclick=dialogclose(1)>';
|
||
//x += '</div><br /></form>';
|
||
setDialogMode(2, "Change Password", 3, account_showChangePasswordEx, x);
|
||
Q('apassword0').focus();
|
||
account_validateNewPassword();
|
||
}
|
||
|
||
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 allowed to create a new device group
|
||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "New Device Group", 1, null, "Unable to create a new device group until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
|
||
|
||
// We are allowed, let's prompt to information
|
||
var x = "Create a new device group using the options below.<br /><br />";
|
||
x += addHtmlValue('Name', '<input id=dp2meshname style=width:230px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
|
||
x += addHtmlValue('Type', '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>Manage using a software agent</option><option value=1>Intel® AMT only, no agent</option></select></div>');
|
||
x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
|
||
setDialogMode(2, "New Device Group", 3, account_createMeshEx, x);
|
||
account_validateMeshCreate();
|
||
Q('dp2meshname').focus();
|
||
}
|
||
|
||
function account_validateMeshCreate() {
|
||
QE('idx_dlgOkButton', Q('dp2meshname').value.length > 0);
|
||
}
|
||
|
||
function account_createMeshEx(button, tag) {
|
||
meshserver.send({ action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: Q('dp2meshtype').value, desc: Q('dp2meshdesc').value });
|
||
}
|
||
|
||
function account_validateDeleteAccount() {
|
||
QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
|
||
}
|
||
|
||
function account_validateNewPassword() {
|
||
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) && (Q('apasswordhint').value != Q('apassword1').value);
|
||
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>Good<span>'; } else { r = '<span style=color:red>Weak<span>'; }
|
||
} else {
|
||
// Password requirements provided, use that
|
||
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||
if (passReq == false) { ok = false; r = '<span style=color:red>Policy<span>' }
|
||
}
|
||
}
|
||
QH('dxPassWarn', r);
|
||
//QE('account_dlgOkButton', ok);
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
// Return a password strength score
|
||
function checkPasswordStrength(password) {
|
||
var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
|
||
if (!password) return 0;
|
||
for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
|
||
for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
|
||
return parseInt(r + (varCount - 1) * 10);
|
||
}
|
||
|
||
// Check password requirements
|
||
function checkPasswordRequirements(password, requirements) {
|
||
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||
var num = 0, lower = 0, upper = 0, nonalpha = 0;
|
||
for (var i = 0; i < password.length; i++) {
|
||
if (/\d/.test(password[i])) { num++; }
|
||
if (/[a-z]/.test(password[i])) { lower++; }
|
||
if (/[A-Z]/.test(password[i])) { upper++; }
|
||
if (/\W/.test(password[i])) { nonalpha++; }
|
||
}
|
||
if (requirements.num && (num < requirements.num)) return false;
|
||
if (requirements.lower && (lower < requirements.lower)) return false;
|
||
if (requirements.upper && (upper < requirements.upper)) return false;
|
||
if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
|
||
return true;
|
||
}
|
||
|
||
function updateMeshes() {
|
||
var r = '';
|
||
var c = 0, count = 0;
|
||
for (i in meshes) {
|
||
// Mesh positioning
|
||
if (c > 1) { r += '</tr><tr>'; c = 0; }
|
||
c++;
|
||
count++;
|
||
|
||
// Mesh rights
|
||
var meshrights = 0;
|
||
if (meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()]) { meshrights = meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; }
|
||
var rights = 'Partial Rights';
|
||
if (meshrights == 0xFFFFFFFF) rights = 'Full Administrator'; else if (meshrights == 0) rights = 'No Rights';
|
||
|
||
// Print the mesh information
|
||
r += '<div onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:431px;height:50px;padding-top:1px;padding-bottom:1px;float:left><div style=float:left;width:30px;height:100%></div><div style=height:100%;cursor:pointer onclick=gotoMesh(\'' + i + '\')><div class=mi style=float:left;width:50px;height:50px></div><div style=height:100%><div class=g1></div><div class=e2 style=width:300px><div class=e1>' + EscapeHtml(meshes[i].name) + '</div><div>' + rights + '</div></div><div class=g2 style=float:left></div></div></div></div>';
|
||
}
|
||
|
||
meshcount = count;
|
||
QH('p2meshes', r);
|
||
QV('p2noMeshFound', count == 0);
|
||
}
|
||
|
||
function gotoMesh(meshid) {
|
||
currentMesh = meshes[meshid];
|
||
p20updateMesh();
|
||
go(20);
|
||
}
|
||
|
||
function server_showRestoreDlg() {
|
||
if (xxdialogMode) return;
|
||
var x = 'Restore the server using a backup, <span style=color:red>this will delete the existing server data</span>. Only do this if you know what you are doing.<br /><br />';
|
||
x += '<form action="/restoreserver.ashx" enctype="multipart/form-data" method="post"><div>';
|
||
x += '<input id=account_dlgFileInput type=file name=datafile style=width:100% accept=".zip,application/octet-stream,application/zip,application/x-zip,application/x-zip-compressed" onchange=account_validateServerRestore()>';
|
||
x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
|
||
x += '<input id=account_dlgOkButton type=submit value=OK style=float:right;width:80px onclick=dialogclose(1)>';
|
||
x += '</div><br /><br /></form>';
|
||
setDialogMode(2, "Restore Server", 0, null, x);
|
||
account_validateServerRestore();
|
||
}
|
||
|
||
function account_validateServerRestore() {
|
||
QE('account_dlgOkButton', Q('account_dlgFileInput').files.length == 1);
|
||
}
|
||
|
||
function server_showVersionDlg() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "MeshCentral Version", 1, null, "Loading...", 'MeshCentralServerUpdate');
|
||
meshserver.send({ action: 'serverversion' });
|
||
}
|
||
|
||
function server_showVersionDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); }
|
||
function server_showVersionDlgEx() { meshserver.send({ action: 'serverupdate' }); }
|
||
|
||
function server_showErrorsDlg() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "MeshCentral Errors", 1, null, "Loading...", 'MeshCentralServerErrors');
|
||
meshserver.send({ action: 'servererrors' });
|
||
}
|
||
function server_showErrorsDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); }
|
||
function server_showErrorsDlgEx() { meshserver.send({ action: 'serverclearerrorlog' }); }
|
||
|
||
//
|
||
// MY MESHS
|
||
//
|
||
|
||
var currentMesh;
|
||
function p20updateMesh() {
|
||
if (currentMesh == null) return;
|
||
QH('p20meshName', EscapeHtml(currentMesh.name));
|
||
var meshtype = 'Unknown #' + currentMesh.mtype;
|
||
var meshrights = 0;
|
||
try { meshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; } catch (ex) { }
|
||
if (currentMesh.mtype == 1) meshtype = 'Intel® AMT only, no agent';
|
||
if (currentMesh.mtype == 2) meshtype = 'Managed using a software agent';
|
||
|
||
var x = '';
|
||
x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
|
||
x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
|
||
|
||
// Display features
|
||
var meshFeatures = [];
|
||
if (currentMesh.flags) { if (currentMesh.flags & 1) { meshFeatures.push('Auto-Remove'); } }
|
||
meshFeatures = meshFeatures.join(', ');
|
||
if (meshFeatures == '') { meshFeatures = '<i>None</i>'; }
|
||
x += addHtmlValue('Features', addLinkConditional(meshFeatures, 'p20editmeshfeatures()', (meshrights & 1) != 0));
|
||
|
||
// Display group type
|
||
x += addHtmlValue('Type', meshtype);
|
||
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
|
||
|
||
// Intel AMT setup
|
||
if (currentMesh.mtype == 2) {
|
||
var intelAmtPolicy = 'No Policy';
|
||
if (currentMesh.amt) {
|
||
if (currentMesh.amt.type == 1) { intelAmtPolicy = 'Deactivate Client Control Mode (CCM)'; }
|
||
else if (currentMesh.amt.type == 2) {
|
||
intelAmtPolicy = 'Simple Client Control Mode (CCM)';
|
||
if (currentMesh.amt.cirasetup == 2) { intelAmtPolicy += ' + CIRA'; }
|
||
}
|
||
}
|
||
x += addHtmlValue('Intel® AMT', addLinkConditional(intelAmtPolicy, 'p20editMeshAmt()', (meshrights & 0xFFFFFFFF) != 0));
|
||
}
|
||
|
||
// Display group note support
|
||
if (meshrights & 1) { x += '<br><input type=button value=Notes title="View notes about this device group" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
|
||
|
||
x += '<br style=clear:both><br>';
|
||
var currentMeshLinks = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
|
||
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a onclick=p20showAddMeshUserDialog() style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Add User</a>'; }
|
||
|
||
if ((meshrights & 4) != 0) {
|
||
if (currentMesh.mtype == 1) {
|
||
x += '<a onclick=addCiraDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new Intel® AMT computer that is located on the internet."><img src=images/icon-installmesh.png border=0 height=12 width=12> Install CIRA</a>';
|
||
x += '<a onclick=addDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new Intel® AMT computer that is located on the local network."><img src=images/icon-installmesh.png border=0 height=12 width=12> Install local</a>';
|
||
}
|
||
if (currentMesh.mtype == 2) {
|
||
x += '<a onclick=addAgentToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new computer to this mesh by installing the mesh agent."><img src=images/icon-addnew.png border=0 height=12 width=12> Install</a>';
|
||
if (features & 64) {
|
||
x += '<a onclick=inviteAgentToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Invite someone to install the mesh agent on this mesh."><img src=images/icon-addnew.png border=0 height=12 width=12> Invite</a>';
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
function getMeshActions(mesh, meshrights) {
|
||
if ((meshrights & 4) == 0) return '';
|
||
var r = '';
|
||
if (mesh.mtype == 1) {
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the local network." onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
|
||
}
|
||
if (mesh.mtype == 2) {
|
||
r += ' <a style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
|
||
}
|
||
return r;
|
||
}
|
||
*/
|
||
|
||
x += '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:left;width:430px>User Authorizations</th><th scope=col style=text-align:left></th></tr>';
|
||
|
||
// 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 = 'Partial Rights', r = sortedusers[i].rights;
|
||
if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights';
|
||
if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") title="Remote user rights to this mesh" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
|
||
x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title="User" class=m2></div><div> ' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
|
||
++count;
|
||
}
|
||
|
||
x += '</tbody></table>';
|
||
|
||
// If we are full administrator on this mesh, allow deletion of the mesh
|
||
if (meshrights == 0xFFFFFFFF) { x += '<div style=font-size:x-small;text-align:right><span><a onclick=p20showDeleteMeshDialog() style=cursor:pointer>Delete Group</a></span></div>'; }
|
||
|
||
QH('p20info', x);
|
||
}
|
||
|
||
function p20editMeshAmt() {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
x += addHtmlValue('Type', '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>No Policy</option><option value=1>Deactivate Client Control Mode (CCM)</option><option value=2>Simple Client Control Mode (CCM)</option></select>');
|
||
x += '<div id=dp20amtpolicydiv></div>';
|
||
setDialogMode(2, "Intel® AMT Policy", 3, p20editMeshAmtEx, x);
|
||
if (currentMesh.amt) { Q('dp20amtpolicy').value = currentMesh.amt.type; }
|
||
p20editMeshAmtChange();
|
||
|
||
// Set the current Intel AMT policy
|
||
if (currentMesh.amt && currentMesh.amt.type == 2) {
|
||
Q('dp20amtpolicypass').value = currentMesh.amt.password;
|
||
Q('dp20amtbadpass').value = currentMesh.amt.badpass;
|
||
if ((features & 0x400) == 0) { Q('dp20amtcira').value = currentMesh.amt.cirasetup; }
|
||
}
|
||
|
||
dp20amtValidatePolicy();
|
||
}
|
||
|
||
function p20editMeshAmtChange() {
|
||
var ptype = Q('dp20amtpolicy').value, x = '';
|
||
if (ptype == 2) {
|
||
x = addHtmlValue('Password*', '<input id=dp20amtpolicypass style=width:230px maxlength=32 onchange=dp20amtValidatePolicy() onkeyup=dp20amtValidatePolicy() />')
|
||
x += addHtmlValue('Password mismatch', "<select id=dp20amtbadpass style=width:230px><option value=0>Do nothing</option><option value=1>Reactivate Intel® AMT</option></select>");
|
||
if ((features & 0x400) == 0) { x += addHtmlValue('<span title="Client Initiated Remote Access">CIRA</span>', "<select id=dp20amtcira style=width:230px><option value=0>Don't configure</option><option value=1>Don't connect to server</option><option value=2>Connect to server</option></select>"); }
|
||
x += '<br/><span style="font-size:10px">* Recommanded, leave blank to assign a random password to each device.</span><br/>';
|
||
x += '<span style="font-size:10px">This policy will not impact devices with Intel® AMT in ACM mode.</span><br/>';
|
||
x += '<span style="font-size:10px">This is not a secure policy as agents will be performing activation.</span>';
|
||
}
|
||
QH('dp20amtpolicydiv', x);
|
||
}
|
||
|
||
function dp20amtValidatePolicy() {
|
||
var ok = true, ptype = Q('dp20amtpolicy').value;
|
||
if (ptype == 2) { var pass = Q('dp20amtpolicypass').value; ok = (pass == '') ? true : passwordcheck(pass); }
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
function p20editMeshAmtEx() {
|
||
var ptype = parseInt(Q('dp20amtpolicy').value), amtpolicy = { type: ptype };
|
||
if (ptype == 2) {
|
||
amtpolicy = { type: ptype, password: Q('dp20amtpolicypass').value, badpass: parseInt(Q('dp20amtbadpass').value) };
|
||
if ((features & 0x400) == 0) { amtpolicy.cirasetup = parseInt(Q('dp20amtcira').value); } else { amtpolicy.cirasetup = 1; }
|
||
}
|
||
meshserver.send({ action: 'meshamtpolicy', meshid: currentMesh._id, amtpolicy: amtpolicy });
|
||
}
|
||
|
||
function p20showDeleteMeshDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = "Are you sure you want to delete group \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the device group will also delete all information about devices within this group.<br /><br />";
|
||
x += "<input id=p20check type=checkbox onchange=p20validateDeleteMeshDialog() />Confirm";
|
||
setDialogMode(2, "Delete Group", 3, p20showDeleteMeshDialogEx, x);
|
||
p20validateDeleteMeshDialog();
|
||
}
|
||
|
||
function p20validateDeleteMeshDialog() {
|
||
QE('idx_dlgOkButton', Q('p20check').checked);
|
||
}
|
||
|
||
function p20showDeleteMeshDialogEx(buttons, tag) {
|
||
meshserver.send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name });
|
||
}
|
||
|
||
function p20editmesh(focus) {
|
||
if (xxdialogMode) return;
|
||
var x = addHtmlValue('Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
|
||
x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
|
||
setDialogMode(2, "Edit Device Group", 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 p20editmeshfeatures() {
|
||
if (xxdialogMode) return;
|
||
var flags = (currentMesh.flags)?currentMesh.flags:0;
|
||
var x = "<div><input type=checkbox id=d20flag1 " + ((flags & 1)?'checked':'') + ">Remove device on disconnect<br></div>";
|
||
setDialogMode(2, "Edit Device Group Features", 3, p20editmeshfeaturesEx, x);
|
||
}
|
||
|
||
function p20editmeshfeaturesEx() {
|
||
var flags = 0;
|
||
if (Q('d20flag1').checked) { flags += 1; }
|
||
meshserver.send({ action: 'editmesh', meshid: currentMesh._id, flags: flags });
|
||
}
|
||
|
||
function p20showAddMeshUserDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = "Allow a user to manage this device group and devices in this group<br /><br />";
|
||
x += addHtmlValue('User Name', '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
|
||
x += '<br><div style="height:120px;overflow-y:scroll;border:1px solid gray">';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>Full Administrator<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>Edit Device Group<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20manageusers>Manage Device Group Users<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20managecomputers>Manage Device Group Computers<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>Remote Control<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>Remote View Only<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>Limited Input Only<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>No Terminal Access<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>No File Access<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>No Intel® AMT<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>Mesh Agent Console<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>Server Files<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
|
||
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
|
||
x += '</div>';
|
||
setDialogMode(2, "Add User to Device Group", 3, p20showAddMeshUserDialogEx, x);
|
||
p20validateAddMeshUserDialog();
|
||
Q('dp20username').focus();
|
||
}
|
||
|
||
function p20validateAddMeshUserDialog() {
|
||
var meshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
|
||
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
|
||
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
|
||
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
|
||
QE('p20manageusers', !Q('p20fulladmin').checked);
|
||
QE('p20managecomputers', !Q('p20fulladmin').checked);
|
||
QE('p20remotecontrol', !Q('p20fulladmin').checked);
|
||
QE('p20meshagentconsole', !Q('p20fulladmin').checked);
|
||
QE('p20meshserverfiles', !Q('p20fulladmin').checked);
|
||
QE('p20wakedevices', !Q('p20fulladmin').checked);
|
||
QE('p20editnotes', !Q('p20fulladmin').checked);
|
||
QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
||
QE('p20remotelimitedinput', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
|
||
QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
||
QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
||
QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
|
||
}
|
||
|
||
function p20showAddMeshUserDialogEx() {
|
||
var meshadmin = 0;
|
||
if (Q('p20fulladmin').checked == true) { meshadmin = 0xFFFFFFFF; } else {
|
||
if (Q('p20editmesh').checked == true) meshadmin += 1;
|
||
if (Q('p20manageusers').checked == true) meshadmin += 2;
|
||
if (Q('p20managecomputers').checked == true) meshadmin += 4;
|
||
if (Q('p20remotecontrol').checked == true) meshadmin += 8;
|
||
if (Q('p20meshagentconsole').checked == true) meshadmin += 16;
|
||
if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
|
||
if (Q('p20wakedevices').checked == true) meshadmin += 64;
|
||
if (Q('p20editnotes').checked == true) meshadmin += 128;
|
||
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;
|
||
}
|
||
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
|
||
}
|
||
|
||
function p20viewuser(userid) {
|
||
if (xxdialogMode) return;
|
||
userid = decodeURIComponent(userid);
|
||
var r = '', cmeshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights, meshrights = currentMesh.links[userid].rights;
|
||
if (meshrights == 0xFFFFFFFF) r = ', Full Administrator (all rights)'; else {
|
||
if ((meshrights & 1) != 0) r += ', Edit Device Group';
|
||
if ((meshrights & 2) != 0) r += ', Manage Device Group Users';
|
||
if ((meshrights & 4) != 0) r += ', Manage Device Group Computers';
|
||
if ((meshrights & 8) != 0) r += ', Remote Control';
|
||
if ((meshrights & 16) != 0) r += ', Agent Console';
|
||
if ((meshrights & 32) != 0) r += ', Server Files';
|
||
if ((meshrights & 64) != 0) r += ', Wake Devices';
|
||
if ((meshrights & 128) != 0) r += ', Edit Notes';
|
||
if (((meshrights & 8) != 0) && (meshrights & 256) != 0) r += ', Remote View Only';
|
||
if (((meshrights & 8) != 0) && (meshrights & 512) != 0) r += ', No Terminal';
|
||
if (((meshrights & 8) != 0) && (meshrights & 1024) != 0) r += ', No Files';
|
||
if (((meshrights & 8) != 0) && (meshrights & 2048) != 0) r += ', No Intel® AMT';
|
||
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r += ', Limited Input';
|
||
}
|
||
r = r.substring(2);
|
||
if (r == '') { r = 'No Rights'; }
|
||
var buttons = 1, x = addHtmlValue('User Name', EscapeHtml(decodeURIComponent(userid.split('/')[2])));
|
||
x += addHtmlValue('Permissions', r);
|
||
if ((('user/' + domain + '/' + userinfo.name.toLowerCase()) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
|
||
setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid);
|
||
}
|
||
|
||
function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid); }
|
||
function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
|
||
function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid}); }
|
||
|
||
//
|
||
// MY FILES
|
||
//
|
||
|
||
var filetreelinkpath;
|
||
var filetreelocation = [];
|
||
|
||
function updateFiles() {
|
||
QV('MainMenuMyFiles', ((features & 8) == 0));
|
||
if ((features & 8) != 0) return; // If running on a server without files, exit now.
|
||
var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p5folderup(0)>Root</a>', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1;
|
||
|
||
// Navigate to path location, build the paths at the same time
|
||
var filetreelocation2 = [], oldlinkpath = filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
|
||
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
|
||
|
||
filetreelinkpath = '';
|
||
for (var i in filetreelocation) {
|
||
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) {
|
||
filetreelocation2.push(filetreelocation[i]);
|
||
fullPath += ' / ' + filetreelocation[i];
|
||
if ((folderdepth == 1)) {
|
||
var sp = filetreelocation[i].split('/');
|
||
publicPath = window.location + sp[0] + 'files/' + sp[2];
|
||
//if (filetreelocation[i] === userinfo._id) { filetreelinkpath += 'self'; } else { filetreelinkpath += (sp[0] + '/' + sp[2]); }
|
||
filetreelinkpath += filetreelocation[i];
|
||
} else {
|
||
if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
|
||
}
|
||
filetreex = filetreex.f[filetreelocation[i]];
|
||
displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + '</a>';
|
||
folderdepth++;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
filetreelocation = filetreelocation2; // In case we could not go down the full path, we set the new path location here.
|
||
var publicfolder = fullPath.toLowerCase().startsWith("root / " + userinfo._id + " / public");
|
||
|
||
// Sort the files
|
||
var filetreexx = p5sort_files(filetreex.f);
|
||
|
||
// Display all files and folders at this location
|
||
for (var i in filetreexx) {
|
||
// Figure out the name and shortname
|
||
var f = filetreexx[i], name = f.n, shortname;
|
||
shortname = name;
|
||
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
|
||
name = EscapeHtml(name);
|
||
|
||
// Figure out the date
|
||
var fdatestr = '';
|
||
if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
|
||
|
||
// Figure out the size
|
||
var fsize = '';
|
||
if (f.s != null) { fsize = getFileSizeStr(f.s); }
|
||
|
||
var h = '';
|
||
if (f.t < 3 || f.t == 4) {
|
||
var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
|
||
h = "<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value='" + name + "'> <span style=float:right title=\"" + title + "\">" + right + "</span><span><div class=fileIcon" + f.t + " onclick=p5folderset(\"" + encodeURIComponent(f.nx) + "\")></div><a style=cursor:pointer onclick=p5folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
|
||
} else {
|
||
var link = shortname;
|
||
var publiclink = '';
|
||
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>Link</a>)'; }
|
||
if (f.s > 0) { link = "<a 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 class=fsize>" + fdatestr + "</span><span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
|
||
}
|
||
|
||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||
}
|
||
|
||
//if (f.parent == null) { }
|
||
QH('p5rightOfButtons', p5getQuotabar(filetreex));
|
||
|
||
QH('p5files', html1 + html2);
|
||
QH('p5currentpath', displayPath);
|
||
QE('p5FolderUp', filetreelocation.length != 0);
|
||
QV('p5PublicShare', publicfolder);
|
||
|
||
// Re-check all boxes if needed
|
||
if (oldlinkpath == filetreelinkpath) {
|
||
checkboxes = document.getElementsByName('fc');
|
||
for (var i = 0; i < checkboxes.length; i++) {
|
||
checkboxes[i].checked = (checkedBoxes.indexOf(checkboxes[i].value) >= 0);
|
||
}
|
||
}
|
||
|
||
p5setActions();
|
||
}
|
||
|
||
function getNiceSize(bytes) {
|
||
if (bytes <= 0) return 'Storage limit exceed';
|
||
if (bytes < 2048) return bytes + ' bytes remaining';
|
||
if (bytes < 2097152) return Math.round(bytes / 1024) + ' kilobytes remaining';
|
||
if (bytes < 2147483648) return Math.round(bytes / 1024 / 1024) + ' megabytes remaining';
|
||
return Math.round(bytes / 1024 / 1024 / 1024) + ' gigabytes remaining';
|
||
}
|
||
|
||
function getNiceSize2(bytes) {
|
||
if (bytes <= 0) return 'None';
|
||
if (bytes < 2048) return bytes + ' b';
|
||
if (bytes < 2097152) return Math.round(bytes / 1024) + ' Kb';
|
||
if (bytes < 2147483648) return Math.round(bytes / 1024 / 1024) + ' Mb';
|
||
return Math.round(bytes / 1024 / 1024 / 1024) + ' Gb';
|
||
}
|
||
|
||
function p5getQuotabar(f) {
|
||
while (f.t > 1 && f.t != 4) { f = f.parent; }
|
||
if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
|
||
var tf = Math.floor(f.s / 1024), tq = (f.maxbytes - f.s);
|
||
return '<span title="' + tf + "k in " + f.c + " file" + (f.c > 1 ? 's' : '') + ". " + (Math.floor(f.maxbytes / 1024 / 1024)) + 'k maxinum">' + getNiceSize(tq) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
|
||
}
|
||
|
||
function p5showPublicLink(u) { setDialogMode(2, "Public Link", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
|
||
|
||
var sortorder;
|
||
function p5sort_filename(a, b) { if (a.ln > b.ln) return (1 * sortorder); if (a.ln < b.ln) return (-1 * sortorder); return 0; }
|
||
function p5sort_timestamp(a, b) { if (a.d > b.d) return (1 * sortorder); if (a.d < b.d) return (-1 * sortorder); return 0; }
|
||
function p5sort_bysize(a, b) { if (a.s == b.s) return p5sort_filename(a, b); return (((a.s - b.s)) * sortorder); }
|
||
|
||
function p5sort_files(files) {
|
||
var r = [], sortselection = Q('p5sortdropdown').value;
|
||
for (var i in files) { files[i].nx = i; if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
|
||
sortorder = 1;
|
||
if (sortselection > 3) { sortorder = -1; sortselection -= 3; }
|
||
if (sortselection == 1) { r.sort(p5sort_filename); }
|
||
else if (sortselection == 2) { r.sort(p5sort_bysize); }
|
||
else if (sortselection == 3) { r.sort(p5sort_timestamp); }
|
||
return r;
|
||
}
|
||
|
||
function p5setActions() {
|
||
var cc = getFileSelCount(), tc = getFileCount(), sfc = getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
|
||
QE('p5DeleteFileButton', (cc > 0) && (filetreelocation.length > 0));
|
||
QE('p5NewFolderButton', filetreelocation.length > 0);
|
||
QE('p5UploadButton', filetreelocation.length > 0);
|
||
QE('p5RenameFileButton', (cc == 1) && (filetreelocation.length > 0));
|
||
QE('p5SelectAllButton', tc > 0);
|
||
Q('p5SelectAllButton').value = (cc > 0 ? 'Select None' : 'Select All');
|
||
QE('p5CutButton', (sfc > 0) && (cc == sfc));
|
||
QE('p5CopyButton', (sfc > 0) && (cc == sfc));
|
||
QE('p5PasteButton', (p5clipboard != null) && (p5clipboard.length > 0) && (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 byte"; return "" + size + " bytes"; }
|
||
function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
|
||
function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); }
|
||
function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
|
||
function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); }
|
||
function p5deletefile() { var cc = getFileSelCount(), rec = (getFileSelDirCount() > 0) ? "<br /><br /><input type=checkbox id=p5recdeleteinput>Recursive delete<br>" : "<input type=checkbox id=p5recdeleteinput style='display:none'>"; setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1) ? ('Delete ' + cc + ' selected items?' + rec) : ('Delete selected item?' + 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, "Rename", 3, p5renamefileEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'fileoperation', fileop: 'rename', path: filetreelocation, oldname: renamefile}); focusTextBox('p5renameinput'); p5fileNameCheck(); }
|
||
function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
|
||
function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e && e.keyCode == 13)) { dialogclose(1); } }
|
||
var isFilenameValid = (function(){ var x1=/^[^\\/:\*\?"<>\|]+$/, x2=/^\./, x3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname){ return x1.test(fname)&&!x2.test(fname)&&!x3.test(fname)&&(fname[0] != '.'); } })();
|
||
function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p5uploadinput\')" /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
|
||
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
|
||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
|
||
|
||
var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
|
||
function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
|
||
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Confim ' + (p5clipboardCut == 0?'copy':'move') + ' of ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
|
||
function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
|
||
function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' for ' + (p5clipboardCut == 0?'copy':'move') + ', <a onclick=p5clearClip() style=cursor:pointer>Clear</a>.' } QH('p5bottomstatus', x); p5setActions(); }
|
||
function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); }
|
||
|
||
function p5fileDragDrop(e) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
QV('bigfail', false);
|
||
QV('bigok', false);
|
||
//QV('p5fileCatchAllInput', false);
|
||
|
||
// For Chrome & Firefox
|
||
var error = 0;
|
||
p5uploadFile(); // Display the the dialog box
|
||
try { Q('p5uploadinput').files = e.dataTransfer.files; } catch (ex) { error = 1; } // Set the files in the dialog box
|
||
if (error == 0) { p5uploadFileEx(); } // Press the submit button
|
||
setDialogMode(0); // Close the dialog box
|
||
|
||
// For IE browser - This will not work with very large files
|
||
if (error == 1) {
|
||
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
|
||
var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length, totalSize = 0;
|
||
for (var i = 0; i < e.dataTransfer.files.length; i++) { totalSize += e.dataTransfer.files[i].size; }
|
||
if (totalSize > 1300000) { p5uploadFile(); return; } // File is too large, not sure what the real maximum is.
|
||
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('*'); // This will not work for large files, there is a limit on the data size in a field.
|
||
Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
|
||
Q('p5loginSubmit2').click();
|
||
}
|
||
}
|
||
reader.readAsDataURL(file);
|
||
}
|
||
}
|
||
}
|
||
|
||
var p5dragtimer = null;
|
||
function p5fileDragOver(e) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
if (p5dragtimer != null) { clearTimeout(p5dragtimer); p5dragtimer = null; }
|
||
var ac = true; // TODO: Set to true if we can accept the file
|
||
if (filetreelocation.length == 0) { ac = false; }
|
||
QV('bigok', ac);
|
||
QV('bigfail', !ac);
|
||
//QV('p5fileCatchAllInput', ac);
|
||
}
|
||
|
||
function p5fileDragLeave(e) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
if (e.target.id != "p5filetable") {
|
||
QV('bigfail', false);
|
||
QV('bigok', false);
|
||
//QV('p5fileCatchAllInput', false);
|
||
} else {
|
||
p5dragtimer = setTimeout(function () { QV('bigfail',false); QV('bigok',false); p5dragtimer=null; }, 10);
|
||
}
|
||
}
|
||
|
||
/*
|
||
function p5fileCatchAllInputChanged(e) {
|
||
p5fileDragLeave(e);
|
||
Q('p5fileDragLink2').value = encodeURIComponent(filetreelinkpath);
|
||
Q('p5fileCatchAllSubmit').click();
|
||
}
|
||
*/
|
||
|
||
//
|
||
// MY EVENTS
|
||
//
|
||
|
||
// Highlights the device being hovered
|
||
function eventMouseHover(e, over) {
|
||
e.children[1].classList.remove('g1s');
|
||
e.children[2].style['background-color'] = ((over == 0) ? '#c9c9c9' : '#b9b9b9');
|
||
e.children[3].classList.remove('g2s');
|
||
if (over == 1) { e.children[1].classList.add('g1s'); e.children[3].classList.add('g2s'); }
|
||
}
|
||
|
||
function eventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in events) {
|
||
var event = events[i], time = new Date(event.time);
|
||
if (time.toLocaleDateString() != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
|
||
dateHeader = time.toLocaleDateString();
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = event.msg.split('(R)').join('®');
|
||
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
|
||
x += '<tr onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1 style=float:none> </td><td style=background-color:#C9C9C9>' + time.toLocaleTimeString() + ' - ' + msg + '</td><td class=g2 style=float:none> </td></tr><tr style=height:2px></tr>';
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = "<br><i>No Events Found</i><br><br>";
|
||
QH('p3events', x);
|
||
}
|
||
|
||
function showDeleteAllEventsDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = "Delete all events in the server event log?<br /><br />";
|
||
x += "<input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm";
|
||
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
|
||
validateDeleteAllEventsDialog();
|
||
}
|
||
|
||
function validateDeleteAllEventsDialog() {
|
||
QE('idx_dlgOkButton', Q('p3check').checked);
|
||
}
|
||
|
||
function showDeleteAllEventsDialogEx(buttons, tag) {
|
||
meshserver.send({ action: 'clearevents' });
|
||
}
|
||
|
||
function refreshEvents() {
|
||
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
|
||
}
|
||
|
||
//
|
||
// MY USERS
|
||
//
|
||
|
||
function updateUsers() {
|
||
QV('MainMenuMyUsers', (users != null) && ((features & 4) == 0));
|
||
QV('LeftMenuMyUsers', (users != null) && ((features & 4) == 0));
|
||
QV('UserNewAccountButton', ((features & 4) == 0) && (serverinfo.domainauth == false));
|
||
if ((users == null) || ((features & 4) != 0)) { QH('p3users', ''); return; }
|
||
|
||
// Sort the list of user id's
|
||
var sortedUserIds = [], maxUsers = 100, hiddenUsers = 0;
|
||
for (var i in users) { sortedUserIds.push(i); }
|
||
sortedUserIds.sort();
|
||
|
||
// Get search
|
||
var userSearch = Q('UserSearchInput').value.toLowerCase();
|
||
var emailSearch = userSearch;
|
||
if (userSearch.startsWith('email:')) { userSearch = null; emailSearch = emailSearch.substring(6); }
|
||
else if (userSearch.startsWith('name:')) { emailSearch = null; userSearch = userSearch.substring(5); }
|
||
else if (userSearch.startsWith('e:')) { userSearch = null; emailSearch = emailSearch.substring(2); }
|
||
else if (userSearch.startsWith('n:')) { emailSearch = null; userSearch = userSearch.substring(2); }
|
||
|
||
// Display the users using the sorted list
|
||
var x = '<table style=width:100% cellpadding=0 cellspacing=0>', addHeader = true;
|
||
x += '<th style=color:gray>Name<th style=color:gray;width:80px>Groups<th style=color:gray;width:120px>Last Access<th style=color:gray;width:120px>Permissions';
|
||
|
||
// Online users
|
||
for (var i in sortedUserIds) {
|
||
var user = users[sortedUserIds[i]], sessions = null;
|
||
if (wssessions != null) { sessions = wssessions[user._id]; }
|
||
if ((sessions != null) &&
|
||
((userSearch != null) && ((userSearch == '') || (user.name.toLowerCase().indexOf(userSearch) >= 0)) ||
|
||
((emailSearch != null) && ((user.email != null) && (user.email.toLowerCase().indexOf(emailSearch) >= 0))))
|
||
) {
|
||
if (maxUsers > 0) {
|
||
if (addHeader) { x += '<tr><td class=userTableHeader colspan=4>Online Users'; addHeader = false; }
|
||
x += addUserHtml(user, sessions);
|
||
maxUsers--;
|
||
} else {
|
||
hiddenUsers++;
|
||
}
|
||
}
|
||
}
|
||
addHeader = true;
|
||
// Offline users
|
||
for (var i in sortedUserIds) {
|
||
var user = users[sortedUserIds[i]], sessions = null;
|
||
if (wssessions != null) { sessions = wssessions[user._id]; }
|
||
if ((sessions == null) &&
|
||
((userSearch != null) && ((userSearch == '') || (user.name.toLowerCase().indexOf(userSearch) >= 0)) ||
|
||
((emailSearch != null) && ((user.email != null) && (user.email.toLowerCase().indexOf(emailSearch) >= 0))))
|
||
) {
|
||
if (maxUsers > 0) {
|
||
if (addHeader) { x += '<tr><td class=userTableHeader colspan=4>Offline Users'; addHeader = false; }
|
||
x += addUserHtml(user, sessions);
|
||
maxUsers--;
|
||
} else {
|
||
hiddenUsers++;
|
||
}
|
||
}
|
||
}
|
||
x += '</table>';
|
||
if (hiddenUsers == 1) { x += '<br />1 more user not shown, use search box to look for users...<br />'; }
|
||
else if (hiddenUsers > 1) { x += '<br />' + hiddenUsers + ' more users not shown, use search box to look for users...<br />'; }
|
||
if (maxUsers == 100) { x += '<br />No users found.<br />'; }
|
||
QH('p3users', x);
|
||
|
||
// Update current user panel if needed
|
||
if ((currentUser != null) && (xxcurrentView == 30)) { gotoUser(encodeURIComponent(currentUser._id),true); }
|
||
}
|
||
|
||
function addUserHtml(user, sessions) {
|
||
var x = '', gray = ' gray', icon = 'm2', msg = '', self = (user.name != userinfo.name), lastAccess = '', permissions = '';
|
||
if (sessions != null) {
|
||
gray = '';
|
||
if (self) {
|
||
msg = "<span style=float:right;margin-top:1px;margin-right:4px title=Chat><a onclick=userChat(event,\"" + encodeURIComponent(user._id) + "\",\"" + encodeURIComponent(user.name) + "\")><img src='images/icon-chat.png' height=16 width=16 style=padding-top:2px /></a></span>";
|
||
msg += "<span style=float:right;margin-top:1px;margin-left:4px;margin-right:4px title=Notify><a onclick=showUserAlertDialog(event,\"" + encodeURIComponent(user._id) + "\")><img src='images/icon-notify.png' height=16 width=16 style=padding-top:2px /></a></span>";
|
||
}
|
||
if (sessions == 1) { lastAccess += '1 session'; } else { lastAccess += sessions + ' sessions'; }
|
||
} else {
|
||
if (user.login) { lastAccess += '<span title="Last login: ' + new Date(user.login * 1000).toLocaleString() + '">' + new Date(user.login * 1000).toLocaleDateString() + '</span>'; }
|
||
}
|
||
if (self) { permissions += "<a style=cursor:pointer onclick=showUserAdminDialog(event,\"" + encodeURIComponent(user._id) + "\")>"; }
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { permissions += "Locked, "; }
|
||
permissions += "<span title='Server Permissions'>";
|
||
if ((user.siteadmin == null) || (user.siteadmin == 0) || (user.siteadmin == 32)) {
|
||
permissions += "User";
|
||
} else if (user.siteadmin == 8) {
|
||
permissions += "User + Files";
|
||
} else if (user.siteadmin == 0xFFFFFFFF) {
|
||
permissions += "Administrator";
|
||
} else {
|
||
permissions += "Partial";
|
||
}
|
||
permissions += "</span>";
|
||
//if ((user.quota != null) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
|
||
if (self) { permissions += "</a>"; }
|
||
|
||
var groups = 0
|
||
if (user.links) { for (var i in user.links) { groups++; } }
|
||
|
||
var username = EscapeHtml(user.name), emailVerified = '';
|
||
if (serverinfo.emailcheck == true) { emailVerified = ((user.emailVerified != true) ? ' <b style=color:red title="Email is not verified">🗴</b>' : ' <b style=color:green title="Email is verified">🗸</b>'); }
|
||
if (user.email != null) { username += ', <a onclick=doemail(event,\"' + user.email + '\")>' + user.email + '</a>' + emailVerified; }
|
||
|
||
if ((user.otpsecret > 0) || (user.otphkeys > 0)) { username += ' <img src="images/key12.png" height=12 width=11 title="2nd factor authentication enabled" style="margin-top:2px" />'; }
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { username += ' <img src="images/padlock12.png" height=12 width=8 title="Account is locked" style="margin-top:2px" />'; }
|
||
|
||
x += '<tr onmouseover=userMouseHover(this,1) onmouseout=userMouseHover(this,0)><td style=cursor:pointer onclick=gotoUser(\"' + encodeURIComponent(user._id) + '\")>';
|
||
x += '<div class=bar style=height:24px;width:100%;font-size:medium>';
|
||
x += '<div style=float:left;height:24px;width:24px;background-color:white><div class="' + icon + gray + '" style=width:16px;margin-top:4px;margin-left:2px;height:16px></div></div>';
|
||
x += '<div class=g1 style=height:24px;float:left></div><div class=g2 style=height:24px;float:right></div>';
|
||
x += '<div><span>' + username + '</span>' + msg + '</div></div><td style=text-align:center>' + groups + '<td style=text-align:center>' + lastAccess + '<td style=text-align:center>' + permissions;
|
||
return x;
|
||
}
|
||
|
||
// Highlights the user being hovered
|
||
function userMouseHover(element, over) {
|
||
var e = element.children[0].children[0];
|
||
e.children[1].classList.remove('g1s');
|
||
e.children[2].classList.remove('g2s');
|
||
if (over == 1) { e.children[1].classList.add('g1s'); e.children[2].classList.add('g2s'); }
|
||
element.children[0].children[0].style['background-color'] = ((over == 0) ? '#c9c9c9' : '#b9b9b9');
|
||
}
|
||
|
||
function userChat(e, userid, name) {
|
||
haltEvent(e);
|
||
var url = '/messenger?id=meshmessenger/' + userid + '/' + encodeURIComponent(userinfo._id) + '&title=' + name;
|
||
if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
|
||
window.open(url, 'meshmessenger:' + userid);
|
||
meshserver.send({ action: 'meshmessenger', userid: decodeURIComponent(userid) });
|
||
return false;
|
||
}
|
||
|
||
function showUserAlertDialog(e, userid) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
setDialogMode(2, "Notify " + EscapeHtml(users[decodeURIComponent(userid)].name), 3, showUserAlertDialogEx, 'Send a text notification to this user.<textarea id=d2notifyText maxlength=2048 style="width:100%;height:184px;resize:none"></textarea>', userid);
|
||
Q('d2notifyText').focus();
|
||
return false;
|
||
}
|
||
|
||
function showUserAlertDialogEx(button, userid) { meshserver.send({ action: 'notifyuser', userid: decodeURIComponent(userid), msg: Q('d2notifyText').value }); }
|
||
|
||
function doemail(e, addr) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
window.open("mailto:" + addr);
|
||
return false;
|
||
}
|
||
|
||
function showUserBroadcastDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = 'Broadcast a message to all connected users.<textarea id=broadcastMessage value="" style=width:370px;height:100px;resize:none maxlength=256 /></textarea>';
|
||
setDialogMode(2, "Broadcast Message", 3, showUserBroadcastDialogEx, x);
|
||
Q('broadcastMessage').focus();
|
||
}
|
||
|
||
function showUserBroadcastDialogEx() {
|
||
meshserver.send({ action: 'userbroadcast', msg: Q('broadcastMessage').value });
|
||
}
|
||
|
||
function showCreateNewAccountDialog() {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
x += addHtmlValue('Name', '<input id=p4name style=width:230px maxlength=64 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += addHtmlValue('Email', '<input id=p4email style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
|
||
x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>';
|
||
|
||
if (passRequirements) {
|
||
var r = [], rc = 0;
|
||
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
|
||
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
|
||
}
|
||
|
||
setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x);
|
||
showCreateNewAccountDialogValidate();
|
||
Q('p4name').focus();
|
||
}
|
||
|
||
function showCreateNewAccountDialogValidate(x) {
|
||
if ((x == null) && (Q('p4email').value.length > 0) && (validateEmail(Q('p4email').value)) == false) { QE('idx_dlgOkButton', false); return; }
|
||
var ok = (!Q('p4name') || ((Q('p4name').value.length > 0) && (Q('p4name').value.indexOf(' ') == -1))) && Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value && checkPasswordRequirements(Q('p4pass1').value, passRequirements);
|
||
if (ok && passRequirements) { if (checkPasswordRequirements(Q('p4pass1').value, passRequirements) == false) { ok = false; } }
|
||
QE('idx_dlgOkButton', ok);
|
||
}
|
||
|
||
function showCreateNewAccountDialogEx() {
|
||
meshserver.send({ action: 'adduser', username: Q('p4name').value, email: Q('p4email').value, pass: Q('p4pass1').value, resetNextLogin: Q('p4resetNextLogin').checked });
|
||
}
|
||
|
||
function showUserAdminDialog(e, userid) {
|
||
if (xxdialogMode) return;
|
||
haltEvent(e);
|
||
userid = decodeURIComponent(userid);
|
||
var x = '<div>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fileaccess>Server Files, <input type=number onchange=showUserAdminDialogValidate() maxlength=10 style=width:80px;text-align:right id=ua_fileaccessquota>k max, blank for default<br><hr/>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fulladmin>Full Administrator<br>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverbackup>Server Backup<br>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverrestore>Server Restore<br>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverupdate>Server Updates<br>';
|
||
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_manageusers>Manage Users<br>';
|
||
x += '<hr/><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_lockedaccount>Lock Account<br>';
|
||
x += '</div>';
|
||
var user = users[userid.toLowerCase()];
|
||
setDialogMode(2, "Server Permissions", 3, showUserAdminDialogEx, x, user);
|
||
if (user.siteadmin && user.siteadmin != 0) {
|
||
Q('ua_fulladmin').checked = (user.siteadmin == 0xFFFFFFFF);
|
||
Q('ua_serverbackup').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1) != 0)); // Server Backup
|
||
Q('ua_manageusers').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 2) != 0)); // Manage Users
|
||
Q('ua_serverrestore').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 4) != 0)); // Server Restore
|
||
Q('ua_fileaccess').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 8) != 0)); // Server Files
|
||
Q('ua_serverupdate').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 16) != 0)); // Server Update
|
||
Q('ua_lockedaccount').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 32) != 0)); // Account locked
|
||
}
|
||
QE('ua_fulladmin', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_serverbackup', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_manageusers', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_serverrestore', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_fileaccess', userinfo.siteadmin == 0xFFFFFFFF);
|
||
QE('ua_serverupdate', userinfo.siteadmin == 0xFFFFFFFF);
|
||
Q('ua_fileaccessquota').value = (user.quota != null)?(user.quota / 1024):'';
|
||
showUserAdminDialogValidate();
|
||
return false;
|
||
}
|
||
|
||
function showUserAdminDialogValidate() {
|
||
if (userinfo.siteadmin == 0xFFFFFFFF) {
|
||
QE('ua_serverbackup', !Q('ua_fulladmin').checked);
|
||
QE('ua_manageusers', !Q('ua_fulladmin').checked);
|
||
QE('ua_serverrestore', !Q('ua_fulladmin').checked);
|
||
QE('ua_fileaccess', !Q('ua_fulladmin').checked);
|
||
QE('ua_serverupdate', !Q('ua_fulladmin').checked);
|
||
QE('ua_fileaccessquota', Q('ua_fileaccess').checked && !Q('ua_fulladmin').checked);
|
||
}
|
||
}
|
||
|
||
function showUserAdminDialogEx(button, user) {
|
||
var siteadmin = 0, quota = parseInt(Q('ua_fileaccessquota').value);
|
||
if (Q('ua_fulladmin').checked == true) { siteadmin = 0xFFFFFFFF; } else {
|
||
if (Q('ua_serverbackup').checked == true) siteadmin += 1;
|
||
if (Q('ua_manageusers').checked == true) siteadmin += 2;
|
||
if (Q('ua_serverrestore').checked == true) siteadmin += 4;
|
||
if (Q('ua_fileaccess').checked == true) siteadmin += 8;
|
||
if (Q('ua_serverupdate').checked == true) siteadmin += 16;
|
||
if (Q('ua_lockedaccount').checked == true) siteadmin += 32;
|
||
}
|
||
var x = { action: 'edituser', name: user.name, siteadmin: siteadmin };
|
||
if (isNaN(quota) == false) { x.quota = (quota * 1024); }
|
||
meshserver.send(x);
|
||
}
|
||
|
||
function onUserSearchInputChanged() { updateUsers(); }
|
||
|
||
//
|
||
// MY USERS GENERAL
|
||
//
|
||
|
||
var currentUser = null;
|
||
function gotoUser(userid, force) {
|
||
if (xxdialogMode && !force) return;
|
||
var user = currentUser = users[decodeURIComponent(userid)];
|
||
if (user == null) { setDialogMode(0); go(4); return; }
|
||
QH('p30userName', user.name);
|
||
QH('p31userName', user.name);
|
||
var self = (user.name == userinfo.name), activeSessions = 0;
|
||
if (wssessions != null && wssessions[user._id]) { activeSessions = wssessions[user._id]; }
|
||
|
||
// Change user grayscale
|
||
Q('MainUserImage').classList.remove('gray');
|
||
if (activeSessions == 0) { Q('MainUserImage').classList.add('gray'); }
|
||
|
||
// Server permissions
|
||
var msg = '', premsg = '';
|
||
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { premsg = '<img src="images/padlock12.png" height=12 width=8 title="Account is locked" style="margin-top:2px" /> '; msg += 'Locked account, '; }
|
||
if ((user.siteadmin == null) || (user.siteadmin == 0) || (user.siteadmin == 32)) { msg += "No server rights"; } else if (user.siteadmin == 8) { msg += "Access to server files"; } else if (user.siteadmin == 0xFFFFFFFF) { msg += "Full administrator"; } else { msg += "Partial rights"; }
|
||
|
||
// Show user attributes
|
||
var x = '<div style=min-height:80px><table style=width:100%>';
|
||
var email = user.email?EscapeHtml(user.email):'<i>Not set</i>', everify = '';
|
||
if (serverinfo.emailcheck) { everify = ((user.emailVerified == true)?'<b style=color:green;cursor:pointer title="Email is verified">🗸</b> ':'<b style=color:red;cursor:pointer title="Email not verified">🗴</b> '); }
|
||
x += addDeviceAttribute('Email', everify + "<a style=cursor:pointer onclick=p30showUserEmailChangeDialog(event,\"" + userid + "\")>" + email + '</a> <a style=cursor:pointer onclick=doemail(event,\"' + user.email + '\")><img class=hoverButton width=10 height=10 src="images/link1.png" /></a>');
|
||
x += addDeviceAttribute('Server Rights', premsg + "<a style=cursor:pointer onclick=showUserAdminDialog(event,\"" + userid + "\")>" + msg + "</a>");
|
||
if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k');
|
||
x += addDeviceAttribute('Creation', new Date(user.creation * 1000).toLocaleString());
|
||
if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login * 1000).toLocaleString());
|
||
if (user.passchange == -1) { x += addDeviceAttribute('Password', 'Will be changed on next login.'); }
|
||
else if (user.passchange) { x += addDeviceAttribute('Password', 'Last changed: ' + new Date(user.passchange * 1000).toLocaleString()); }
|
||
|
||
var linkCount = 0, linkCountStr = '<i>None<i>';
|
||
if (user.links) {
|
||
for (var i in user.links) { linkCount++; }
|
||
if (linkCount == 1) { linkCountStr = '1 group'; } else if (linkCount > 1) { linkCountStr = linkCount + ' groups'; }
|
||
}
|
||
x += addDeviceAttribute('Device Groups', linkCountStr);
|
||
|
||
var multiFactor = 0;
|
||
if ((user.otpsecret > 0) || (user.otphkeys > 0)) {
|
||
multiFactor = 1;
|
||
var factors = [];
|
||
if (user.otpsecret > 0) { factors.push('Authentication App'); }
|
||
if (user.otphkeys > 0) { factors.push('Security Key'); }
|
||
if (user.otpkeys > 0) { factors.push('Backup Codes'); }
|
||
x += addDeviceAttribute('Security', '<img src="images/key12.png" height=12 width=11 title="2nd factor authentication enabled" style="margin-top:2px" /> ' + factors.join(', '));
|
||
}
|
||
|
||
x += '</table></div><br />';
|
||
|
||
// Add action buttons
|
||
x += '<input type=button value=Notes title="View notes about this user" onclick=showNotes(false,"' + userid + '") />';
|
||
if (!self && (activeSessions > 0)) { x += '<input type=button value=Notify title="Send user notification" onclick=showUserAlertDialog(event,"' + userid + '") />'; }
|
||
|
||
// Setup the panel
|
||
QH('p30html', x);
|
||
|
||
// Draw the user timeline
|
||
drawUserTimeline();
|
||
|
||
// Check if we can delete this user
|
||
var deletePossible = true;
|
||
if (user._id == userinfo._id) deletePossible = false;
|
||
if (user.siteadmin && user.siteadmin > 0 && userinfo.siteadmin != 0xFFFFFFFF) deletePossible = false;
|
||
|
||
// Show bottom buttons
|
||
x = '<div style=float:right;font-size:x-small>';
|
||
if (deletePossible) x += '<a style=cursor:pointer onclick=p30showDeleteUserDialog() title="Remove this user">Delete User</a>';
|
||
x += '</div><div style=font-size:x-small>';
|
||
if (userinfo.siteadmin == 0xFFFFFFFF) x += '<a style=cursor:pointer onclick=p30showUserChangePassDialog(' + multiFactor + ') title="Change the password for this user">Change Password</a>';
|
||
x += '</div><br>'
|
||
QH('p30html3', x);
|
||
|
||
// Update user's connection state
|
||
x = '';
|
||
if (activeSessions == 1) { x = '1 active session'; } else if (activeSessions > 1) { x = activeSessions + ' active sessions'; }
|
||
QH('MainUserState', x);
|
||
|
||
go(30);
|
||
|
||
// Update user events (TODO: do this only if we change users)
|
||
QH('p31events', '');
|
||
refreshUsersEvents();
|
||
}
|
||
|
||
// Display the user's email change dialog box
|
||
function p30showUserEmailChangeDialog(event) {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
x += addHtmlValue('Email', '<input id=dp30email style=width:230px maxlength=32 onchange=p30validateEmail() onkeyup=p30validateEmail() />');
|
||
if (serverinfo.emailcheck) { x += addHtmlValue('Status', '<select id=dp30verified style=width:230px onchange=p30validateEmail()><option value=0>Not verified</option><option value=1>Verified</option></select>'); }
|
||
setDialogMode(2, "Change Email for " + EscapeHtml(currentUser.name), 3, p30showUserEmailChangeDialogEx, x);
|
||
Q('dp30email').focus();
|
||
Q('dp30email').value = currentUser.email;
|
||
if (serverinfo.emailcheck) { Q('dp30verified').value = currentUser.emailVerified?1:0; }
|
||
p30validateEmail();
|
||
}
|
||
|
||
// Perform validation on the user's email change dialog box
|
||
function p30validateEmail() {
|
||
var v = Q('dp30email').value, x = v.split('@');
|
||
x = (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (v.length < 1024) && ((v != userinfo.email) || ((serverinfo.emailcheck == true) && (Q('dp30verified').value != (userinfo.emailVerified?1:0))));
|
||
QE('idx_dlgOkButton', x);
|
||
}
|
||
|
||
// Send to the server the new user's email address and validation status
|
||
function p30showUserEmailChangeDialogEx() {
|
||
var x = { action: 'edituser', name: currentUser.name, email: Q('dp30email').value };
|
||
if (serverinfo.emailcheck) { x.emailVerified = (Q('dp30verified').value == 1); }
|
||
meshserver.send(x);
|
||
}
|
||
|
||
// Display the user's password change dialog box
|
||
function p30showUserChangePassDialog(multiFactor) {
|
||
if (xxdialogMode) return;
|
||
var x = '';
|
||
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
|
||
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate(1) onkeyup=showCreateNewAccountDialogValidate(1)></input>');
|
||
if (features & 0x00010000) { x += addHtmlValue('Password hint', '<input id=p4hint type=text style=width:230px maxlength=256></input>'); }
|
||
|
||
if (passRequirements) {
|
||
var r = [], rc = 0;
|
||
for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
|
||
if (rc > 0) { x += '<div style=font-size:x-small;padding:6px>Requirements: ' + r.join(', ') + '.</div>'; }
|
||
}
|
||
|
||
x += '<div><input id=p4resetNextLogin type=checkbox />Force password reset on next login.</div>';
|
||
if (multiFactor == 1) { x += '<div><input id=p4twoFactorRemove type=checkbox />Remove all 2nd factor authentication.</div>'; }
|
||
setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x, multiFactor);
|
||
showCreateNewAccountDialogValidate(1);
|
||
Q('p4pass1').focus();
|
||
}
|
||
|
||
function p30showUserChangePassDialogEx(b, tag) {
|
||
var removeMultiFactor = false;
|
||
if ((tag == 1) && (Q('p4twoFactorRemove').checked == true)) { removeMultiFactor = true; }
|
||
if (Q('p4pass1').value == Q('p4pass2').value) {
|
||
var r = { action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value, removeMultiFactor: removeMultiFactor, resetNextLogin: Q('p4resetNextLogin').checked };
|
||
if (features & 0x00010000) { r.hint = Q('p4hint').value; }
|
||
meshserver.send(r);
|
||
}
|
||
}
|
||
|
||
function p30showDeleteUserDialog() {
|
||
if (xxdialogMode) return;
|
||
setDialogMode(2, "Delete User " + EscapeHtml(currentUser.name), 3, p30showDeleteUserDialogEx, 'Confirm deletion of user ' + EscapeHtml(currentUser.name) + '?');
|
||
}
|
||
|
||
function p30showDeleteUserDialogEx() {
|
||
meshserver.send({ action: 'deleteuser', userid: currentUser._id, username: currentUser.name });
|
||
}
|
||
|
||
// Draw device power bars. The bars are 766px wide.
|
||
function drawUserTimeline() {
|
||
var timeline = null, now = Date.now();
|
||
//if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
||
timeline = [];
|
||
|
||
// Calculate when the timeline starts
|
||
var d = new Date();
|
||
d.setHours(0, 0, 0, 0);
|
||
d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
|
||
var timelineStart = d.getTime();
|
||
|
||
// De-compact the timeline
|
||
var timeline2 = [];
|
||
if (timeline != null && timeline.length > 1) {
|
||
timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
|
||
var ct = timeline[1];
|
||
for (var i = 2; i < timeline.length; i += 2) {
|
||
var power = timeline[i], dt = now;
|
||
if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
|
||
timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
|
||
ct = ct + dt;
|
||
}
|
||
}
|
||
|
||
// Draw the timeline
|
||
var x = '', count = 1, date = new Date();
|
||
date.setHours(0, 0, 0, 0);
|
||
for (var i = 0; i < 7; i++) {
|
||
var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
|
||
for (var j in timeline2) {
|
||
var block = timeline2[j];
|
||
if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
|
||
var ts = Math.max(start, block[0]);
|
||
var te = Math.min(Math.min(end, block[1]), now);
|
||
var width = Math.round((te - ts) / 112794);
|
||
if (width > 0) {
|
||
var title = powerStateStrings2[block[2]] + ' from ' + new Date(ts).toLocaleTimeString() + ' to ' + new Date(te).toLocaleTimeString() + '.';
|
||
datavalue += '<div title="' + title + '" style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>';
|
||
}
|
||
}
|
||
}
|
||
x += '<tr style=' + (((count % 2) == 0)?'background-color:#DDD':'') + '><td><div> ' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
|
||
++count;
|
||
date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
|
||
}
|
||
QH('p30html2', '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:center;width:150px>Day</th><th scope=col style=text-align:center>7 Day Login State</th></tr>' + x + '</tbody></table>');
|
||
}
|
||
|
||
//
|
||
// MY USERS EVENTS
|
||
//
|
||
|
||
var currentUserEvents = null;
|
||
function userEventsUpdate() {
|
||
var x = '', dateHeader = null;
|
||
for (var i in currentUserEvents) {
|
||
var event = currentUserEvents[i];
|
||
var time = new Date(event.time);
|
||
if (time.toLocaleDateString() != dateHeader) {
|
||
if (dateHeader != null) x += '</table>';
|
||
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
|
||
dateHeader = time.toLocaleDateString();
|
||
}
|
||
var icon = 'si3';
|
||
if (event.etype == 'user') icon = 'm2';
|
||
if (event.etype == 'server') icon = 'si3';
|
||
|
||
var msg = event.msg.split('(R)').join('®');
|
||
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
|
||
x += '<tr><td><div class=bar18 style=height:18px;width:100%;font-size:medium>';
|
||
x += '<div style=float:left;height:18px;width:18px;background-color:white><div class=' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
|
||
x += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
|
||
x += '<div style=font-size:14px><span style=width:300px>' + time.toLocaleTimeString() + ' - ' + msg + '</span></div></div></td></tr>';
|
||
}
|
||
if (dateHeader != null) x += '</table>';
|
||
if (x == '') x = "<br><i>No Events Found</i><br><br>";
|
||
QH('p31events', x);
|
||
}
|
||
|
||
function refreshUsersEvents() {
|
||
meshserver.send({ action: 'events', limit: parseInt(p31limitdropdown.value), user: currentUser.name });
|
||
}
|
||
|
||
//
|
||
// FILE SELECTOR, DIALOG 3
|
||
//
|
||
|
||
function d3init() {
|
||
Q('d3localFile').value = '';
|
||
d3modechange();
|
||
}
|
||
|
||
function d3modechange() {
|
||
var mode = Q('d3uploadMode').value;
|
||
QV('d3localmode', mode == 1);
|
||
QV('d3servermode', mode == 2);
|
||
if (mode == 1) { d3setActions(); } else { d3updatefiles(); }
|
||
}
|
||
|
||
var d3filetreelinkpath;
|
||
var d3filetreelocation = [];
|
||
|
||
function d3updatefiles() {
|
||
if (Q('d3uploadMode').value == 1) return;
|
||
var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1;
|
||
|
||
// Navigate to path location, build the paths at the same time
|
||
var d3filetreelocation2 = [], oldlinkpath = d3filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
|
||
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
|
||
|
||
d3filetreelinkpath = '';
|
||
for (var i in d3filetreelocation) {
|
||
if ((filetreex.f != null) && (filetreex.f[d3filetreelocation[i]] != null)) {
|
||
d3filetreelocation2.push(d3filetreelocation[i]);
|
||
if ((folderdepth == 1)) {
|
||
var sp = d3filetreelocation[i].split('/');
|
||
publicPath = window.location + sp[0] + 'files/' + sp[2];
|
||
if (d3filetreelocation[i] === userinfo._id) { d3filetreelinkpath += 'self'; } else { d3filetreelinkpath += (sp[0] + '/' + sp[2]); }
|
||
} else {
|
||
if (d3filetreelinkpath != '') { d3filetreelinkpath += '/' + d3filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + d3filetreelocation[i]; } }
|
||
}
|
||
filetreex = filetreex.f[d3filetreelocation[i]];
|
||
folderdepth++;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
d3filetreelocation = d3filetreelocation2; // In case we could not go down the full path, we set the new path location here.
|
||
|
||
// Sort the files
|
||
var filetreexx = p5sort_files(filetreex.f);
|
||
|
||
// Display all files and folders at this location
|
||
for (var i in filetreexx) {
|
||
// Figure out the name and shortname
|
||
var f = filetreexx[i], name = f.n, shortname;
|
||
shortname = name;
|
||
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
|
||
name = EscapeHtml(name);
|
||
|
||
// Figure out the size
|
||
var fsize = '';
|
||
if (f.s != null) { fsize = getFileSizeStr(f.s); }
|
||
|
||
var h = '';
|
||
if (f.t < 3) {
|
||
var title = '';
|
||
h = "<div class=filelist file=999><span style=float:right title=\"" + title + "\"></span><span><div class=fileIcon" + f.t + " onclick=d3folderset(\"" + encodeURIComponent(f.nx) + "\")></div> <a style=cursor:pointer onclick=d3folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
|
||
} else {
|
||
var link = shortname;
|
||
//if (f.s > 0) { link = "<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=" + encodeURIComponent(filetreelinkpath + '/' + f.nx) + "\">" + shortname + "</a>"; }
|
||
h = "<div class=filelist file=3><input style=float:left name=fcx class=fcb type=checkbox onchange=d3setActions() value='" + f.nx + "'> <span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
|
||
}
|
||
|
||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||
}
|
||
|
||
QH('d3serverfiles', html1 + html2);
|
||
QE('p3FolderUp', d3filetreelocation.length > 0);
|
||
d3setActions();
|
||
}
|
||
|
||
function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); }
|
||
function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
|
||
function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; }
|
||
function d3setActions() {
|
||
var mode = Q('d3uploadMode').value;
|
||
if (mode == 1) {
|
||
QE('idx_dlgOkButton', Q('d3localFile').value.length > 0);
|
||
} else {
|
||
QE('idx_dlgOkButton', d3getFileSel().length == 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// NOTIFICATIONS
|
||
//
|
||
|
||
var notifications = [];
|
||
|
||
// Toggle showing notifications
|
||
function clickNotificationIcon(show) {
|
||
//addNotification({ icon:0, text:'test' });
|
||
if (show == true) { QV('notifiyBox', true); } else if (show == false) { QV('notifiyBox', false); } else { QV('notifiyBox', QS('notifiyBox')['display'] == 'none'); }
|
||
drawNotifications();
|
||
}
|
||
|
||
// Set the notification count on the upper right oft he screen
|
||
function setNotificationCount(c) {
|
||
if (parseInt(Q('notificationCount').innerHTML) == c) return; // If the count did not change, exit now.
|
||
QH('notificationCount', c);
|
||
QS('notificationCount')['background-color'] = (c == 0)?'lightblue':'orange';
|
||
QV('notificationCount', c > 0);
|
||
}
|
||
|
||
// Refresh the notification box
|
||
function drawNotifications() {
|
||
var r = '';
|
||
if (notifications.length == 0) {
|
||
r = '<div style=margin:5px>There are currently no notifications</div>';
|
||
} else {
|
||
for (var i in notifications) {
|
||
var n = notifications[i];
|
||
var t = '';
|
||
var d = new Date(n.time);
|
||
var icon = 0;
|
||
if (n.nodeid != null) {
|
||
var node = getNodeFromId(n.nodeid);
|
||
if (node != null) {
|
||
//console.log(node);
|
||
icon = node.icon;
|
||
t = '<b>' + node.name + '</b>: '
|
||
}
|
||
}
|
||
|
||
r += '<div title="Occured at ' + d.toLocaleString() + '" id="notifyx' + n.id + '" class=notification style="cursor:pointer;border-top:1px solid ' + ((r == '')?'transparent':'orange') + '"><div class=j' + icon + ' onclick="notificationSelected(' + n.id + ')" style=margin:5px;float:left></div><div onclick="notificationDelete(' + n.id + ')" class=unselectable title="Clear this notification" style=margin:5px;float:right;color:orange><b>X</b></div><div onclick="notificationSelected(' + n.id + ')" style=margin:5px>' + t + n.text + '</div></div>';
|
||
}
|
||
}
|
||
var deleteall = '';
|
||
if (notifications.length > 1) { deleteall = '<div id="notifyRemoveAll" onclick="deleteAllNotifications()" style="cursor:pointer;border-top:1px solid orange;margin:5px;color:orange;text-align:right;padding-right:3px">Clear all</div>'; }
|
||
QH('notifiyBox', '<div class=customScroll style="max-height:170px;overflow-y:auto;margin:5px">' + r + '</div>' + deleteall );
|
||
}
|
||
|
||
// A notification was selected
|
||
function notificationSelected(id) {
|
||
var j = -1;
|
||
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
|
||
if (j != -1) {
|
||
var n = notifications[j];
|
||
if (n.nodeid != null) {
|
||
if (n.tag == 'desktop') gotoDevice(n.nodeid, 12); // Desktop
|
||
else if (n.tag == 'terminal') gotoDevice(n.nodeid, 11); // Terminal
|
||
else if (n.tag == 'files') gotoDevice(n.nodeid, 13); // Files
|
||
else if (n.tag == 'intelamt') gotoDevice(n.nodeid, 14); // Intel AMT
|
||
else if (n.tag == 'console') gotoDevice(n.nodeid, 15); // Files
|
||
else gotoDevice(n.nodeid, 10); // General
|
||
} else {
|
||
if (n.tag.startsWith('meshmessenger/')) {
|
||
window.open('/messenger?id=' + n.tag + '&title=' + encodeURIComponent(n.username), n.tag.split('/')[2]);
|
||
notificationDelete(id);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Remove one notification
|
||
function notificationDelete(id) {
|
||
var j = -1, e = Q('notifyx' + id);
|
||
if (e != null) {
|
||
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
|
||
if (j != -1) {
|
||
notifications.splice(j, 1);
|
||
e.parentNode.removeChild(e);
|
||
setNotificationCount(notifications.length);
|
||
if (notifications.length == 0) { QV('notifiyBox', false); }
|
||
if (notifications.length == 1) { QV('notifyRemoveAll', false); }
|
||
if ((notifications.length > 0) && (j == 0)) {
|
||
var n = notifications[0];
|
||
QS('notifyx' + n.id)['border-top'] = '1px solid transparent';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Add a new notification and play the notification sound
|
||
function addNotification(n) {
|
||
if (n.time == null) { n.time = Date.now(); }
|
||
if (n.id == null) { n.id = Math.random(); }
|
||
notifications.unshift(n);
|
||
setNotificationCount(notifications.length);
|
||
Q('chimes').play();
|
||
clickNotificationIcon(true);
|
||
}
|
||
|
||
// Remove all notifications
|
||
function deleteAllNotifications() {
|
||
notifications = [];
|
||
setNotificationCount(0);
|
||
drawNotifications();
|
||
QV('notifiyBox', false);
|
||
}
|
||
|
||
//
|
||
// Server Statistics
|
||
//
|
||
|
||
function setupServerStats() {
|
||
window.serverStatCpu = new Chart(document.getElementById('serverCpuChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
|
||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||
});
|
||
window.serverStatMemory = new Chart(document.getElementById('serverMemoryChart').getContext('2d'), {
|
||
type: 'doughnut',
|
||
data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
|
||
options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
|
||
});
|
||
}
|
||
|
||
var lastServerStats = null;
|
||
function updateServerStats(message) {
|
||
if (message != null) { lastServerStats = message; } else { message = lastServerStats; }
|
||
if (message == null) return;
|
||
|
||
// Paint the pie graphs
|
||
if (typeof message.cpuavg == 'object') {
|
||
var m = Math.min(message.cpuavg[0], 1);
|
||
window.serverStatCpu.config.data.datasets[0].data = [m, 1 - m];
|
||
QH('serverCpuChartText', '<div style=margin-bottom:5px>CPU Load</div><div><b title="CPU load in the last minute">' + (Math.round(message.cpuavg[0] * 100.0) / 100.0) + '</b>, <b title="CPU load in the last 5 minutes">' + (Math.round(message.cpuavg[1] * 100.0) / 100.0) + '</b>, <b title="CPU load in the 15 minutes">' + (Math.round(message.cpuavg[2] * 100.0) / 100.0) + '</b></div>');
|
||
QS('serverCpuChartView')['display'] = 'inline-block';
|
||
window.serverStatCpu.update();
|
||
}
|
||
if ((typeof message.totalmem == 'number') && (typeof message.freemem == 'number')) {
|
||
window.serverStatMemory.config.data.datasets[0].data = [message.totalmem - message.freemem, message.freemem];
|
||
QH('serverMemoryChartText', '<div style=margin-bottom:5px>Memory</div><div><b>' + getNiceSize2(message.freemem) + '</b> free, <b>' + getNiceSize2(message.totalmem) + '</b> total</div>');
|
||
QS('serverMemoryChartView')['display'] = 'inline-block';
|
||
window.serverStatMemory.update();
|
||
}
|
||
|
||
// Display all of the server values
|
||
var x = '<div style=width:100% cellpadding=0 cellspacing=0>';
|
||
if (typeof message.values == 'object') {
|
||
for (var i in message.values) {
|
||
x += '<div class=userTableHeader style=margin-bottom:4px;width:200px>' + i + '</div>';
|
||
for (var j in message.values[i]) {
|
||
x += '<div style=display:inline-block><table style=width:300px;height:24px;background-color:#d3d9d6;margin-bottom:4px;vertical-align:middle;border-spacing:0><tr><td class=h1></td><td><span>' + j + '</span><span style=float:right>' + message.values[i][j] + '</span></td><td class=h2></td></tr></table></div>';
|
||
}
|
||
}
|
||
}
|
||
x += '</div>';
|
||
|
||
QH('serverStatsTable', x);
|
||
}
|
||
|
||
//
|
||
// POPUP DIALOG
|
||
//
|
||
|
||
// null = Hidden, 1 = Generic Message
|
||
var xxdialogMode;
|
||
var xxdialogFunc;
|
||
var xxdialogButtons;
|
||
var xxdialogTag;
|
||
var xxcurrentView = -1;
|
||
|
||
// Display a dialog box
|
||
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
|
||
function setDialogMode(x, y, b, f, c, tag) {
|
||
xxdialogMode = x;
|
||
xxdialogFunc = f;
|
||
xxdialogButtons = b;
|
||
xxdialogTag = tag;
|
||
QE('idx_dlgOkButton', true);
|
||
QV('idx_dlgOkButton', b & 1);
|
||
QV('idx_dlgCancelButton', b & 2);
|
||
QV('id_dialogclose', (b & 2) || (b & 8));
|
||
QV('idx_dlgDeleteButton', b & 4);
|
||
QV('idx_dlgButtonBar', b & 7);
|
||
if (y) QH('id_dialogtitle', y);
|
||
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||
QV('dialog', x);
|
||
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||
}
|
||
|
||
function dialogclose(x) {
|
||
var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
|
||
setDialogMode();
|
||
if (((b & 8) || x) && f) f(x, t);
|
||
}
|
||
|
||
function center() {
|
||
if (xxcurrentView == 11) { deskAdjust(); } //deskAdjust(); }
|
||
else if (xxcurrentView == 10) { masterUpdate(256); }
|
||
else if (xxcurrentView == 1) { masterUpdate(4); }
|
||
}
|
||
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||
|
||
function goBack() {
|
||
if (xxdialogMode) return;
|
||
if ((xxcurrentView >= 10) && (xxcurrentView < 20)) { go(1); } // Return to My Devices
|
||
if ((xxcurrentView >= 20) && (xxcurrentView < 30)) { go(2); } // Return to My Account
|
||
if ((xxcurrentView >= 30) && (xxcurrentView < 40)) { go(4); } // Return to My Users
|
||
}
|
||
|
||
function go(x) {
|
||
if (xxdialogMode || xxcurrentView == x) return;
|
||
// Edit this line when adding a new screen
|
||
for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
|
||
xxcurrentView = x;
|
||
|
||
// Remove left bar selection
|
||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
||
for (var i in leftBarItems) { Q(leftBarItems[i]).classList.remove('lbbuttonsel'); Q(leftBarItems[i]).classList.remove('lbbuttonsel2'); }
|
||
|
||
// My Devices
|
||
QV('topbar', x != 0);
|
||
if (x >= 10 && x < 20) { QS('MainMenuMyDevices').backgroundColor = "#606060"; } else { QS('MainMenuMyDevices').backgroundColor = ((x == 1) ? "#003366" : "#808080"); }
|
||
if (x == 1 || (x >= 10 && x < 20)) { Q('LeftMenuMyDevices').classList.add('lbbuttonsel'); }
|
||
if (x == 1) { Q('LeftMenuMyDevices').classList.add('lbbuttonsel2'); }
|
||
|
||
// My Account
|
||
if (x >= 20 && x < 30) { QS('MainMenuMyAccount').backgroundColor = "#606060"; } else { QS('MainMenuMyAccount').backgroundColor = ((x == 2) ? "#003366" : "#808080"); }
|
||
if (x == 2 || (x >= 20 && x < 30)) { Q('LeftMenuMyAccount').classList.add('lbbuttonsel'); }
|
||
if (x == 2) { Q('LeftMenuMyAccount').classList.add('lbbuttonsel2'); }
|
||
|
||
// My Events
|
||
QS('MainMenuMyEvents').backgroundColor = ((x == 3) ? "#003366" : "#808080");
|
||
if (x == 3) { Q('LeftMenuMyEvents').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||
|
||
// My Users
|
||
if (x >= 30 && x < 40) { QS('MainMenuMyUsers').backgroundColor = "#606060"; } else { QS('MainMenuMyUsers').backgroundColor = ((x == 4) ? "#003366" : "#808080"); }
|
||
if (x == 4 || (x >= 30 && x < 40)) { Q('LeftMenuMyUsers').classList.add('lbbuttonsel'); }
|
||
if (x == 4) { Q('LeftMenuMyUsers').classList.add('lbbuttonsel2'); }
|
||
|
||
// My Files
|
||
QS('MainMenuMyFiles').backgroundColor = ((x == 5) ? "#003366" : "#808080");
|
||
if (x == 5) { Q('LeftMenuMyFiles').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||
|
||
// My Server
|
||
QS('MainMenuMyServer').backgroundColor = (((x == 6) || (x == 115)) ? "#003366" : "#808080");
|
||
if (((x == 6) || (x == 115))) { Q('LeftMenuMyServer').classList.add('lbbuttonsel', 'lbbuttonsel2'); }
|
||
|
||
// column_l max-height
|
||
if (webPageFullScreen) {
|
||
QS('column_l')["max-height"] = 'calc(100vh - 135px)';
|
||
} else {
|
||
QS('column_l')["max-height"] = (x >= 10) ? 'calc(100vh - 159px)' : 'calc(100vh - 135px)';
|
||
}
|
||
if ((x == 0) && (webPageFullScreen)) {
|
||
QS('page_content').position = '';
|
||
QV('page_leftbar', false);
|
||
QS('column_l').height = 'calc(100vh - 110px)';
|
||
QS('column_l')["max-height"] = '';
|
||
}
|
||
|
||
QV('MainSubMenuSpan', x >= 10 && x < 20);
|
||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||
QV('ServerSubMenuSpan', x == 6 || x == 115);
|
||
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 115: 'ServerConsole' };
|
||
for (var i in panels) {
|
||
Q(panels[i]).classList.remove('style3x');
|
||
Q(panels[i]).classList.remove('style3sel');
|
||
Q(panels[i]).classList.add((x == i) ? 'style3sel' : 'style3x');
|
||
}
|
||
|
||
// Panel 115 is weird, it's panel 15 for device console but used as a server console.
|
||
if (x == 115) { QV('p15', true); }
|
||
QV('p15uploadCore', x != 115);
|
||
QV('p15BackButton', x != 115);
|
||
if ((x == 15) || (x == 115)) { setupConsole(); }
|
||
|
||
if (x == 1) masterUpdate(4);
|
||
|
||
// Update the web page title
|
||
if ((currentNode) && (x >= 10) && (x < 20)) { document.title = 'MeshCentral - ' + currentNode.name; } else { document.title = 'MeshCentral'; }
|
||
}
|
||
|
||
// Generic methods
|
||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||
//function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>♦ " + x + "</a>"; }
|
||
function addLink(x, f) { return "<span style=cursor:pointer;text-decoration:none onclick='" + f + "'>" + x + " <img class=hoverButton width=10 height=10 src=images/link5.png></span>"; }
|
||
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
||
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||
function addOption(q, t, i) { var option = document.createElement("option"); option.text = t; option.value = i; Q(q).add(option); }
|
||
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||
function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != "SUCCESS") { messagebox("Call Error", r.Header.Method + ": " + r.Body.ReturnValueStr.replace("_", " ")); return true; } return false; }
|
||
function TableStart() { return "<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>"; }
|
||
function TableStart2() { return "<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>"; }
|
||
function TableEntry(n, v) { return "<tr><td><p>" + n + "<td>" + v; }
|
||
function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
|
||
function TableEnd(n) { return "<tr><td colspan=2><p>" + (n?n:'') + "</table>"; }
|
||
function AddButton(v, f) { return "<input type=button value='" + v + "' onclick='" + f + "' style=margin:4px>"; }
|
||
function AddButton2(v, f) { return "<input type=button value='" + v + "' onclick='" + f + "'>"; }
|
||
function AddRefreshButton(f) { return "<input type=button name=refreshbtn value=Refresh onclick='refreshButtons(false);" + f + "' style=margin:4px " + (refreshButtonsState==false?"disabled":"") + ">"; }
|
||
function MoreStart() { return "<a style=cursor:pointer;color:blue id=morexxx1 onclick=QV(\"morexxx1\",false);QV(\"morexxx2\",true)>▼ More</a><div id=morexxx2 style=display:none><br><hr>"; };
|
||
function MoreEnd() { return "<a style=cursor:pointer;color:blue onclick=QV(\"morexxx2\",false);QV(\"morexxx1\",true)>▲ Less</a></div>"; };
|
||
function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
|
||
function getInstance(x, y) { for (var i in x) { if (x[i]["InstanceID"] == y) return x[i]; } return null; }
|
||
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
|
||
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
|
||
function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
|
||
//function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
|
||
//function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
|
||
function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
|
||
function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
|
||
function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
|
||
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
|
||
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||
function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
|
||
function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
|
||
|
||
</script></body></html> |