mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	You can now view & clear the server error log on the web ui as administrator
This commit is contained in:
		
							parent
							
								
									e0ee698e2a
								
							
						
					
					
						commit
						bfe8a8074e
					
				
					 17 changed files with 564 additions and 199 deletions
				
			
		| 
						 | 
				
			
			@ -17,7 +17,6 @@ limitations under the License.
 | 
			
		|||
function createMeshCore(agent) {
 | 
			
		||||
    var obj = {};
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    function borderController() {
 | 
			
		||||
        this.container = null;
 | 
			
		||||
        this.Start = function Start(user) {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +45,6 @@ function createMeshCore(agent) {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    require('events').EventEmitter.call(obj, true).createEvent('loggedInUsers_Updated');
 | 
			
		||||
    obj.on('loggedInUsers_Updated', function ()
 | 
			
		||||
| 
						 | 
				
			
			@ -58,10 +56,10 @@ function createMeshCore(agent) {
 | 
			
		|||
        }
 | 
			
		||||
        sendConsoleText('LogOn Status Changed. Active Users => [' + users.join(', ') + ']');
 | 
			
		||||
    });
 | 
			
		||||
    //obj.borderManager = new borderController();
 | 
			
		||||
    obj.borderManager = new borderController();
 | 
			
		||||
    
 | 
			
		||||
    // MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
 | 
			
		||||
    obj.meshCoreInfo = "MeshCore v5";
 | 
			
		||||
    obj.meshCoreInfo = "MeshCore v6";
 | 
			
		||||
    obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
 | 
			
		||||
    obj.loggedInUsers = [];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +139,10 @@ function createMeshCore(agent) {
 | 
			
		|||
        sha = require('SHA256Stream');
 | 
			
		||||
        mesh = require('MeshAgent');
 | 
			
		||||
        childProcess = require('child_process');
 | 
			
		||||
        if (mesh.hasKVM == 1) { obj.meshCoreCapabilities |= 1; }
 | 
			
		||||
        if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
 | 
			
		||||
            // Check if this computer supports a desktop
 | 
			
		||||
            try { if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) { obj.meshCoreCapabilities |= 1; } } catch (ex) { }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Running in nodejs
 | 
			
		||||
        obj.meshCoreInfo += '-NodeJS';
 | 
			
		||||
| 
						 | 
				
			
			@ -911,7 +912,6 @@ function createMeshCore(agent) {
 | 
			
		|||
                    response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, border.';
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                    /*
 | 
			
		||||
                case 'border':
 | 
			
		||||
                    {
 | 
			
		||||
                        if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -929,7 +929,6 @@ function createMeshCore(agent) {
 | 
			
		|||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                    */
 | 
			
		||||
                case 'users':
 | 
			
		||||
                    {
 | 
			
		||||
                        var retList = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,11 +1022,14 @@ function createMeshCore(agent) {
 | 
			
		|||
                case 'info': { // Return information about the agent and agent core module
 | 
			
		||||
                    response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
 | 
			
		||||
                    if (amtLmsState >= 0) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
 | 
			
		||||
                    response += '\r\nModules: ' + addedModules.join(', ');
 | 
			
		||||
                    response += '\r\nServerConnected: ' + mesh.isControlChannelConnected;
 | 
			
		||||
                    response += '\r\nModules: ' + addedModules.join(', ') + '.';
 | 
			
		||||
                    response += '\r\nServerConnected: ' + mesh.isControlChannelConnected + '.';
 | 
			
		||||
                    var oldNodeId = db.Get('OldNodeId');
 | 
			
		||||
                    if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
 | 
			
		||||
                    response += '\r\ServerState: ' + meshServerConnectionState + '.';
 | 
			
		||||
                    response += '\r\nServerState: ' + meshServerConnectionState + '.';
 | 
			
		||||
                    if (process.platform != 'win32') {
 | 
			
		||||
                        response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.';
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'selfinfo': { // Return self information block
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var MemoryStream = require('MemoryStream');
 | 
			
		||||
var lme_id = 0;             // Our next channel identifier
 | 
			
		||||
var lme_port_offset = 0;    // Debug: Set this to "-100" to bind to 16892 & 16893 and IN_ADDRANY. This is for LMS debugging.
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +37,7 @@ var APF_CHANNEL_DATA = 94;
 | 
			
		|||
var APF_CHANNEL_CLOSE = 97;
 | 
			
		||||
var APF_PROTOCOLVERSION = 192;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function lme_object() {
 | 
			
		||||
    this.ourId = ++lme_id;
 | 
			
		||||
    this.amtId = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -379,14 +379,16 @@ function lme_heci(options) {
 | 
			
		|||
                    buffer.writeUInt32BE(0xFFFFFFFF, 13);       // Reserved
 | 
			
		||||
                    this.write(buffer);
 | 
			
		||||
 | 
			
		||||
                    //var buffer = Buffer.alloc(17);
 | 
			
		||||
                    //buffer.writeUInt8(APF_CHANNEL_OPEN_FAILURE, 0);
 | 
			
		||||
                    //buffer.writeUInt32BE(channelSender, 1);     // Intel AMT sender channel
 | 
			
		||||
                    //buffer.writeUInt32BE(2, 5);                 // Reason code
 | 
			
		||||
                    //buffer.writeUInt32BE(0, 9);                 // Reserved
 | 
			
		||||
                    //buffer.writeUInt32BE(0, 13);                // Reserved
 | 
			
		||||
                    //this.write(buffer);
 | 
			
		||||
                    //console.log('Sent APF_CHANNEL_OPEN_FAILURE', channelSender);
 | 
			
		||||
                    /*
 | 
			
		||||
                    var buffer = Buffer.alloc(17);
 | 
			
		||||
                    buffer.writeUInt8(APF_CHANNEL_OPEN_FAILURE, 0);
 | 
			
		||||
                    buffer.writeUInt32BE(channelSender, 1);     // Intel AMT sender channel
 | 
			
		||||
                    buffer.writeUInt32BE(2, 5);                 // Reason code
 | 
			
		||||
                    buffer.writeUInt32BE(0, 9);                 // Reserved
 | 
			
		||||
                    buffer.writeUInt32BE(0, 13);                // Reserved
 | 
			
		||||
                    this.write(buffer);
 | 
			
		||||
                    console.log('Sent APF_CHANNEL_OPEN_FAILURE', channelSender);
 | 
			
		||||
                    */
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,6 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
 | 
			
		|||
    obj.FailAllError = 0;               // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
 | 
			
		||||
    obj.digest = null;
 | 
			
		||||
    obj.RequestCount = 0;
 | 
			
		||||
    obj.requests = {};
 | 
			
		||||
 | 
			
		||||
    if (arguments.length == 1 && typeof(arguments[0] == 'object'))
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -90,12 +89,9 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
 | 
			
		|||
        }
 | 
			
		||||
        var request = { protocol: (obj.tls == 1 ? 'https:' : 'http:'), method: 'POST', host: obj.host, path: '/wsman', port: obj.port, rejectUnauthorized: false, checkServerIdentity: function (cert) { console.log('checkServerIdentity', JSON.stringify(cert)); } };
 | 
			
		||||
        var req = obj.digest.request(request);
 | 
			
		||||
        req.reqid = obj.RequestCount++;
 | 
			
		||||
        obj.requests[req.reqid] = req; // Keep a reference to the request object so it does not get disposed.
 | 
			
		||||
        //console.log('Request ' + (obj.RequestCount++));
 | 
			
		||||
        req.on('error', function (e) { delete obj.requests[this.reqid]; obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });
 | 
			
		||||
        req.on('error', function (e) { obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });
 | 
			
		||||
        req.on('response', function (response) {
 | 
			
		||||
            response.reqid = this.reqid;
 | 
			
		||||
            //console.log('Response: ' + response.statusCode);
 | 
			
		||||
            if (response.statusCode != 200) {
 | 
			
		||||
                //console.log('ERR:' + JSON.stringify(response));
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +99,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
 | 
			
		|||
            } else {
 | 
			
		||||
                response.acc = '';
 | 
			
		||||
                response.on('data', function (data2) { this.acc += data2; });
 | 
			
		||||
                response.on('end', function () { delete obj.requests[this.reqid]; obj.gotNextMessages(response.acc, 'success', { status: response.statusCode }, [postdata, callback, tag]); });
 | 
			
		||||
                response.on('end', function () { obj.gotNextMessages(response.acc, 'success', { status: response.statusCode }, [postdata, callback, tag]); });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : undefined); } }); } catch (e) { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Parse XML and return JSON
 | 
			
		||||
module.exports.ParseWsman = function (xml) {
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +39,7 @@ module.exports.ParseWsman = function (xml) {
 | 
			
		|||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.log("Unable to parse XML: " + xml);
 | 
			
		||||
        console.error("Unable to parse XML: " + xml, e);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +106,6 @@ function _PutObjToBodyXml(resuri, putObj) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// This is a drop-in replacement to _turnToXml() that works without xml parser dependency.
 | 
			
		||||
try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : null); } }); } catch (ex) { }
 | 
			
		||||
function _treeBuilder() {
 | 
			
		||||
    this.tree = [];
 | 
			
		||||
    this.push = function (element) { this.tree.push(element); };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -202,9 +202,6 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
    obj.AMT_AgentPresenceWatchdog_RegisterAgent = function (callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "RegisterAgent", {}, callback_func, tag, pri, selectors); }
 | 
			
		||||
    obj.AMT_AgentPresenceWatchdog_AssertPresence = function (SequenceNumber, callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertPresence", { "SequenceNumber": SequenceNumber }, callback_func, tag, pri, selectors); }
 | 
			
		||||
    obj.AMT_AgentPresenceWatchdog_AssertShutdown = function (SequenceNumber, callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertShutdown", { "SequenceNumber": SequenceNumber }, callback_func, tag, pri, selectors); }
 | 
			
		||||
    //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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -264,7 +261,7 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
    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_AddCertificate = function (CertificateBlob, callback_func, tag) { obj.Exec("AMT_PublicKeyManagementService", "AddCertificate", { "CertificateBlob": CertificateBlob }, callback_func, tag); }
 | 
			
		||||
    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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -275,7 +272,7 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
    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_CommitChanges = function (_method_dummy, callback_func, tag) { obj.Exec("AMT_SetupAndConfigurationService", "CommitChanges", { "_method_dummy": _method_dummy }, callback_func, tag); }
 | 
			
		||||
    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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -292,6 +289,7 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
    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_TLSCredentialContext_Create = function AMT_TLSCredentialContext_Create(ElementInContext, ElementProvidingContext, callback_func, tag) { obj.Create("AMT_TLSCredentialContext", { "ElementInContext": ElementInContext, "ElementProvidingContext": ElementProvidingContext }, 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, tag) { obj.Exec("AMT_WebUIService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func, tag); }
 | 
			
		||||
    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); }
 | 
			
		||||
| 
						 | 
				
			
			@ -765,18 +763,18 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
                    x['Initiator'] = 'KVM Default Port';
 | 
			
		||||
                    ptr = 5;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Read timestamp
 | 
			
		||||
                TimeStamp = ReadInt(e, ptr);
 | 
			
		||||
                x['Time'] = new Date((TimeStamp + (t.getTimezoneOffset() * 60)) * 1000);
 | 
			
		||||
                ptr += 4;
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Read network access
 | 
			
		||||
                x['MCLocationType'] = e[ptr++];
 | 
			
		||||
                var netlen = e[ptr++];
 | 
			
		||||
 | 
			
		||||
                x['NetAddress'] = e.slice(ptr, ptr + netlen).toString();
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Read extended data
 | 
			
		||||
                ptr += netlen;
 | 
			
		||||
                var exlen = e[ptr++];
 | 
			
		||||
| 
						 | 
				
			
			@ -990,7 +988,7 @@ function AmtStackCreateService(wsmanStack) {
 | 
			
		|||
    // 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);
 | 
			
		||||
        for (var i = 2; i < (sid.length / 4); i++) r += "-" + ReadIntX(sid, i * 4);
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,67 +54,100 @@ function monitorinfo()
 | 
			
		|||
    }
 | 
			
		||||
    else if(process.platform == 'linux')
 | 
			
		||||
    {
 | 
			
		||||
        this._X11 = this._gm.CreateNativeProxy('libX11.so');
 | 
			
		||||
        this._X11.CreateMethod('XChangeProperty');
 | 
			
		||||
        this._X11.CreateMethod('XCloseDisplay');
 | 
			
		||||
        this._X11.CreateMethod('XCreateGC');
 | 
			
		||||
        this._X11.CreateMethod('XCreateWindow');
 | 
			
		||||
        this._X11.CreateMethod('XCreateSimpleWindow');
 | 
			
		||||
        this._X11.CreateMethod('XDefaultColormap');
 | 
			
		||||
        this._X11.CreateMethod('XDefaultScreen');
 | 
			
		||||
        this._X11.CreateMethod('XDrawLine');
 | 
			
		||||
        this._X11.CreateMethod('XDisplayHeight');
 | 
			
		||||
        this._X11.CreateMethod('XDisplayWidth');
 | 
			
		||||
        this._X11.CreateMethod('XFetchName');
 | 
			
		||||
        this._X11.CreateMethod('XFlush');
 | 
			
		||||
        this._X11.CreateMethod('XFree');
 | 
			
		||||
        this._X11.CreateMethod('XCreateGC');
 | 
			
		||||
        this._X11.CreateMethod('XGetWindowProperty');
 | 
			
		||||
        this._X11.CreateMethod('XInternAtom');
 | 
			
		||||
        this._X11.CreateMethod('XMapWindow');
 | 
			
		||||
        this._X11.CreateMethod({ method: 'XNextEvent', threadDispatch: true });
 | 
			
		||||
        this._X11.CreateMethod('XOpenDisplay');
 | 
			
		||||
        this._X11.CreateMethod('XRootWindow');
 | 
			
		||||
        this._X11.CreateMethod('XScreenCount');
 | 
			
		||||
        this._X11.CreateMethod('XScreenOfDisplay');
 | 
			
		||||
        this._X11.CreateMethod('XSelectInput');
 | 
			
		||||
        this._X11.CreateMethod('XSendEvent');
 | 
			
		||||
        this._X11.CreateMethod('XSetForeground');
 | 
			
		||||
        this._X11.CreateMethod('XSetFunction');
 | 
			
		||||
        this._X11.CreateMethod('XSetLineAttributes');
 | 
			
		||||
        this._X11.CreateMethod('XSetNormalHints');
 | 
			
		||||
        this._X11.CreateMethod('XSetSubwindowMode');
 | 
			
		||||
 
 | 
			
		||||
        this._X11.CreateMethod('XBlackPixel');
 | 
			
		||||
        this._X11.CreateMethod('XWhitePixel');     
 | 
			
		||||
        
 | 
			
		||||
        // First thing we need to do, is determine where the X11 libraries are
 | 
			
		||||
        var fs = require('fs');
 | 
			
		||||
        var files = fs.readdirSync('/usr/lib');
 | 
			
		||||
        var files2;
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        for (j in files)
 | 
			
		||||
        {
 | 
			
		||||
            if (files[j].split('libX11.so.').length > 1 && files[j].split('.').length == 3)
 | 
			
		||||
            {
 | 
			
		||||
                Object.defineProperty(this, 'Location_X11LIB', { value: '/usr/lib/'  + files[j] });
 | 
			
		||||
            }
 | 
			
		||||
            if (files[j].split('libXtst.so.').length > 1 && files[j].split('.').length == 3)
 | 
			
		||||
            {
 | 
			
		||||
                Object.defineProperty(this, 'Location_X11TST', { value: '/usr/lib/' + files[j] });
 | 
			
		||||
            }
 | 
			
		||||
            if (files[j].split('libXext.so.').length > 1 && files[j].split('.').length == 3)
 | 
			
		||||
            {
 | 
			
		||||
                Object.defineProperty(this, 'Location_X11EXT', { value: '/usr/lib/' + files[j] });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        for (var i in files)
 | 
			
		||||
        {
 | 
			
		||||
            try {
 | 
			
		||||
                if (files[i].split('libX11.so.').length > 1 && files[i].split('.').length == 3) {
 | 
			
		||||
                    Object.defineProperty(this, 'Location_X11LIB', { value: '/usr/lib/' + files[i] });
 | 
			
		||||
                }
 | 
			
		||||
                if (files[i].split('libXtst.so.').length > 1 && files[i].split('.').length == 3) {
 | 
			
		||||
                    Object.defineProperty(this, 'Location_X11TST', { value: '/usr/lib/' + files[i] });
 | 
			
		||||
                }
 | 
			
		||||
                if (files[i].split('libXext.so.').length > 1 && files[i].split('.').length == 3) {
 | 
			
		||||
                    Object.defineProperty(this, 'Location_X11EXT', { value: '/usr/lib/' + files[i] });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (files[i].split('-linux-').length > 1) {
 | 
			
		||||
                    files2 = fs.readdirSync('/usr/lib/' + files[i]);
 | 
			
		||||
                    for (j in files2) {
 | 
			
		||||
                        if (files2[j].split('libX11.so.').length > 1 && files2[j].split('.').length == 3) {
 | 
			
		||||
                            Object.defineProperty(this, 'Location_X11LIB', { value: '/usr/lib/' + files[i] + '/' + files2[j] });
 | 
			
		||||
                        }
 | 
			
		||||
                        if (files2[j].split('libXtst.so.').length > 1 && files2[j].split('.').length == 3) {
 | 
			
		||||
                            Object.defineProperty(this, 'Location_X11TST', { value: '/usr/lib/' + files[i] + '/' + files2[j] });
 | 
			
		||||
                        }
 | 
			
		||||
                        if (files2[j].split('libXext.so.').length > 1 && files2[j].split('.').length == 3) {
 | 
			
		||||
                            Object.defineProperty(this, 'Location_X11EXT', { value: '/usr/lib/' + files[i] + '/' + files2[j] });
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } catch (ex) { }
 | 
			
		||||
        }
 | 
			
		||||
        Object.defineProperty(this, 'kvm_x11_support', { value: (this.Location_X11LIB && this.Location_X11TST && this.Location_X11EXT)?true:false });
 | 
			
		||||
 | 
			
		||||
        if (this.Location_X11LIB)
 | 
			
		||||
        {
 | 
			
		||||
            this._X11 = this._gm.CreateNativeProxy(this.Location_X11LIB);
 | 
			
		||||
            this._X11.CreateMethod('XChangeProperty');
 | 
			
		||||
            this._X11.CreateMethod('XCloseDisplay');
 | 
			
		||||
            this._X11.CreateMethod('XCreateGC');
 | 
			
		||||
            this._X11.CreateMethod('XCreateWindow');
 | 
			
		||||
            this._X11.CreateMethod('XCreateSimpleWindow');
 | 
			
		||||
            this._X11.CreateMethod('XDefaultColormap');
 | 
			
		||||
            this._X11.CreateMethod('XDefaultScreen');
 | 
			
		||||
            this._X11.CreateMethod('XDrawLine');
 | 
			
		||||
            this._X11.CreateMethod('XDisplayHeight');
 | 
			
		||||
            this._X11.CreateMethod('XDisplayWidth');
 | 
			
		||||
            this._X11.CreateMethod('XFetchName');
 | 
			
		||||
            this._X11.CreateMethod('XFlush');
 | 
			
		||||
            this._X11.CreateMethod('XFree');
 | 
			
		||||
            this._X11.CreateMethod('XCreateGC');
 | 
			
		||||
            this._X11.CreateMethod('XGetWindowProperty');
 | 
			
		||||
            this._X11.CreateMethod('XInternAtom');
 | 
			
		||||
            this._X11.CreateMethod('XMapWindow');
 | 
			
		||||
            this._X11.CreateMethod({ method: 'XNextEvent', threadDispatch: true });
 | 
			
		||||
            this._X11.CreateMethod('XOpenDisplay');
 | 
			
		||||
            this._X11.CreateMethod('XRootWindow');
 | 
			
		||||
            this._X11.CreateMethod('XScreenCount');
 | 
			
		||||
            this._X11.CreateMethod('XScreenOfDisplay');
 | 
			
		||||
            this._X11.CreateMethod('XSelectInput');
 | 
			
		||||
            this._X11.CreateMethod('XSendEvent');
 | 
			
		||||
            this._X11.CreateMethod('XSetForeground');
 | 
			
		||||
            this._X11.CreateMethod('XSetFunction');
 | 
			
		||||
            this._X11.CreateMethod('XSetLineAttributes');
 | 
			
		||||
            this._X11.CreateMethod('XSetNormalHints');
 | 
			
		||||
            this._X11.CreateMethod('XSetSubwindowMode');
 | 
			
		||||
 | 
			
		||||
            this._X11.CreateMethod('XBlackPixel');
 | 
			
		||||
            this._X11.CreateMethod('XWhitePixel');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isUnity = function isUnity()
 | 
			
		||||
        {
 | 
			
		||||
            var ret = false;
 | 
			
		||||
            var display = this._X11.XOpenDisplay(this._gm.CreateVariable(':0'));
 | 
			
		||||
            var rootWindow = this._X11.XRootWindow(display, this._X11.XDefaultScreen(display));
 | 
			
		||||
 | 
			
		||||
            var a = this._X11.XInternAtom(display, this._gm.CreateVariable('_NET_CLIENT_LIST'), 1);
 | 
			
		||||
            var actualType = this._gm.CreateVariable(8);
 | 
			
		||||
            var format = this._gm.CreateVariable(4);
 | 
			
		||||
            var numItems = this._gm.CreateVariable(8);
 | 
			
		||||
            var bytesAfter = this._gm.CreateVariable(8);
 | 
			
		||||
            var data = this._gm.CreatePointer();
 | 
			
		||||
 | 
			
		||||
            this._X11.XGetWindowProperty(display, rootWindow, a, 0, ~0, 0, 0, actualType, format, numItems, bytesAfter, data);
 | 
			
		||||
            for (var i = 0; i < numItems.Deref(0, 4).toBuffer().readUInt32LE(0) ; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                var w = data.Deref().Deref(i * 8, 8).Deref(8);
 | 
			
		||||
                var name = this._gm.CreatePointer();
 | 
			
		||||
                var ns = this._X11.XFetchName(display, w, name);
 | 
			
		||||
                if (name.Deref().String == 'unity-launcher')
 | 
			
		||||
                {
 | 
			
		||||
                    ret = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            this._X11.XCloseDisplay(display);
 | 
			
		||||
            return (ret);
 | 
			
		||||
            return (process.env['XDG_CURRENT_DESKTOP'] == 'Unity');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.unDecorateWindow = function unDecorateWindow(display, window)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
 | 
			
		|||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var GM = require('_GenericMarshal');
 | 
			
		||||
 | 
			
		||||
// Used on Windows and Linux to get information about running processes
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +22,8 @@ function processManager() {
 | 
			
		|||
    this._ObjectID = 'process-manager'; // Used for debugging, allows you to get the object type at runtime.
 | 
			
		||||
    
 | 
			
		||||
    // Setup the platform specific calls.
 | 
			
		||||
    switch (process.platform) {
 | 
			
		||||
    switch (process.platform)
 | 
			
		||||
    {
 | 
			
		||||
        case 'win32':
 | 
			
		||||
            this._kernel32 = GM.CreateNativeProxy('kernel32.dll');
 | 
			
		||||
            this._kernel32.CreateMethod('GetLastError');
 | 
			
		||||
| 
						 | 
				
			
			@ -30,17 +32,26 @@ function processManager() {
 | 
			
		|||
            this._kernel32.CreateMethod('Process32Next');
 | 
			
		||||
            break;
 | 
			
		||||
        case 'linux':
 | 
			
		||||
        case 'darwin':
 | 
			
		||||
            this._childProcess = require('child_process');
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            throw (process.platform + ' not supported');
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    this.enumerateProcesses = function enumerateProcesses()
 | 
			
		||||
    {
 | 
			
		||||
        var promise = require('promise');
 | 
			
		||||
        var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
 | 
			
		||||
        this.getProcesses(function (ps, prom) { prom._res(ps); }, ret);
 | 
			
		||||
        return (ret);
 | 
			
		||||
    }
 | 
			
		||||
    // Return a object of: pid -> process information.
 | 
			
		||||
    this.getProcesses = function getProcesses(callback) {
 | 
			
		||||
        switch (process.platform) {
 | 
			
		||||
            default: // This is not a supported platform.
 | 
			
		||||
    this.getProcesses = function getProcesses(callback)
 | 
			
		||||
    {
 | 
			
		||||
        switch(process.platform)
 | 
			
		||||
        {
 | 
			
		||||
            default:
 | 
			
		||||
                throw ('Enumerating processes on ' + process.platform + ' not supported');
 | 
			
		||||
                break;
 | 
			
		||||
            case 'win32': // Windows processes
 | 
			
		||||
| 
						 | 
				
			
			@ -49,8 +60,9 @@ function processManager() {
 | 
			
		|||
                var info = GM.CreateVariable(304);
 | 
			
		||||
                info.toBuffer().writeUInt32LE(304, 0);
 | 
			
		||||
                var nextProcess = this._kernel32.Process32First(h, info);
 | 
			
		||||
                while (nextProcess.Val) {
 | 
			
		||||
                    retVal[info.Deref(8, 4).toBuffer().readUInt32LE(0)] = { cmd: info.Deref(GM.PointerSize == 4 ? 36 : 44, 260).String };
 | 
			
		||||
                while (nextProcess.Val) 
 | 
			
		||||
                {
 | 
			
		||||
                    retVal[info.Deref(8, 4).toBuffer().readUInt32LE(0)] = { pid: info.Deref(8, 4).toBuffer().readUInt32LE(0), cmd: info.Deref(GM.PointerSize == 4 ? 36 : 44, 260).String };
 | 
			
		||||
                    nextProcess = this._kernel32.Process32Next(h, info);
 | 
			
		||||
                }
 | 
			
		||||
                if (callback) { callback.apply(this, [retVal]); }
 | 
			
		||||
| 
						 | 
				
			
			@ -64,40 +76,80 @@ function processManager() {
 | 
			
		|||
                p.callback = callback;
 | 
			
		||||
                p.args = [];
 | 
			
		||||
                for (var i = 1; i < arguments.length; ++i) { p.args.push(arguments[i]); }
 | 
			
		||||
                p.on('exit', function onGetProcesses() {
 | 
			
		||||
                    delete this.Parent._psp[this.pid];
 | 
			
		||||
                p.on('exit', function onGetProcesses()
 | 
			
		||||
                {
 | 
			
		||||
                    delete this.Parent._psp[this.pid]; 
 | 
			
		||||
                    var retVal = {}, lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
 | 
			
		||||
                    for (var i in lines) {
 | 
			
		||||
                    for (var i in lines)
 | 
			
		||||
                    {
 | 
			
		||||
                        var tokens = lines[i].split(' ');
 | 
			
		||||
                        var tokenList = [];
 | 
			
		||||
                        for (var x in tokens) {
 | 
			
		||||
                        for(var x in tokens)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (i == 0 && tokens[x]) { key[tokens[x]] = keyi++; }
 | 
			
		||||
                            if (i > 0 && tokens[x]) { tokenList.push(tokens[x]); }
 | 
			
		||||
                            if (i > 0 && tokens[x]) { tokenList.push(tokens[x]);}
 | 
			
		||||
                        }
 | 
			
		||||
                        if (i > 0) {
 | 
			
		||||
                            if (tokenList[key.PID]) { retVal[tokenList[key.PID]] = { user: tokenList[key.USER], cmd: tokenList[key.COMMAND] }; }
 | 
			
		||||
                            if (tokenList[key.PID]) { retVal[tokenList[key.PID]] = { pid: key.PID, user: tokenList[key.USER], cmd: tokenList[key.COMMAND] }; }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this.callback) {
 | 
			
		||||
                    if (this.callback)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.args.unshift(retVal);
 | 
			
		||||
                        this.callback.apply(this.parent, this.args);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                p.stdout.on('data', function (chunk) { this.parent.ps += chunk.toString(); });
 | 
			
		||||
                break;
 | 
			
		||||
            case 'darwin':
 | 
			
		||||
                var promise = require('promise');
 | 
			
		||||
                var p = new promise(function (res, rej) { this._res = res; this._rej = rej; });
 | 
			
		||||
                p.pm = this;
 | 
			
		||||
                p.callback = callback;
 | 
			
		||||
                p.args = [];
 | 
			
		||||
                for (var i = 1; i < arguments.length; ++i) { p.args.push(arguments[i]); }
 | 
			
		||||
                p.child = this._childProcess.execFile("/bin/ps", ["ps", "-xa"]);
 | 
			
		||||
                p.child.promise = p;
 | 
			
		||||
                p.child.stdout.ps = '';
 | 
			
		||||
                p.child.stdout.on('data', function (chunk) { this.ps += chunk.toString(); });
 | 
			
		||||
                p.child.on('exit', function ()
 | 
			
		||||
                {
 | 
			
		||||
                    var lines = this.stdout.ps.split('\n');
 | 
			
		||||
                    var pidX = lines[0].split('PID')[0].length + 3;
 | 
			
		||||
                    var cmdX = lines[0].split('CMD')[0].length;
 | 
			
		||||
                    var ret = {};
 | 
			
		||||
                    for (var i = 1; i < lines.length; ++i)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (lines[i].length > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            ret[lines[i].substring(0, pidX).trim()] = { pid: lines[i].substring(0, pidX).trim(), cmd: lines[i].substring(cmdX) };
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    this.promise._res(ret);
 | 
			
		||||
                });
 | 
			
		||||
                p.then(function (ps)
 | 
			
		||||
                {
 | 
			
		||||
                    this.args.unshift(ps);
 | 
			
		||||
                    this.callback.apply(this.pm, this.args);
 | 
			
		||||
                });
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Get information about a specific process on Linux
 | 
			
		||||
    this.getProcessInfo = function getProcessInfo(pid) {
 | 
			
		||||
        switch (process.platform) {
 | 
			
		||||
    this.getProcessInfo = function getProcessInfo(pid)
 | 
			
		||||
    {
 | 
			
		||||
        switch(process.platform)
 | 
			
		||||
        {
 | 
			
		||||
            default:
 | 
			
		||||
                throw ('getProcessInfo() not supported for ' + process.platform);
 | 
			
		||||
                break;
 | 
			
		||||
            case 'linux':
 | 
			
		||||
                var status = require('fs').readFileSync('/proc/' + pid + '/status');
 | 
			
		||||
                var info = {}, lines = status.toString().split('\n');
 | 
			
		||||
                for (var i in lines) {
 | 
			
		||||
                var info = {};
 | 
			
		||||
                var lines = status.toString().split('\n');
 | 
			
		||||
                for(var i in lines)
 | 
			
		||||
                {
 | 
			
		||||
                    var tokens = lines[i].split(':');
 | 
			
		||||
                    if (tokens.length > 1) { tokens[1] = tokens[1].trim(); }
 | 
			
		||||
                    info[tokens[0]] = tokens[1];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,10 +16,32 @@ limitations under the License.
 | 
			
		|||
 | 
			
		||||
var refTable = {};
 | 
			
		||||
 | 
			
		||||
function event_switcher_helper(desired_callee, target)
 | 
			
		||||
{
 | 
			
		||||
    this._ObjectID = 'event_switcher';
 | 
			
		||||
    this.func = function func()
 | 
			
		||||
    {
 | 
			
		||||
        var args = [];
 | 
			
		||||
        for(var i in arguments)
 | 
			
		||||
        {
 | 
			
		||||
            args.push(arguments[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return (func.target.apply(func.desired, args));
 | 
			
		||||
    };
 | 
			
		||||
    this.func.desired = desired_callee;
 | 
			
		||||
    this.func.target = target;
 | 
			
		||||
    this.func.self = this;
 | 
			
		||||
}
 | 
			
		||||
function event_switcher(desired_callee, target)
 | 
			
		||||
{
 | 
			
		||||
    return (new event_switcher_helper(desired_callee, target));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Promise(promiseFunc)
 | 
			
		||||
{
 | 
			
		||||
    this._ObjectID = 'promise';
 | 
			
		||||
    this._internal = { promise: this, func: promiseFunc, completed: false, errors: false, completedArgs: [] };
 | 
			
		||||
    this.promise = this;
 | 
			
		||||
    this._internal = { _ObjectID: 'promise.internal', promise: this, func: promiseFunc, completed: false, errors: false, completedArgs: [] };
 | 
			
		||||
    require('events').EventEmitter.call(this._internal);
 | 
			
		||||
    this._internal.on('_eventHook', function (eventName, eventCallback)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,21 +104,21 @@ function Promise(promiseFunc)
 | 
			
		|||
    };
 | 
			
		||||
    this.catch = function(func)
 | 
			
		||||
    {
 | 
			
		||||
        this._internal.once('settled', func);
 | 
			
		||||
        this._internal.once('rejected', event_switcher(this, func).func);
 | 
			
		||||
    }
 | 
			
		||||
    this.finally = function (func)
 | 
			
		||||
    {
 | 
			
		||||
        this._internal.once('settled', func);
 | 
			
		||||
        this._internal.once('settled', event_switcher(this, func).func);
 | 
			
		||||
    };
 | 
			
		||||
    this.then = function (resolved, rejected)
 | 
			
		||||
    {
 | 
			
		||||
        if (resolved) { this._internal.once('resolved', resolved); }
 | 
			
		||||
        if (rejected) { this._internal.once('rejected', rejected); }
 | 
			
		||||
        if (resolved) { this._internal.once('resolved', event_switcher(this, resolved).func); }
 | 
			
		||||
        if (rejected) { this._internal.once('rejected', event_switcher(this, rejected).func); }
 | 
			
		||||
 | 
			
		||||
        var retVal = new Promise(function (r, j) { });
 | 
			
		||||
 | 
			
		||||
        this._internal.once('resolved', retVal._internal.resolver);
 | 
			
		||||
        this._internal.once('rejected', retVal._internal.rejector);
 | 
			
		||||
        retVal.parentPromise = this;
 | 
			
		||||
        return (retVal);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,18 @@ var RSMB = 1381190978;
 | 
			
		|||
var memoryLocation = { 0x1: 'Other', 0x2: 'Unknown', 0x3: 'System Board', 0x4: 'ISA', 0x5: 'EISA', 0x6: 'PCI', 0x7: 'MCA', 0x8: 'PCMCIA', 0x9: 'Proprietary', 0xA: 'NuBus', 0xA0: 'PC-98/C20', 0xA1: 'PC-98/C24', 0xA2: 'PC-98/E', 0xA3: 'PC-98/LB' };
 | 
			
		||||
var wakeReason = ['Reserved', 'Other', 'Unknown', 'APM Timer', 'Modem Ring', 'LAN', 'Power Switch', 'PCI', 'AC Power'];
 | 
			
		||||
 | 
			
		||||
function SMBiosTables() {
 | 
			
		||||
// Fill the left with zeros until the string is of a given length
 | 
			
		||||
function zeroLeftPad(str, len)
 | 
			
		||||
{
 | 
			
		||||
    if ((len == null) && (typeof (len) != 'number')) { return null; }
 | 
			
		||||
    if (str == null) str = ''; // If null, this is to generate zero leftpad string
 | 
			
		||||
    var zlp = '';
 | 
			
		||||
    for (var i = 0; i < len - str.length; i++) { zlp += '0'; }
 | 
			
		||||
    return zlp + str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function SMBiosTables()
 | 
			
		||||
{
 | 
			
		||||
    this._ObjectID = 'SMBiosTable';
 | 
			
		||||
    if (process.platform == 'win32') {
 | 
			
		||||
        this._marshal = require('_GenericMarshal');
 | 
			
		||||
| 
						 | 
				
			
			@ -114,14 +125,14 @@ function SMBiosTables() {
 | 
			
		|||
            this.child = require('child_process').execFile('/usr/sbin/dmidecode', ['dmidecode', '-u']);
 | 
			
		||||
            this.child.SMBiosTable = this;
 | 
			
		||||
            this.child.ms = new MemoryStream();
 | 
			
		||||
            this.child.ms.callback = callback
 | 
			
		||||
            this.child.ms.callback = callback;
 | 
			
		||||
            this.child.ms.child = this.child;
 | 
			
		||||
            this.child.stdout.on('data', function (buffer) { this.parent.ms.write(buffer); });
 | 
			
		||||
            this.child.on('exit', function () { this.ms.end(); });
 | 
			
		||||
            this.child.ms.on('end', function () {
 | 
			
		||||
                //console.log('read ' + this.buffer.length + ' bytes');
 | 
			
		||||
                if (this.buffer.length < 300) { // TODO: Trap error message better that this.
 | 
			
		||||
                    console.log('Not enough permission to read SMBiosTable');
 | 
			
		||||
                if (this.buffer.length < 300) {
 | 
			
		||||
                    //console.log('Not enough permission to read SMBiosTable');
 | 
			
		||||
                    if (this.callback) { this.callback.apply(this.child.SMBiosTable, []); }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
| 
						 | 
				
			
			@ -181,12 +192,21 @@ function SMBiosTables() {
 | 
			
		|||
        }
 | 
			
		||||
        return (retVal);
 | 
			
		||||
    };
 | 
			
		||||
    this.systemInfo = function systemInfo(data) {
 | 
			
		||||
    this.systemInfo = function systemInfo(data)
 | 
			
		||||
    {
 | 
			
		||||
        if (!data) { throw ('no data'); }
 | 
			
		||||
        var retVal = { _ObjectID: 'SMBiosTables.systemInfo' };
 | 
			
		||||
        if (data[1]) {
 | 
			
		||||
        if (data[1])
 | 
			
		||||
        {
 | 
			
		||||
            var si = data[1].peek();
 | 
			
		||||
            retVal.uuid = si.slice(4, 20).toString('hex');
 | 
			
		||||
            var uuid = si.slice(4, 20);
 | 
			
		||||
 | 
			
		||||
            retVal.uuid = [zeroLeftPad(uuid.readUInt32LE(0).toString(16), 8),
 | 
			
		||||
            zeroLeftPad(uuid.readUInt16LE(4).toString(16), 4),
 | 
			
		||||
            zeroLeftPad(uuid.readUInt16LE(6).toString(16), 4),
 | 
			
		||||
            zeroLeftPad(uuid.readUInt16BE(8).toString(16), 4),
 | 
			
		||||
            zeroLeftPad(uuid.slice(10).toString('hex').toLowerCase(), 12)].join('-');
 | 
			
		||||
 | 
			
		||||
            retVal.wakeReason = wakeReason[si[20]];
 | 
			
		||||
        }
 | 
			
		||||
        return (retVal);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,13 @@ limitations under the License.
 | 
			
		|||
var NOTIFY_FOR_THIS_SESSION = 0;
 | 
			
		||||
var NOTIFY_FOR_ALL_SESSIONS = 1;
 | 
			
		||||
var WM_WTSSESSION_CHANGE = 0x02B1;
 | 
			
		||||
var WM_POWERBROADCAST = 0x218;
 | 
			
		||||
var PBT_POWERSETTINGCHANGE = 0x8013;
 | 
			
		||||
var PBT_APMSUSPEND = 0x4;
 | 
			
		||||
var PBT_APMRESUMESUSPEND = 0x7;
 | 
			
		||||
var PBT_APMRESUMEAUTOMATIC = 0x12;
 | 
			
		||||
var PBT_APMPOWERSTATUSCHANGE = 0xA;
 | 
			
		||||
 | 
			
		||||
var WTS_CONSOLE_CONNECT         = (0x1);
 | 
			
		||||
var WTS_CONSOLE_DISCONNECT      = (0x2);
 | 
			
		||||
var WTS_REMOTE_CONNECT          = (0x3);
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +36,10 @@ var WTS_SESSION_REMOTE_CONTROL  = (0x9);
 | 
			
		|||
var WTS_SESSION_CREATE          = (0xA);
 | 
			
		||||
var WTS_SESSION_TERMINATE       = (0xB);
 | 
			
		||||
 | 
			
		||||
var GUID_ACDC_POWER_SOURCE;
 | 
			
		||||
var GUID_BATTERY_PERCENTAGE_REMAINING;
 | 
			
		||||
var GUID_CONSOLE_DISPLAY_STATE;
 | 
			
		||||
 | 
			
		||||
function UserSessions()
 | 
			
		||||
{
 | 
			
		||||
    this._ObjectID = 'user-sessions';
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +60,15 @@ function UserSessions()
 | 
			
		|||
        {
 | 
			
		||||
            p.__resolver(users);
 | 
			
		||||
        };
 | 
			
		||||
        this.Current(p.__handler);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            this.Current(p.__handler);
 | 
			
		||||
        }
 | 
			
		||||
        catch(e)
 | 
			
		||||
        {
 | 
			
		||||
            p.__rejector(e);
 | 
			
		||||
        }
 | 
			
		||||
        p.parent = this;
 | 
			
		||||
        return (p);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +84,29 @@ function UserSessions()
 | 
			
		|||
        this._wts.CreateMethod('WTSRegisterSessionNotification');
 | 
			
		||||
        this._wts.CreateMethod('WTSUnRegisterSessionNotification');
 | 
			
		||||
        this._wts.CreateMethod('WTSFreeMemory');
 | 
			
		||||
        this._user32 = this._marshal.CreateNativeProxy('user32.dll');
 | 
			
		||||
        this._user32.CreateMethod('RegisterPowerSettingNotification');
 | 
			
		||||
        this._user32.CreateMethod('UnregisterPowerSettingNotification');
 | 
			
		||||
        this._rpcrt = this._marshal.CreateNativeProxy('Rpcrt4.dll');
 | 
			
		||||
        this._rpcrt.CreateMethod('UuidFromStringA');
 | 
			
		||||
        this._rpcrt.StringToUUID = function StringToUUID(guid)
 | 
			
		||||
        {
 | 
			
		||||
            var retVal = StringToUUID.us._marshal.CreateVariable(16);
 | 
			
		||||
            if(StringToUUID.us._rpcrt.UuidFromStringA(StringToUUID.us._marshal.CreateVariable(guid), retVal).Val == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return (retVal);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw ('Could not convert string to UUID');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._rpcrt.StringToUUID.us = this;
 | 
			
		||||
 | 
			
		||||
        GUID_ACDC_POWER_SOURCE = this._rpcrt.StringToUUID('5d3e9a59-e9D5-4b00-a6bd-ff34ff516548');
 | 
			
		||||
        GUID_BATTERY_PERCENTAGE_REMAINING = this._rpcrt.StringToUUID('a7ad8041-b45a-4cae-87a3-eecbb468a9e1');
 | 
			
		||||
        GUID_CONSOLE_DISPLAY_STATE = this._rpcrt.StringToUUID('6fe69556-704a-47a0-8f24-c28d936fda47');
 | 
			
		||||
 | 
			
		||||
        this.SessionStates = ['Active', 'Connected', 'ConnectQuery', 'Shadow', 'Disconnected', 'Idle', 'Listening', 'Reset', 'Down', 'Init'];
 | 
			
		||||
        this.InfoClass =
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -146,45 +188,112 @@ function UserSessions()
 | 
			
		|||
            return (retVal);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this._immediate = setImmediate(function (self)
 | 
			
		||||
        {
 | 
			
		||||
            if (self._serviceHooked) { return; } // If we were hooked by a service, we won't need to do anything further
 | 
			
		||||
 | 
			
		||||
            // We need to spin up a message pump, and fetch a window handle
 | 
			
		||||
            var message_pump = require('win-message-pump');
 | 
			
		||||
            self._messagepump = new message_pump({ filter: WM_WTSSESSION_CHANGE });
 | 
			
		||||
            self._messagepump.on('exit', function (code) { self._wts.WTSUnRegisterSessionNotification(self.hwnd); });
 | 
			
		||||
            self._messagepump.on('hwnd', function (h)
 | 
			
		||||
        // We need to spin up a message pump, and fetch a window handle
 | 
			
		||||
        var message_pump = require('win-message-pump');
 | 
			
		||||
        this._messagepump = new message_pump({ filter: WM_WTSSESSION_CHANGE }); this._messagepump.parent = this;     
 | 
			
		||||
        this._messagepump.on('exit', function (code) { this.parent._wts.WTSUnRegisterSessionNotification(this.parent.hwnd); });
 | 
			
		||||
        this._messagepump.on('hwnd', function (h)
 | 
			
		||||
        {
 | 
			
		||||
            this.parent.hwnd = h;
 | 
			
		||||
 | 
			
		||||
            // Now that we have a window handle, we can register it to receive Windows Messages
 | 
			
		||||
            this.parent._wts.WTSRegisterSessionNotification(this.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS);
 | 
			
		||||
            this.parent._user32.ACDC_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0);
 | 
			
		||||
            this.parent._user32.BATT_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0);
 | 
			
		||||
            this.parent._user32.DISP_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0);
 | 
			
		||||
        });
 | 
			
		||||
        this._messagepump.on('message', function (msg)
 | 
			
		||||
        {
 | 
			
		||||
            switch(msg.message)
 | 
			
		||||
            {
 | 
			
		||||
                self.hwnd = h;
 | 
			
		||||
                // Now that we have a window handle, we can register it to receive Windows Messages
 | 
			
		||||
                self._wts.WTSRegisterSessionNotification(self.hwnd, NOTIFY_FOR_ALL_SESSIONS);
 | 
			
		||||
            });
 | 
			
		||||
            self._messagepump.on('message', function (msg)
 | 
			
		||||
            {
 | 
			
		||||
                if (msg.message == WM_WTSSESSION_CHANGE)
 | 
			
		||||
                {
 | 
			
		||||
                case WM_WTSSESSION_CHANGE:
 | 
			
		||||
                    switch(msg.wparam)
 | 
			
		||||
                    {
 | 
			
		||||
                        case WTS_SESSION_LOCK:
 | 
			
		||||
                            self.enumerateUsers().then(function (users)
 | 
			
		||||
                            this.parent.enumerateUsers().then(function (users)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (users[msg.lparam]) { self.emit('locked', users[msg.lparam]); }
 | 
			
		||||
                                if (users[msg.lparam]) { this.parent.emit('locked', users[msg.lparam]); }
 | 
			
		||||
                            });
 | 
			
		||||
                            break;
 | 
			
		||||
                        case WTS_SESSION_UNLOCK:
 | 
			
		||||
                            self.enumerateUsers().then(function (users)
 | 
			
		||||
                            this.parent.enumerateUsers().then(function (users)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (users[msg.lparam]) { self.emit('unlocked', users[msg.lparam]); }
 | 
			
		||||
                                if (users[msg.lparam]) { this.parent.emit('unlocked', users[msg.lparam]); }
 | 
			
		||||
                            });
 | 
			
		||||
                            break;
 | 
			
		||||
                        case WTS_SESSION_LOGON:
 | 
			
		||||
                        case WTS_SESSION_LOGOFF:
 | 
			
		||||
                            this.parent.emit('changed');
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }, this);
 | 
			
		||||
                    break;
 | 
			
		||||
                case WM_POWERBROADCAST:
 | 
			
		||||
                    switch(msg.wparam)
 | 
			
		||||
                    {
 | 
			
		||||
                        default:
 | 
			
		||||
                            console.log('WM_POWERBROADCAST [UNKNOWN wparam]: ' + msg.wparam);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case PBT_APMSUSPEND:
 | 
			
		||||
                            require('power-monitor').emit('sx', 'SLEEP');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case PBT_APMRESUMEAUTOMATIC:
 | 
			
		||||
                            require('power-monitor').emit('sx', 'RESUME_NON_INTERACTIVE');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case PBT_APMRESUMESUSPEND:
 | 
			
		||||
                            require('power-monitor').emit('sx', 'RESUME_INTERACTIVE');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case PBT_APMPOWERSTATUSCHANGE:
 | 
			
		||||
                            require('power-monitor').emit('changed');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case PBT_POWERSETTINGCHANGE:
 | 
			
		||||
                            var lparam = this.parent._marshal.CreatePointer(Buffer.from(msg.lparam_hex, 'hex'));
 | 
			
		||||
                            var data = lparam.Deref(20, lparam.Deref(16, 4).toBuffer().readUInt32LE(0)).toBuffer();
 | 
			
		||||
                            switch(lparam.Deref(0, 16).toBuffer().toString('hex'))
 | 
			
		||||
                            {
 | 
			
		||||
                                case GUID_ACDC_POWER_SOURCE.Deref(0, 16).toBuffer().toString('hex'):
 | 
			
		||||
                                    switch(data.readUInt32LE(0))
 | 
			
		||||
                                    {
 | 
			
		||||
                                        case 0:
 | 
			
		||||
                                            require('power-monitor').emit('acdc', 'AC');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        case 1:
 | 
			
		||||
                                            require('power-monitor').emit('acdc', 'BATTERY');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        case 2:
 | 
			
		||||
                                            require('power-monitor').emit('acdc', 'HOT');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                    }
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case GUID_BATTERY_PERCENTAGE_REMAINING.Deref(0, 16).toBuffer().toString('hex'):
 | 
			
		||||
                                    require('power-monitor').emit('batteryLevel', data.readUInt32LE(0));
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case GUID_CONSOLE_DISPLAY_STATE.Deref(0, 16).toBuffer().toString('hex'):
 | 
			
		||||
                                    switch(data.readUInt32LE(0))
 | 
			
		||||
                                    {
 | 
			
		||||
                                        case 0:
 | 
			
		||||
                                            require('power-monitor').emit('display', 'OFF');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        case 1:
 | 
			
		||||
                                            require('power-monitor').emit('display', 'ON');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        case 2:
 | 
			
		||||
                                            require('power-monitor').emit('display', 'DIMMED');
 | 
			
		||||
                                            break;
 | 
			
		||||
                                    }
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    else if(process.platform == 'linux')
 | 
			
		||||
    {
 | 
			
		||||
        var dbus = require('linux-dbus');
 | 
			
		||||
        this._linuxWatcher = require('fs').watch('/var/run/utmp');
 | 
			
		||||
        this._linuxWatcher.user_session = this;
 | 
			
		||||
        this._linuxWatcher.on('change', function (a, b)
 | 
			
		||||
| 
						 | 
				
			
			@ -336,6 +445,112 @@ function UserSessions()
 | 
			
		|||
 | 
			
		||||
            return (retVal);
 | 
			
		||||
        }
 | 
			
		||||
        this._recheckLoggedInUsers = function _recheckLoggedInUsers()
 | 
			
		||||
        {
 | 
			
		||||
            this.enumerateUsers().then(function (u)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                if (u.Active.length > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    // There is already a user logged in, so we can monitor DBUS for lock/unlock
 | 
			
		||||
                    if (this.parent._linux_lock_watcher != null && this.parent._linux_lock_watcher.uid != u.Active[0].uid)
 | 
			
		||||
                    {
 | 
			
		||||
                        delete this.parent._linux_lock_watcher;
 | 
			
		||||
                    }
 | 
			
		||||
                    this.parent._linux_lock_watcher = new dbus(process.env['XDG_CURRENT_DESKTOP'] == 'Unity' ? 'com.ubuntu.Upstart0_6' : 'org.gnome.ScreenSaver', u.Active[0].uid);
 | 
			
		||||
                    this.parent._linux_lock_watcher.user_session = this.parent;
 | 
			
		||||
                    this.parent._linux_lock_watcher.on('signal', function (s)
 | 
			
		||||
                    {
 | 
			
		||||
                        var p = this.user_session.enumerateUsers();
 | 
			
		||||
                        p.signalData = s.data[0];
 | 
			
		||||
                        p.then(function (u)
 | 
			
		||||
                        {
 | 
			
		||||
                            switch (this.signalData)
 | 
			
		||||
                            {
 | 
			
		||||
                                case true:
 | 
			
		||||
                                case 'desktop-lock':
 | 
			
		||||
                                    this.parent.emit('locked', u.Active[0]);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case false:
 | 
			
		||||
                                case 'desktop-unlock':
 | 
			
		||||
                                    this.parent.emit('unlocked', u.Active[0]);
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                else if (this.parent._linux_lock_watcher != null)
 | 
			
		||||
                {
 | 
			
		||||
                    delete this.parent._linux_lock_watcher;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        };
 | 
			
		||||
        this.on('changed', this._recheckLoggedInUsers); // For linux Lock/Unlock monitoring, we need to watch for LogOn/LogOff, and keep track of the UID.
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        // First step, is to see if there is a user logged in:
 | 
			
		||||
        this._recheckLoggedInUsers();
 | 
			
		||||
    }
 | 
			
		||||
    else if(process.platform == 'darwin')
 | 
			
		||||
    {
 | 
			
		||||
        this._idTable = function()
 | 
			
		||||
        {
 | 
			
		||||
            var table = {};
 | 
			
		||||
            var child = require('child_process').execFile('/usr/bin/id', ['id']);
 | 
			
		||||
            child.stdout.str = '';
 | 
			
		||||
            child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
 | 
			
		||||
            child.waitExit();
 | 
			
		||||
 | 
			
		||||
            var lines = child.stdout.str.split('\n')[0].split(' ');
 | 
			
		||||
            for (var i = 0; i < lines.length; ++i) {
 | 
			
		||||
                var types = lines[i].split('=');
 | 
			
		||||
                var tokens = types[1].split(',');
 | 
			
		||||
                table[types[0]] = {};
 | 
			
		||||
 | 
			
		||||
                for (var j in tokens) {
 | 
			
		||||
                    var idarr = tokens[j].split('(');
 | 
			
		||||
                    var id = idarr[0];
 | 
			
		||||
                    var name = idarr[1].substring(0, idarr[1].length - 1).trim();
 | 
			
		||||
                    table[types[0]][name] = id;
 | 
			
		||||
                    table[types[0]][id] = name;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return (table);
 | 
			
		||||
        }
 | 
			
		||||
        this.Current = function (cb)
 | 
			
		||||
        {
 | 
			
		||||
            var users = {};
 | 
			
		||||
            var table = this._idTable();
 | 
			
		||||
            var child = require('child_process').execFile('/usr/bin/last', ['last']);
 | 
			
		||||
            child.stdout.str = '';
 | 
			
		||||
            child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
 | 
			
		||||
            child.waitExit();
 | 
			
		||||
 | 
			
		||||
            var lines = child.stdout.str.split('\n');
 | 
			
		||||
            for (var i = 0; i < lines.length && lines[i].length > 0; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (!users[lines[i].split(' ')[0]])
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        users[lines[i].split(' ')[0]] = { Username: lines[i].split(' ')[0], State: lines[i].split('still logged in').length > 1 ? 'Active' : 'Inactive', uid: table.uid[lines[i].split(' ')[0]] };
 | 
			
		||||
                    }
 | 
			
		||||
                    catch(e)
 | 
			
		||||
                    {}
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if(users[lines[i].split(' ')[0]].State != 'Active' && lines[i].split('still logged in').length > 1)
 | 
			
		||||
                    {
 | 
			
		||||
                        users[lines[i].split(' ')[0]].State = 'Active';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Object.defineProperty(users, 'Active', { value: showActiveOnly(users) });
 | 
			
		||||
            if (cb) { cb.call(this, users); }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
function showActiveOnly(source)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,3 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 Intel Corporation
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function _Scan()
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,7 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2018 Intel Corporation
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
var MemoryStream = require('MemoryStream');
 | 
			
		||||
var WindowsChildScript = 'var parent = require("ScriptContainer");var Wireless = require("wifi-scanner-windows");Wireless.on("Scan", function (ap) { parent.send(ap); });Wireless.Scan();';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function AccessPoint(_ssid, _bssid, _lq)
 | 
			
		||||
{
 | 
			
		||||
    this.ssid = _ssid;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ function WindowsMessagePump(options)
 | 
			
		|||
        {\
 | 
			
		||||
            if(h==null || h.Val == xhwnd.Val)\
 | 
			
		||||
            {\
 | 
			
		||||
                require('ScriptContainer').send({message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val});\
 | 
			
		||||
                require('ScriptContainer').send({message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val, lparam_hex: lparam.pointerBuffer().toString('hex')});\
 | 
			
		||||
                var retVal = u.DefWindowProcA(xhwnd, xmsg, wparam, lparam);\
 | 
			
		||||
                return(retVal);\
 | 
			
		||||
            }\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,7 +179,7 @@ function CreateMeshCentralServer(config, args) {
 | 
			
		|||
        xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Updating server certificates...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } else if (data.indexOf('Starting self upgrade...') >= 0) { xprocess.xrestart = 3; } console.log(data); });
 | 
			
		||||
        xprocess.stderr.on('data', function (data) {
 | 
			
		||||
            if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock
 | 
			
		||||
            if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync(obj.getConfigFilePath('mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n');
 | 
			
		||||
            if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync(obj.getConfigFilePath('mesherrors.txt'), '-------- ' + new Date().toLocaleString() + ' ---- ' + obj.currentVer + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n');
 | 
			
		||||
        });
 | 
			
		||||
        xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } });
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -1104,7 +1104,7 @@ function CreateMeshCentralServer(config, args) {
 | 
			
		|||
    function logErrorEvent(msg) { if (obj.servicelog != null) { obj.servicelog.error(msg); } console.error(msg); }
 | 
			
		||||
 | 
			
		||||
    // Read entire file and return it in callback function
 | 
			
		||||
    function readEntireTextFile(filepath, func) {
 | 
			
		||||
    obj.readEntireTextFile = function(filepath, func) {
 | 
			
		||||
        var called = false;
 | 
			
		||||
        try {
 | 
			
		||||
            obj.fs.open(filepath, 'r', function (err, fd) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								meshuser.js
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								meshuser.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -561,6 +561,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                        obj.parent.parent.performServerUpdate();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'servererrors':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Load the server error log
 | 
			
		||||
                        if ((user.siteadmin & 16) == 0) break;
 | 
			
		||||
                        obj.parent.parent.readEntireTextFile(obj.parent.parent.getConfigFilePath('mesherrors.txt'), function (data) { ws.send(JSON.stringify({ action: 'servererrors', data: data })); } );
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'serverclearerrorlog':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Clear the server error log
 | 
			
		||||
                        if ((user.siteadmin & 16) == 0) break;
 | 
			
		||||
                        obj.parent.parent.fs.unlink(obj.parent.parent.getConfigFilePath('mesherrors.txt'));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'createmesh':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Create mesh
 | 
			
		||||
| 
						 | 
				
			
			@ -1262,6 +1276,26 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
        ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo }));
 | 
			
		||||
    } catch (e) { console.log(e); }
 | 
			
		||||
 | 
			
		||||
    // Read entire file and return it in callback function
 | 
			
		||||
    function readEntireTextFile(filepath, func) {
 | 
			
		||||
        var called = false;
 | 
			
		||||
        try {
 | 
			
		||||
            obj.fs.open(filepath, 'r', function (err, fd) {
 | 
			
		||||
                obj.fs.fstat(fd, function (err, stats) {
 | 
			
		||||
                    var bufferSize = stats.size, chunkSize = 512, buffer = new Buffer(bufferSize), bytesRead = 0;
 | 
			
		||||
                    while (bytesRead < bufferSize) {
 | 
			
		||||
                        if ((bytesRead + chunkSize) > bufferSize) { chunkSize = (bufferSize - bytesRead); }
 | 
			
		||||
                        obj.fs.readSync(fd, buffer, bytesRead, chunkSize, bytesRead);
 | 
			
		||||
                        bytesRead += chunkSize;
 | 
			
		||||
                    }
 | 
			
		||||
                    obj.fs.close(fd);
 | 
			
		||||
                    called = true;
 | 
			
		||||
                    func(buffer.toString('utf8', 0, bufferSize));
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        } catch (e) { if (called == false) { func(null); } }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Read the folder and all sub-folders and serialize that into json.
 | 
			
		||||
    function readFilesRec(path) {
 | 
			
		||||
        var r = {}, dir = obj.fs.readdirSync(path);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "meshcentral",
 | 
			
		||||
  "version": "0.2.0-o",
 | 
			
		||||
  "version": "0.2.0-p",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "Remote Management",
 | 
			
		||||
    "Intel AMT",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -242,6 +242,7 @@
 | 
			
		|||
                        <a id="p2ServerActionsBackup" href="/backup.zip" target="_blank" style="cursor:pointer">Download server backup</a><br />
 | 
			
		||||
                        <a id="p2ServerActionsRestore" onclick="server_showRestoreDlg()" style="cursor:pointer">Restore server with backup</a><br />
 | 
			
		||||
                        <a id="p2ServerActionsVersion" onclick="server_showVersionDlg()" style="cursor:pointer">Check server version</a><br />
 | 
			
		||||
                        <a id="p2ServerActionsErrors" onclick="server_showErrorsDlg()" style="cursor:pointer">Show server error log</a><br />
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <br style=clear:both />
 | 
			
		||||
                    <strong>Administrative Meshes</strong>
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,6 +1179,18 @@
 | 
			
		|||
                    }
 | 
			
		||||
                    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 /><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to clear error log.');
 | 
			
		||||
                            server_showVersionDlgUpdate();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'events': {
 | 
			
		||||
                    if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
 | 
			
		||||
                        currentDeviceEvents = message.events;
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,8 +1675,9 @@
 | 
			
		|||
                    var nodestate = NodeStateStr(nodes[i]);
 | 
			
		||||
                    if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
 | 
			
		||||
                    if (view == 1) {
 | 
			
		||||
                        var xw = Math.floor(Q('xdevices').clientWidth / 301);
 | 
			
		||||
                        xw = 301 + Math.floor((Q('xdevices').clientWidth - (xw * 301)) / xw);
 | 
			
		||||
                        var realw = Q('xdevices').clientWidth - 30;
 | 
			
		||||
                        var xw = Math.floor(realw / 301);
 | 
			
		||||
                        xw = 301 + Math.floor((realw - (xw * 301)) / xw);
 | 
			
		||||
                        r += '<div id=devs style=display:inline-block;width:' + xw + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><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:' + (xw - 100) + 'px title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div>';
 | 
			
		||||
                    } else if (view == 2) {
 | 
			
		||||
                        r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>';
 | 
			
		||||
| 
						 | 
				
			
			@ -1671,7 +1685,7 @@
 | 
			
		|||
                        r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + nodes[i]._id + '\')><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(\'' + nodes[i]._id + '\')><span style=float:right>' + nodestate + '</span><span style=width:300px>' + name + '</span></div></div></td></tr>';
 | 
			
		||||
                    } else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0)) {
 | 
			
		||||
                    } else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0) && ((nodes[i].agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
 | 
			
		||||
                        if ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + nodes[i]._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(\'' + nodes[i]._id + '\',11)>';
 | 
			
		||||
                            //r += '<input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox style=float:left>';
 | 
			
		||||
| 
						 | 
				
			
			@ -3106,8 +3120,8 @@
 | 
			
		|||
                // 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)) && (meshrights & 8));
 | 
			
		||||
                QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0)) && (meshrights & 8));
 | 
			
		||||
                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));
 | 
			
		||||
                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));
 | 
			
		||||
                QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
 | 
			
		||||
                QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
 | 
			
		||||
                QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
 | 
			
		||||
| 
						 | 
				
			
			@ -3512,12 +3526,12 @@
 | 
			
		|||
 | 
			
		||||
            // Show the right buttons
 | 
			
		||||
            QV('disconnectbutton1span', (deskState != 0));
 | 
			
		||||
            QV('connectbutton1span', (deskState == 0) && (mesh.mtype == 2));
 | 
			
		||||
            QV('connectbutton1span', (deskState == 0) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
 | 
			
		||||
            QV('connectbutton1hspan', (deskState == 0) && ((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', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
 | 
			
		||||
            QV('d7meshkvm', (mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1)));
 | 
			
		||||
 | 
			
		||||
            // Enable buttons
 | 
			
		||||
            var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
 | 
			
		||||
| 
						 | 
				
			
			@ -3859,7 +3873,7 @@
 | 
			
		|||
 | 
			
		||||
            // Show the right buttons
 | 
			
		||||
            QV('disconnectbutton2span', (termState == true));
 | 
			
		||||
            QV('connectbutton2span', (termState == false) && (mesh.mtype == 2));
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			@ -4815,6 +4829,14 @@
 | 
			
		|||
        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
 | 
			
		||||
        //
 | 
			
		||||
| 
						 | 
				
			
			@ -5911,9 +5933,7 @@
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        function dialogclose(x) {
 | 
			
		||||
            var f = xxdialogFunc;
 | 
			
		||||
            var b = xxdialogButtons;
 | 
			
		||||
            var t = xxdialogTag;
 | 
			
		||||
            var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
 | 
			
		||||
            setDialogMode();
 | 
			
		||||
            if (((b & 8) || x) && f) f(x, t);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue