"use strict"; function Socket(options) { function getStringFromData(buf, begin, len, defaultText) { var szValue; if ("function" == typeof TextDecoder) szValue = new TextDecoder("utf-8").decode(new Uint8Array(buf.buffer, buf.byteOffset + begin, len)); else try { szValue = String.fromCharCode.apply(null, new Uint8Array(buf.buffer, buf.byteOffset + begin, len)), szValue = decodeURIComponent(escape(szValue)).replace(/\0/g, ""); } catch (ex) { szValue = ""; } return szValue.length > 0 ? szValue : defaultText; } function getPostCodeFromData(buf) { var index1, index2, szValue = ""; return buf.length >= 2 && (index1 = ("00" + buf[1].toString(16).toUpperCase()).substr(-2), index2 = ("00" + buf[0].toString(16).toUpperCase()).substr(-2), szValue = index1 + index2), szValue; } function IRC_CMD(dataView) { this.cmd, this.size, this.seq, this.flags, this.buf; try { dataView && (this.cmd = dataView.getUint32(0, !0), this.size = dataView.getUint32(4, !0), this.seq = dataView.getUint16(8, !0), this.flags = dataView.getUint16(10, !0), this.buf = new Uint8Array(dataView.buffer, dataView.byteOffset + 12)); } catch (e) {} } function IRC_SERVER_HELLO(dataView) { this.iv, this.status, this.flags, this.session_key; try { dataView && (4 === me.version ? this.status = dataView.getUint8(0, !0) : (this.status = dataView.getUint8(16), this.flags = dataView.getUint32(17, !0))); } catch (e) {} } function Handshake(wsuri, sessionKey, channel, openCommand, success, failure) { var socket, onfail = failure || function(sock, reason) { console.log("Handshake failed: " + reason); }, onsuccess = success || function(sock) { sock.onmessage = function(evt) {}; }, sockopen_auth = function(evt) { if (4 === me.version) return !0; var client_hello = new Uint8Array(54); client_hello[16] = openCommand, client_hello[17] = channel; for (var i = 0; i < sessionKey.length; i++) client_hello[22 + i] = sessionKey.charCodeAt(i); socket.send(client_hello); }, sockrecv_auth = function(evt) { var server_hello = new IRC_SERVER_HELLO(new DataView(evt.data)); if (4 === me.version) switch (server_hello.status) { case DVCNET.CMD_AUTHENTICATE: var name = channel === CMD_CHANNEL ? "CMD" : "KVM", client_hello = new Uint8Array(34); client_hello[0] = "CMD" === name ? 2 : 1, client_hello[1] = 32; for (var i = 0; i < sessionKey.length; i++) client_hello[2 + i] = sessionKey.charCodeAt(i); socket.send(client_hello); break; case DVCNET.CMD_AUTHENTICATED: socket.onmessage = null, socket.onopen = null, onsuccess(socket); break; case DVCNET.NEG_BUSY_NO_MURC: video.set_licensed_murc(!1); case DVCNET.NEG_BUSY: me.cmdsocket = socket; var msgKey = "IRC.message.ConsoleInUseNoShare", tmrMsgKey = "IRC.message.TimedAutoDisconnect", msgBox = { callback: "neg_seize", messageKey: msgKey, stayTime: 10, timerStringKey: tmrMsgKey, title: null, icon: null, buttons: [ { text: "Acquire", textKey: "IRC.control.Acquire", isDefault: !0, value: !0 }, { text: "Cancel", textKey: "cancel", isDefault: !1, value: !1 } ] }; video.confirm(msgBox); break; case DVCNET.NEG_SEIZE: case DVCNET.NEG_SHARE: onfail(socket, server_hello.status); break; case DVCNET.CMD_DENIED: case DVCNET.NEG_DROP: case DVCNET.CMD_NO_SESSIONS: default: socket.onmessage = null, socket.onopen = null, onfail(socket, server_hello.status); } else switch (socket.onmessage = null, socket.onopen = null, server_hello.status) { case 0: onsuccess(socket); break; default: onfail(socket, server_hello.status); } }; if ("function" == typeof MozWebSocket) socket = new MozWebSocket(wsuri); else { if ("function" != typeof WebSocket) throw "No WebSockets!"; try { socket = new WebSocket(wsuri); } catch (e) { "SyntaxError" === e.message && this.ie && wsuri.match(/[^[\]]+(?=])/g).length ? onfail(null, "IE+IPv6") : onfail(null, e.message); } } socket && (socket.onerror = function(evt) { 1 === socket.readyState ? console.log("WebSocket connection failed: " + evt.type) : console.log("WebSocket error: " + evt.type); }, socket.binaryType = "arraybuffer", socket.onmessage = sockrecv_auth, socket.onopen = sockopen_auth); } var me = this, KVM_CHANNEL = 0, CMD_CHANNEL = 1, DVCNET = { CMD_AUTHENTICATE: 80, CMD_DENIED: 81, CMD_AUTHENTICATED: 82, NEG_BUSY: 83, NEG_DROP: 84, NEG_SEIZE: 85, NEG_SHARE: 86, CMD_NO_SESSIONS: 88, NEG_BUSY_NO_MURC: 89 }, SCSI_ERR = { APPLET_CONNECT: -2, NO_IMAGE: -3, OPTION_ERROR: -4, SCRIPT_CONNECT: -5, NO_LICENSE: -6, REJECTED: -7, CONNECT_FAILED: -8, OP_FAILED: -9, EXPECTED_ISO: -10, EXPECTED_IMG: -11, VIDEO_STARTUP: -12, FW_ACTIVE: -13, FLASH_FAILED: -14 }; this.onstatuschange = function() {}, this.version = options.version || 4, this.openCommand = options.openCommand || 0, this.sessionKey = options.sessionKey, this.sockaddr = "wss://" + options.host + "/wss/ircport", this.sockrecv = options.sockrecv, this.ie = options.ie, this.video = options.video, this.health_state = "", this.power_state = "", this.neg_seize = function(resp) { if (me.openCommand = resp ? 1 : 0, resp === !0) { var cmd = new Uint8Array(2); cmd[0] = DVCNET.NEG_SEIZE, cmd[1] = 0, me.cmdsocket.send(cmd); } else me.close(), me.onclose && me.onclose(); }, this.handleSeize = function(irc_cmd) { var user = getStringFromData(irc_cmd.buf, 0, 64, "UNKNOWN"), addr = getStringFromData(irc_cmd.buf, 64, 64, "UNKNOWN"), dlgMsg = "IRC.message.RequestAcquire", tmrMsg = "IRC.message.AutoPermission", actMsg = "IRC.status.granted", messageInserts = [ { placeHolder: "{0}", value: user }, { placeHolder: "{1}", value: addr } ], msgBox = { callback: "send_bool", retvalOverride: !0, messageKey: dlgMsg, messageInserts: messageInserts, title: null, icon: null, stayTime: 10, timerStringKey: tmrMsg, actionKey: actMsg, buttons: [ { textKey: "IRC.control.Yes", isDefault: !0, value: !0 }, { textKey: "IRC.control.No", value: !1 } ] }; video.confirm(msgBox); }, this.handleShare = function(irc_cmd) { var user = getStringFromData(irc_cmd.buf, 0, 64, "UNKNOWN"), addr = getStringFromData(irc_cmd.buf, 64, 64, "UNKNOWN"); me.sendBool(!1), video.handle_share(user, addr); }, this.handlePostCode = function(irc_cmd) { if (2 === irc_cmd.size) { var code = getPostCodeFromData(irc_cmd.buf); video.post_code(code); } }, this.handleAckNotification = function(irc_cmd) { var dlgMsg = ""; if (4 !== irc_cmd.size) return void $.log("IRC: rejecting Ack notification: size is not 4."); var dataView = new DataView(irc_cmd.buf.buffer, irc_cmd.buf.byteOffset), result = dataView.getInt8(0, !0), device = dataView.getInt8(1, !0), type = dataView.getInt8(2, !0), connected = 0 !== dataView.getInt8(3, !0) ? !0 : !1; if (0 === result) video.vm_change({ isFloppy: 1 == device, isURL: 8 == type, isConnected: !!connected }); else if (0 > result && !connected) { switch (result) { case -1: dlgMsg = "IRC.message.CannotParse"; break; case SCSI_ERR.APPLET_CONNECT: case SCSI_ERR.SCRIPT_CONNECT: dlgMsg = "IRC.message.DriveAlreadyConnected"; break; case SCSI_ERR.NO_IMAGE: dlgMsg = "IRC.message.ImageNotFound"; break; case SCSI_ERR.OPTION_ERROR: dlgMsg = "IRC.message.InternalConfigError"; break; case SCSI_ERR.NO_LICENSE: dlgMsg = "IRC.message.VMNotLicensed"; break; case SCSI_ERR.REJECTED: dlgMsg = "IRC.message.CannotConnect"; break; default: dlgMsg = "IRC.message.UnknownError"; } if (dlgMsg.length > 0) { var msgBox = { messageKey: dlgMsg, stayTime: 10, title: null, icon: null }; video.alert(msgBox); } } }, this.handleFirmwareUpdate = function(irc_cmd) { var dlgMsg = "IRC.message.ClosedFwUpgrade", msgBox = { messageKey: dlgMsg, stayTime: 20, title: null, icon: null }; video.alert(msgBox), me.close(); }, this.handleUnauthorized = function(irc_cmd) { var priv = ""; switch (irc_cmd.flags) { case 2: priv = "RemoteConsolePriv"; break; case 3: priv = "VirtualMediaPriv"; break; case 4: priv = "VirtualPowerAndResetPriv"; } priv.length > 0 && video.unauthorized(priv); }, this.handleLicenseViolation = function(irc_cmd) { var dlgMsg = "IRC.message.IRCNotLicensed", msgBox = { titleKey: "IRC.title.LicenseRequired", type: "critical", messageKey: dlgMsg }; video.alert(msgBox), me.close(); }, this.handleReset = function(irc_cmd) { var dlgMsg = "IRC.message.iLOReset", msgBox = { messageKey: dlgMsg, stayTime: 20, title: null, icon: null }; video.alert(msgBox), me.close(); }, this.onhealthchange = function(health_state) { this.health_state !== health_state && (this.health_state = health_state, video.health_change(health_state)); }, this.handleHealthState = function(health_state) { if (me.onhealthchange) switch (health_state) { case 0: me.onhealthchange("OP_STATUS_OK"); break; case 1: me.onhealthchange("OP_STATUS_WARNING"); break; case 2: me.onhealthchange("OP_STATUS_CRITICAL"); break; default: me.onhealthchange("OP_STATUS_UNKNOWN"); } }, this.handlePowerState = function(power_state) { if (me.onpowerchange) switch (power_state) { case 1: me.onpowerchange("ON"); break; case 0: default: me.onpowerchange("OFF"); } }, this.onpowerchange = function(power_state) { this.power_state !== power_state && (this.power_state = power_state, video.power_change(power_state)); }, this.cmdsockrecv = function(evt) { var irc_cmd = new IRC_CMD(new DataView(evt.data)); switch (irc_cmd.cmd) { case 2: video.status_change("Post Complete"); break; case 3: me.handlePowerState(irc_cmd.buf[0]); break; case 4: me.handleHealthState(irc_cmd.buf[0]); break; case 5: me.handlePostCode(irc_cmd); break; case 6: me.handleSeize(irc_cmd); break; case 7: me.handleAckNotification(irc_cmd); break; case 9: me.handleShare(irc_cmd); break; case 10: console.log("IRC: received firmware update notification."), me.handleFirmwareUpdate(irc_cmd); break; case 11: console.log("IRC: received unauthorized notification."), me.handleUnauthorized(irc_cmd); break; case 13: break; case 14: me.handleLicenseViolation(irc_cmd); break; case 15: console.log("IRC: iLO reset detected."), me.handleReset(irc_cmd); break; case 16: case 17: break; default: console.log("IRC: received unhandled command: ", irc_cmd); } }, this.open_cmdsocket = function() { new Handshake(me.sockaddr, me.sessionKey, 1, 0, function(ws) { ws.onmessage = me.cmdsockrecv, ws.onclose = function() { me.onclose && me.onclose(), console.log("cmd socket closed"); }, ws.onerror = function(evt) { console.log("cmd socket open error: " + evt); }, me.cmdsocket = ws, me.send = me.send_kvm, setTimeout(function() { me.all_keys_up(); }, 2e3); }, null); }, this.send_kvm = function(arr) { this.socket && this.socket.readyState && this.socket.send(new Uint8Array(arr)); }, this.send_cmd = function(arr) { this.cmdsocket && this.cmdsocket.readyState && this.cmdsocket.send(new Uint8Array(arr)); }, this.send_null = function(arr) {}, this.send = this.send_null, this.sendBool = function(rsp) { var cmd = [ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ]; cmd[0] = rsp ? 4 : 3, this.send_cmd(cmd); }, this.kbdsend = function(hidrpt) { var cmd; cmd = me.version > 2 ? [ 1, 0 ] : [ 255, 214 ], cmd = cmd.concat(hidrpt), me.send(cmd); }, this.all_keys_up = function() { me.kbdsend([ 0, 0, 0, 0, 0, 0, 0, 0 ]); }, this.ctrl_alt_del = function() { me.kbdsend([ 5, 0, 76, 0, 0, 0, 0, 0 ]), setTimeout(function() { me.kbdsend([ 5, 0, 0, 0, 0, 0, 0, 0 ]), setTimeout(function() { me.all_keys_up(); }, 5); }, 250); }, this.num_lock = function() { me.kbdsend([ 0, 0, 83, 0, 0, 0, 0, 0 ]), setTimeout(function() { me.all_keys_up(); }, 50); }, this.caps_lock = function() { me.kbdsend([ 0, 0, 57, 0, 0, 0, 0, 0 ]), setTimeout(function() { me.all_keys_up(); }, 50); }, this.refresh = function() { me.version > 2 ? me.send([ 5, 0 ]) : me.send([ 27, 91, 126 ]); }, this.send_ack = function() { me.send([ 12, 0 ]); }, this.keepalive = function() { me.send([ 27, 91, 40 ]); }, this.autoalive = function() { me.send([ 27, 91, 38 ]); }, this.mouse_send = function(rx, ry, ax, ay, button, wheel) { if (2 === this.version) return !1; var buf = [ 2, 0, 255 & ax, ax >> 8, 255 & ay, ay >> 8, 255 & rx, 255 & ry, button, wheel ]; return this.send(buf), !0; }, this.no_op = function() { return !1; }, this.close = function() { this.socket && this.socket.close(), this.cmdsocket && this.cmdsocket.close(); }, new Handshake(me.sockaddr, me.sessionKey, KVM_CHANNEL, me.openCommand, function(ws) { me.connected = !0, me.socket = ws, me.socket.onmessage = me.sockrecv, me.socket.onclose = function(evt) { console.log("WebSocket closed", evt), me.connected = !1, me.onclose && me.onclose(); }, me.socket.onerror = function(evt) { console.log("WebSocket ERROR: ", evt); }, me.open_cmdsocket(); }, function(ws, error) { var alertToast = function(key) { video.toast({ textKey: key, type: "critical", sticky: !0 }); }; switch (error) { case DVCNET.CMD_DENIED: switch (me.openCommand) { case 1: alertToast("IRC.message.AcquireDenied"); break; case 2: alertToast("IRC.message.ShareDenied"); break; case 0: default: alertToast("IRC.message.SessionLimitReached"); } break; case 2: var msgKey = "IRC.message.ConsoleInUseNoShare", tmrMsgKey = "IRC.message.TimedAutoDisconnect", msgBox = { callback: "send_bool", messageKey: msgKey, stayTime: 10, timerStringKey: tmrMsgKey, title: null, icon: null, buttons: [ { textKey: "IRC.control.Acquire", isDefault: !0, value: !0 }, { textKey: "cancel", isDefault: !1, value: !1 } ] }; return video.confirm(msgBox), void me.close(); case 3: alertToast("status_labels.NOT_SUPPORTED"); break; case 4: video.toast({ text: "Bad Request", type: "critical", sticky: !0 }); break; case 5: video.toast({ text: "Internal Error", type: "critical", sticky: !0 }); break; case 6: case DVCNET.CMD_NO_SESSIONS: alertToast("IRC.message.NoFreeSessions"); break; case 7: alertToast("IRC.message.FeatureNotLicensed"); break; case "SyntaxError": alertToast("IRC.message.WebSocketSyntaxError"); break; case "IE+IPv6": alertToast("IRC.message.WebSocketIEIPv6"); break; default: me.ie || isNaN(error) || video.toast({ text: "Unexpected error: " + error, type: "critical", sticky: !0 }); } console.log("Handshake error: ", error), me.close(), me.onclose && me.onclose(); }); }