New toast notifications
This commit is contained in:
parent
b6b2706d19
commit
bd82453c3b
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -18,7 +18,7 @@ function createMeshCore(agent) {
|
|||
var obj = {};
|
||||
|
||||
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
||||
obj.meshCoreInfo = "MeshCore v4";
|
||||
obj.meshCoreInfo = "MeshCore v5";
|
||||
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
|
||||
var meshServerConnectionState = 0;
|
||||
var tunnels = {};
|
||||
|
@ -402,6 +402,11 @@ function createMeshCore(agent) {
|
|||
getIpLocationData(function (location) { mesh.SendCommand({ "action": "iplocation", "type": "publicip", "value": location }); });
|
||||
break;
|
||||
}
|
||||
case 'toast': {
|
||||
// Display a toast message
|
||||
if (data.title && data.msg) { require('toaster').Toast(data.title, data.msg); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +526,6 @@ function createMeshCore(agent) {
|
|||
|
||||
// Clean up WebSocket
|
||||
this.removeAllListeners('data');
|
||||
delete this;
|
||||
}
|
||||
function onTunnelSendOk() { sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid); }
|
||||
function onTunnelData(data) {
|
||||
|
@ -571,19 +575,28 @@ function createMeshCore(agent) {
|
|||
this.on('data', onTunnelControlData);
|
||||
//this.write('MeshCore Terminal Hello');
|
||||
if (process.platform != 'win32') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n"); }
|
||||
} else if (this.httprequest.protocol == 2) {
|
||||
} else if (this.httprequest.protocol == 2)
|
||||
{
|
||||
// Remote desktop using native pipes
|
||||
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
|
||||
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
|
||||
this.desktop = this.httprequest.desktop;
|
||||
|
||||
// Display a toast message
|
||||
//require('toaster').Toast('MeshCentral', 'Remote Desktop Control Started.');
|
||||
|
||||
this.end = function () {
|
||||
--this.desktop.kvm.connectionCount;
|
||||
this.unpipe(this.httprequest.desktop.kvm);
|
||||
this.httprequest.desktop.kvm.unpipe(this);
|
||||
if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
|
||||
if (this.desktop.kvm.connectionCount == 0) {
|
||||
// Display a toast message
|
||||
//require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.');
|
||||
this.httprequest.desktop.kvm.end();
|
||||
}
|
||||
};
|
||||
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
|
||||
this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. (****************)
|
||||
this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
this.removeAllListeners('data');
|
||||
this.on('data', onTunnelControlData);
|
||||
|
@ -839,7 +852,12 @@ function createMeshCore(agent) {
|
|||
var response = null;
|
||||
switch (cmd) {
|
||||
case 'help': { // Displays available commands
|
||||
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.';
|
||||
response = 'aaaAvailable 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.';
|
||||
break;
|
||||
}
|
||||
case 'toast': {
|
||||
require('toaster').Toast('MeshCentral', args['_'][0]);
|
||||
response = 'ok';
|
||||
break;
|
||||
}
|
||||
case 'setdebug': {
|
||||
|
|
|
@ -5,15 +5,16 @@ 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
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
// JavaScript source code
|
||||
var GM = require('_GenericMarshal');
|
||||
|
||||
function processManager() {
|
||||
|
@ -34,12 +35,16 @@ function processManager() {
|
|||
}
|
||||
this.getProcesses = function getProcesses(callback) {
|
||||
switch (process.platform) {
|
||||
default:
|
||||
throw ('Enumerating processes on ' + process.platform + ' not supported');
|
||||
case 'win32':
|
||||
var h = this._kernel32.CreateToolhelp32Snapshot(2, 0), info = GM.CreateVariable(304), retVal = {};
|
||||
var retVal = [];
|
||||
var h = this._kernel32.CreateToolhelp32Snapshot(2, 0);
|
||||
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 };
|
||||
retVal.push({ 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]); }
|
||||
|
@ -55,15 +60,16 @@ function processManager() {
|
|||
for (var i = 1; i < arguments.length; ++i) { p.args.push(arguments[i]); }
|
||||
p.on('exit', function onGetProcesses() {
|
||||
delete this.Parent._psp[this.pid];
|
||||
var retVal = {}, lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
|
||||
var retVal = [], lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
|
||||
for (var i in lines) {
|
||||
var tokens = lines[i].split(' '), tokenList = [];
|
||||
var tokens = lines[i].split(' ');
|
||||
var tokenList = [];
|
||||
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) && (tokenList[key.PID])) {
|
||||
retVal[tokenList[key.PID]] = { user: tokenList[key.USER], cmd: tokenList[key.COMMAND] };
|
||||
retVal.push({ pid: tokenList[key.PID], user: tokenList[key.USER], cmd: tokenList[key.COMMAND] });
|
||||
}
|
||||
}
|
||||
if (this.callback) {
|
||||
|
@ -73,22 +79,20 @@ function processManager() {
|
|||
});
|
||||
p.stdout.on('data', function (chunk) { this.parent.ps += chunk.toString(); });
|
||||
break;
|
||||
default:
|
||||
throw ('Enumerating processes on ' + process.platform + ' not supported');
|
||||
}
|
||||
};
|
||||
this.getProcessInfo = function getProcessInfo(pid) {
|
||||
switch (process.platform) {
|
||||
default:
|
||||
throw ('getProcessInfo() not supported for ' + process.platform);
|
||||
case 'linux':
|
||||
var status = require('fs').readFileSync('/proc/' + pid + '/status'), lines = status.toString().split('\n'), info = {};
|
||||
var status = require('fs').readFileSync('/proc/' + pid + '/status'), info = {}, 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];
|
||||
}
|
||||
return info;
|
||||
default:
|
||||
throw ('getProcessInfo() not supported for ' + process.platform);
|
||||
return (info);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
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 toasters = {};
|
||||
|
||||
function Toaster()
|
||||
{
|
||||
this._ObjectID = 'Toaster';
|
||||
this.Toast = function Toast(title, caption)
|
||||
{
|
||||
if (process.platform != 'win32') return;
|
||||
|
||||
var retVal = {};
|
||||
var emitter = require('events').inherits(retVal);
|
||||
emitter.createEvent('Clicked');
|
||||
emitter.createEvent('Dismissed');
|
||||
|
||||
var session = require('user-sessions').Current();
|
||||
for (var i in session)
|
||||
{
|
||||
console.log(session[i]);
|
||||
}
|
||||
try
|
||||
{
|
||||
console.log('Attempting Toast Mechanism 1');
|
||||
retVal._child = require('ScriptContainer').Create({ processIsolation: true, sessionId: session.connected[0].SessionId });
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
console.log('Attempting Toast Mechanism 2');
|
||||
retVal._child = require('ScriptContainer').Create({ processIsolation: true });
|
||||
}
|
||||
retVal._child.parent = retVal;
|
||||
|
||||
retVal._child.on('exit', function (code) { this.parent.emit('Dismissed'); delete this.parent._child; });
|
||||
retVal._child.addModule('win-console', getJSModule('win-console'));
|
||||
retVal._child.addModule('win-messagepump', getJSModule('win-messagepump'));
|
||||
|
||||
var str = "\
|
||||
try{\
|
||||
var toast = require('win-console');\
|
||||
var balloon = toast.SetTrayIcon({ szInfo: '" + caption + "', szInfoTitle: '" + title + "', balloonOnly: true });\
|
||||
balloon.on('ToastDismissed', function(){process.exit();});\
|
||||
}\
|
||||
catch(e)\
|
||||
{\
|
||||
require('ScriptContainer').send(e);\
|
||||
}\
|
||||
require('ScriptContainer').send('done');\
|
||||
";
|
||||
retVal._child.ExecuteString(str);
|
||||
toasters[retVal._hashCode()] = retVal;
|
||||
retVal.on('Dismissed', function () { delete toasters[this._hashCode()]; });
|
||||
console.log('Returning');
|
||||
return (retVal);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = new Toaster();
|
|
@ -1,4 +1,18 @@
|
|||
/*
|
||||
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 UserSessions()
|
||||
{
|
||||
|
@ -87,6 +101,8 @@ function UserSessions()
|
|||
}
|
||||
|
||||
this._wts.WTSFreeMemory(pinfo.Deref());
|
||||
|
||||
Object.defineProperty(retVal, 'connected', { value: showActiveOnly(retVal) });
|
||||
return (retVal);
|
||||
};
|
||||
}
|
||||
|
@ -94,9 +110,58 @@ function UserSessions()
|
|||
{
|
||||
this.Current = function Current()
|
||||
{
|
||||
return ({});
|
||||
var retVal = {};
|
||||
var emitterUtils = require('events').inherits(retVal);
|
||||
emitterUtils.createEvent('logon');
|
||||
|
||||
retVal._child = require('child_process').execFile('/usr/bin/last', ['last', '-f', '/var/run/utmp']);
|
||||
retVal._child.Parent = retVal;
|
||||
retVal._child._txt = '';
|
||||
retVal._child.on('exit', function (code)
|
||||
{
|
||||
var lines = this._txt.split('\n');
|
||||
var sessions = [];
|
||||
for(var i in lines)
|
||||
{
|
||||
if (lines[i])
|
||||
{
|
||||
console.log(getTokens(lines[i]));
|
||||
var user = lines[i].substring(0, lines[i].indexOf(' '));
|
||||
sessions.push(user);
|
||||
}
|
||||
}
|
||||
sessions.pop();
|
||||
console.log(sessions);
|
||||
});
|
||||
retVal._child.stdout.Parent = retVal._child;
|
||||
retVal._child.stdout.on('data', function (chunk) { this.Parent._txt += chunk.toString(); });
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
function showActiveOnly(source)
|
||||
{
|
||||
var retVal = [];
|
||||
for (var i in source)
|
||||
{
|
||||
if (source[i].State == 'Active' || source[i].State == 'Connected')
|
||||
{
|
||||
retVal.push(source[i]);
|
||||
}
|
||||
}
|
||||
return (retVal);
|
||||
}
|
||||
function getTokens(str)
|
||||
{
|
||||
var columns = [];
|
||||
var i;
|
||||
|
||||
columns.push(str.substring(0, (i=str.indexOf(' '))));
|
||||
while (str[++i] == ' ');
|
||||
columns.push(str.substring(i, str.substring(i).indexOf(' ') + i));
|
||||
|
||||
return (columns);
|
||||
}
|
||||
|
||||
module.exports = new UserSessions();
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
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,7 +1,22 @@
|
|||
/*
|
||||
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;
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
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 TrayIconFlags =
|
||||
{
|
||||
NIF_MESSAGE: 0x00000001,
|
||||
NIF_ICON: 0x00000002,
|
||||
NIF_TIP: 0x00000004,
|
||||
NIF_STATE: 0x00000008,
|
||||
NIF_INFO: 0x00000010,
|
||||
NIF_GUID: 0x00000020,
|
||||
NIF_REALTIME: 0x00000040,
|
||||
NIF_SHOWTIP: 0x00000080,
|
||||
|
||||
NIM_ADD: 0x00000000,
|
||||
NIM_MODIFY: 0x00000001,
|
||||
NIM_DELETE: 0x00000002,
|
||||
NIM_SETFOCUS: 0x00000003,
|
||||
NIM_SETVERSION: 0x00000004
|
||||
};
|
||||
var NOTIFYICON_VERSION_4 = 4;
|
||||
var MessageTypes = { WM_APP: 0x8000, WM_USER: 0x0400 };
|
||||
function WindowsConsole()
|
||||
{
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
this._ObjectID = 'WindowsConsole';
|
||||
this._Marshal = require('_GenericMarshal');
|
||||
this._kernel32 = this._Marshal.CreateNativeProxy("kernel32.dll");
|
||||
this._user32 = this._Marshal.CreateNativeProxy("user32.dll");
|
||||
this._kernel32.CreateMethod("GetConsoleWindow");
|
||||
this._kernel32.CreateMethod('GetCurrentThread');
|
||||
this._user32.CreateMethod("ShowWindow");
|
||||
this._user32.CreateMethod("LoadImageA");
|
||||
this._user32.CreateMethod({ method: 'GetMessageA', threadDispatch: 1 });
|
||||
this._shell32 = this._Marshal.CreateNativeProxy('Shell32.dll');
|
||||
this._shell32.CreateMethod('Shell_NotifyIconA');
|
||||
|
||||
this._handle = this._kernel32.GetConsoleWindow();
|
||||
this.minimize = function () {
|
||||
this._user32.ShowWindow(this._handle, 6);
|
||||
};
|
||||
this.restore = function () {
|
||||
this._user32.ShowWindow(this._handle, 9);
|
||||
};
|
||||
this.hide = function () {
|
||||
this._user32.ShowWindow(this._handle, 0);
|
||||
};
|
||||
this.show = function () {
|
||||
this._user32.ShowWindow(this._handle, 5);
|
||||
};
|
||||
|
||||
|
||||
this._loadicon = function (imagePath) {
|
||||
var h = this._user32.LoadImageA(0, this._Marshal.CreateVariable(imagePath), 1, 0, 0, 0x00000010 | 0x00008000 | 0x00000040); // LR_LOADFROMFILE | LR_SHARED | LR_DEFAULTSIZE
|
||||
return (h);
|
||||
};
|
||||
|
||||
this.SetTrayIcon = function SetTrayIcon(options)
|
||||
{
|
||||
var data = this._Marshal.CreateVariable(this._Marshal.PointerSize == 4 ? 508 : 528);
|
||||
//console.log('struct size = ' + data._size);
|
||||
//console.log('TryIcon, WM_MESSAGE filter = ' + options.filter);
|
||||
data.toBuffer().writeUInt32LE(data._size, 0);
|
||||
|
||||
var trayType = TrayIconFlags.NIF_TIP | TrayIconFlags.NIF_MESSAGE
|
||||
options.filter = MessageTypes.WM_APP + 1;
|
||||
data.Deref(this._Marshal.PointerSize == 4 ? 16 : 24, 4).toBuffer().writeUInt32LE(options.filter);
|
||||
|
||||
if (!options.noBalloon) { trayType |= TrayIconFlags.NIF_INFO; }
|
||||
|
||||
if (options.icon)
|
||||
{
|
||||
trayType |= TrayIconFlags.NIF_ICON;
|
||||
var hIcon = data.Deref(this._Marshal.PointerSize == 4 ? 20 : 32, this._Marshal.PointerSize);
|
||||
options.icon.pointerBuffer().copy(hIcon.toBuffer());
|
||||
}
|
||||
|
||||
data.Deref(this._Marshal.PointerSize * 2, 4).toBuffer().writeUInt32LE(1);
|
||||
data.Deref(this._Marshal.PointerSize == 4 ? 12 : 20, 4).toBuffer().writeUInt32LE(trayType);
|
||||
data.Deref(this._Marshal.PointerSize == 4 ? 416 : 432, 4).toBuffer().writeUInt32LE(NOTIFYICON_VERSION_4);
|
||||
|
||||
var szTip = data.Deref(this._Marshal.PointerSize == 4 ? 24 : 40, 128);
|
||||
var szInfo = data.Deref(this._Marshal.PointerSize == 4 ? 160 : 176, 256);
|
||||
var szInfoTitle = data.Deref(this._Marshal.PointerSize == 4 ? 420 : 436, 64);
|
||||
|
||||
if (options.szTip) { Buffer.from(options.szTip).copy(szTip.toBuffer()); }
|
||||
if (options.szInfo) { Buffer.from(options.szInfo).copy(szInfo.toBuffer()); }
|
||||
if (options.szInfoTitle) { Buffer.from(options.szInfoTitle).copy(szInfoTitle.toBuffer()); }
|
||||
|
||||
|
||||
var MessagePump = require('win-messagepump');
|
||||
retVal = { _ObjectID: 'WindowsConsole.TrayIcon', MessagePump: new MessagePump(options) };
|
||||
var retValEvents = require('events').inherits(retVal);
|
||||
retValEvents.createEvent('ToastClicked');
|
||||
retValEvents.createEvent('IconHover');
|
||||
retValEvents.createEvent('ToastDismissed');
|
||||
retVal.Options = options;
|
||||
retVal.MessagePump.TrayIcon = retVal;
|
||||
retVal.MessagePump.NotifyData = data;
|
||||
retVal.MessagePump.WindowsConsole = this;
|
||||
retVal.MessagePump.on('exit', function onExit(code) { console.log('Pump Exited'); if (this.TrayIcon) { this.TrayIcon.remove(); } });
|
||||
retVal.MessagePump.on('hwnd', function onHwnd(h)
|
||||
{
|
||||
//console.log('Got HWND');
|
||||
options.hwnd = h;
|
||||
h.pointerBuffer().copy(this.NotifyData.Deref(this.WindowsConsole._Marshal.PointerSize, this.WindowsConsole._Marshal.PointerSize).toBuffer());
|
||||
|
||||
if(this.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_ADD, this.NotifyData).Val == 0)
|
||||
{
|
||||
// Something went wrong
|
||||
}
|
||||
});
|
||||
retVal.MessagePump.on('message', function onWindowsMessage(msg)
|
||||
{
|
||||
if(msg.message == this.TrayIcon.Options.filter)
|
||||
{
|
||||
var handled = false;
|
||||
if (msg.wparam == 1 && msg.lparam == 1029)
|
||||
{
|
||||
this.TrayIcon.emit('ToastClicked');
|
||||
handled = true;
|
||||
}
|
||||
if (msg.wparam == 1 && msg.lparam == 512)
|
||||
{
|
||||
this.TrayIcon.emit('IconHover');
|
||||
handled = true;
|
||||
}
|
||||
if (this.TrayIcon.Options.balloonOnly && msg.wparam == 1 && (msg.lparam == 1028 || msg.lparam == 1029))
|
||||
{
|
||||
this.TrayIcon.emit('ToastDismissed');
|
||||
this.TrayIcon.remove();
|
||||
handled = true;
|
||||
}
|
||||
if (!handled) { console.log(msg); }
|
||||
}
|
||||
});
|
||||
retVal.remove = function remove()
|
||||
{
|
||||
this.MessagePump.WindowsConsole._shell32.Shell_NotifyIconA(TrayIconFlags.NIM_DELETE, this.MessagePump.NotifyData);
|
||||
this.MessagePump.stop();
|
||||
delete this.MessagePump.TrayIcon;
|
||||
delete this.MessagePump;
|
||||
};
|
||||
return (retVal);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new WindowsConsole();
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
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 WH_CALLWNDPROC = 4;
|
||||
var WM_QUIT = 0x0012;
|
||||
|
||||
function WindowsMessagePump(options)
|
||||
{
|
||||
this._ObjectID = 'WindowsMessagePump';
|
||||
this._options = options;
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('hwnd');
|
||||
emitterUtils.createEvent('error');
|
||||
emitterUtils.createEvent('message');
|
||||
emitterUtils.createEvent('exit');
|
||||
|
||||
this._child = require('ScriptContainer').Create({ processIsolation: 0 });
|
||||
this._child.MessagePump = this;
|
||||
this._child.prependListener('~', function _childFinalizer() { this.MessagePump.emit('exit', 0); console.log('calling stop'); this.MessagePump.stop(); });
|
||||
this._child.once('exit', function onExit(code) { this.MessagePump.emit('exit', code); });
|
||||
this._child.once('ready', function onReady()
|
||||
{
|
||||
console.log('child ready');
|
||||
var execString =
|
||||
"var m = require('_GenericMarshal');\
|
||||
var h = null;\
|
||||
var k = m.CreateNativeProxy('Kernel32.dll');\
|
||||
k.CreateMethod('GetLastError');\
|
||||
k.CreateMethod('GetModuleHandleA');\
|
||||
var u = m.CreateNativeProxy('User32.dll');\
|
||||
u.CreateMethod('GetMessageA');\
|
||||
u.CreateMethod('CreateWindowExA');\
|
||||
u.CreateMethod('TranslateMessage');\
|
||||
u.CreateMethod('DispatchMessageA');\
|
||||
u.CreateMethod('RegisterClassExA');\
|
||||
u.CreateMethod('DefWindowProcA');\
|
||||
var wndclass = m.CreateVariable(m.PointerSize == 4 ? 48 : 80);\
|
||||
wndclass.hinstance = k.GetModuleHandleA(0);\
|
||||
wndclass.cname = m.CreateVariable('MainWWWClass');\
|
||||
wndclass.wndproc = m.GetGenericGlobalCallback(4);\
|
||||
wndclass.toBuffer().writeUInt32LE(wndclass._size);\
|
||||
wndclass.cname.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 40 : 64, m.PointerSize).toBuffer());\
|
||||
wndclass.wndproc.pointerBuffer().copy(wndclass.Deref(8, m.PointerSize).toBuffer());\
|
||||
wndclass.hinstance.pointerBuffer().copy(wndclass.Deref(m.PointerSize == 4 ? 20 : 24, m.PointerSize).toBuffer());\
|
||||
wndclass.wndproc.on('GlobalCallback', function onWndProc(xhwnd, xmsg, wparam, lparam)\
|
||||
{\
|
||||
if(h==null || h.Val == xhwnd.Val)\
|
||||
{\
|
||||
require('ScriptContainer').send({message: xmsg.Val, wparam: wparam.Val, lparam: lparam.Val});\
|
||||
var retVal = u.DefWindowProcA(xhwnd, xmsg, wparam, lparam);\
|
||||
return(retVal);\
|
||||
}\
|
||||
});\
|
||||
u.RegisterClassExA(wndclass);\
|
||||
h = u.CreateWindowExA(0x00000088, wndclass.cname, 0, 0x00800000, 0, 0, 100, 100, 0, 0, 0, 0);\
|
||||
if(h.Val == 0)\
|
||||
{\
|
||||
require('ScriptContainer').send({error: 'Error Creating Hidden Window'});\
|
||||
process.exit();\
|
||||
}\
|
||||
require('ScriptContainer').send({hwnd: h.pointerBuffer().toString('hex')});\
|
||||
require('ScriptContainer').on('data', function onData(jmsg)\
|
||||
{\
|
||||
if(jmsg.listen)\
|
||||
{\
|
||||
var msg = m.CreateVariable(m.PointerSize == 4 ? 28 : 48);\
|
||||
while(u.GetMessageA(msg, h, 0, 0).Val>0)\
|
||||
{\
|
||||
u.TranslateMessage(msg);\
|
||||
u.DispatchMessageA(msg);\
|
||||
}\
|
||||
process.exit();\
|
||||
}\
|
||||
});";
|
||||
|
||||
this.ExecuteString(execString);
|
||||
});
|
||||
this._child.on('data', function onChildData(msg)
|
||||
{
|
||||
if (msg.hwnd)
|
||||
{
|
||||
var m = require('_GenericMarshal');
|
||||
this._hwnd = m.CreatePointer(Buffer.from(msg.hwnd, 'hex'));
|
||||
this.MessagePump.emit('hwnd', this._hwnd);
|
||||
this.send({ listen: this.MessagePump._options.filter });
|
||||
}
|
||||
else if(msg.message)
|
||||
{
|
||||
this.MessagePump.emit('message', msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log('Received: ', msg);
|
||||
}
|
||||
});
|
||||
this.stop = function stop()
|
||||
{
|
||||
if(this._child && this._child._hwnd)
|
||||
{
|
||||
console.log('posting WM_QUIT');
|
||||
var marshal = require('_GenericMarshal');
|
||||
var User32 = marshal.CreateNativeProxy('User32.dll');
|
||||
User32.CreateMethod('PostMessageA');
|
||||
User32.PostMessageA(this._child._hwnd, WM_QUIT, 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = WindowsMessagePump;
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
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 KEY_QUERY_VALUE = 0x0001;
|
||||
var KEY_WRITE = 0x20006;
|
||||
|
||||
var KEY_DATA_TYPES =
|
||||
{
|
||||
REG_NONE: 0,
|
||||
REG_SZ: 1,
|
||||
REG_EXPAND_SZ: 2,
|
||||
REG_BINARY: 3,
|
||||
REG_DWORD: 4,
|
||||
REG_DWORD_BIG_ENDIAN: 5,
|
||||
REG_LINK: 6,
|
||||
REG_MULTI_SZ: 7,
|
||||
REG_RESOURCE_LIST: 8,
|
||||
REG_FULL_RESOURCE_DESCRIPTOR: 9,
|
||||
REG_RESOURCE_REQUIREMENTS_LIST: 10,
|
||||
REG_QWORD: 11
|
||||
};
|
||||
|
||||
function windows_registry()
|
||||
{
|
||||
this._ObjectId = 'windows_registry';
|
||||
this._marshal = require('_GenericMarshal');
|
||||
this._AdvApi = this._marshal.CreateNativeProxy('Advapi32.dll');
|
||||
this._AdvApi.CreateMethod('RegCreateKeyExA');
|
||||
this._AdvApi.CreateMethod('RegOpenKeyExA');
|
||||
this._AdvApi.CreateMethod('RegQueryValueExA');
|
||||
this._AdvApi.CreateMethod('RegCloseKey');
|
||||
this._AdvApi.CreateMethod('RegDeleteKeyA');
|
||||
this._AdvApi.CreateMethod('RegDeleteValueA');
|
||||
this._AdvApi.CreateMethod('RegSetValueExA');
|
||||
this.HKEY = { Root: Buffer.from('80000000', 'hex').swap32(), CurrentUser: Buffer.from('80000001', 'hex').swap32(), LocalMachine: Buffer.from('80000002', 'hex').swap32(), Users: Buffer.from('80000003', 'hex').swap32() };
|
||||
|
||||
this.QueryKey = function QueryKey(hkey, path, key)
|
||||
{
|
||||
var h = this._marshal.CreatePointer();
|
||||
var len = this._marshal.CreateVariable(4);
|
||||
var valType = this._marshal.CreateVariable(4);
|
||||
key = this._marshal.CreateVariable(key);
|
||||
var HK = this._marshal.CreatePointer(hkey);
|
||||
var retVal = null;
|
||||
|
||||
if (this._AdvApi.RegOpenKeyExA(HK, this._marshal.CreateVariable(path), 0, KEY_QUERY_VALUE, h).Val != 0)
|
||||
{
|
||||
throw ('Error Opening Registry Key: ' + path);
|
||||
}
|
||||
|
||||
if(this._AdvApi.RegQueryValueExA(h.Deref(), key, 0, 0, 0, len).Val == 0)
|
||||
{
|
||||
var data = this._marshal.CreateVariable(len.toBuffer().readUInt32LE());
|
||||
if (this._AdvApi.RegQueryValueExA(h.Deref(), key, 0, valType, data, len).Val == 0)
|
||||
{
|
||||
switch(valType.toBuffer().readUInt32LE())
|
||||
{
|
||||
case KEY_DATA_TYPES.REG_DWORD:
|
||||
retVal = data.toBuffer().readUInt32LE();
|
||||
break;
|
||||
case KEY_DATA_TYPES.REG_DWORD_BIG_ENDIAN:
|
||||
retVal = data.toBuffer().readUInt32BE();
|
||||
break;
|
||||
case KEY_DATA_TYPES.REG_SZ:
|
||||
retVal = data.String;
|
||||
break;
|
||||
case KEY_DATA_TYPES.REG_BINARY:
|
||||
default:
|
||||
retVal = data.toBuffer();
|
||||
retVal._data = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
throw ('Not Found');
|
||||
}
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
return (retVal);
|
||||
};
|
||||
this.WriteKey = function WriteKey(hkey, path, key, value)
|
||||
{
|
||||
var result;
|
||||
var h = this._marshal.CreatePointer();
|
||||
|
||||
if (this._AdvApi.RegCreateKeyExA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path), 0, 0, 0, KEY_WRITE, 0, h, 0).Val != 0)
|
||||
{
|
||||
throw ('Error Opening Registry Key: ' + path);
|
||||
}
|
||||
|
||||
var data;
|
||||
var dataType;
|
||||
|
||||
switch(typeof(value))
|
||||
{
|
||||
case 'boolean':
|
||||
dataType = KEY_DATA_TYPES.REG_DWORD;
|
||||
data = this._marshal.CreateVariable(4);
|
||||
data.toBuffer().writeUInt32LE(value ? 1 : 0);
|
||||
break;
|
||||
case 'number':
|
||||
dataType = KEY_DATA_TYPES.REG_DWORD;
|
||||
data = this._marshal.CreateVariable(4);
|
||||
data.toBuffer().writeUInt32LE(value);
|
||||
break;
|
||||
case 'string':
|
||||
dataType = KEY_DATA_TYPES.REG_SZ;
|
||||
data = this._marshal.CreateVariable(value);
|
||||
break;
|
||||
default:
|
||||
dataType = KEY_DATA_TYPES.REG_BINARY;
|
||||
data = this._marshal.CreateVariable(value.length);
|
||||
value.copy(data.toBuffer());
|
||||
break;
|
||||
}
|
||||
|
||||
if(this._AdvApi.RegSetValueExA(h.Deref(), this._marshal.CreateVariable(key), 0, dataType, data, data._size).Val != 0)
|
||||
{
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
throw ('Error writing reg key: ' + key);
|
||||
}
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
};
|
||||
this.DeleteKey = function DeleteKey(hkey, path, key)
|
||||
{
|
||||
if(!key)
|
||||
{
|
||||
if(this._AdvApi.RegDeleteKeyA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path)).Val != 0)
|
||||
{
|
||||
throw ('Error Deleting Key: ' + path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var h = this._marshal.CreatePointer();
|
||||
var result;
|
||||
if (this._AdvApi.RegOpenKeyExA(this._marshal.CreatePointer(hkey), this._marshal.CreateVariable(path), 0, KEY_QUERY_VALUE | KEY_WRITE, h).Val != 0)
|
||||
{
|
||||
throw ('Error Opening Registry Key: ' + path);
|
||||
}
|
||||
if ((result = this._AdvApi.RegDeleteValueA(h.Deref(), this._marshal.CreateVariable(key)).Val) != 0)
|
||||
{
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
throw ('Error[' + result + '] Deleting Key: ' + path + '.' + key);
|
||||
}
|
||||
this._AdvApi.RegCloseKey(h.Deref());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = new windows_registry();
|
||||
|
|
@ -75,7 +75,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
|
|||
func(certs);
|
||||
|
||||
// Check if the Let's Encrypt certificate needs to be renewed.
|
||||
setTimeout(obj.checkRenewCertificate, 300000); // Check in 5 minutes.
|
||||
setTimeout(obj.checkRenewCertificate, 60000); // Check in 1 minute.
|
||||
setInterval(obj.checkRenewCertificate, 86400000); // Check again in 24 hours and every 24 hours.
|
||||
return;
|
||||
} else {
|
||||
|
@ -111,7 +111,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
|
|||
if (obj.leResults == null) { return; }
|
||||
// TODO: Only renew on one of the peers if multi-peers are active.
|
||||
// Check if we need to renew the certificate
|
||||
obj.le.renew({ duplicate: false }, obj.leResults).then(function (xresults) {
|
||||
obj.le.renew({ duplicate: false, domains: obj.leDomains, email: obj.parent.config.letsencrypt.email }, obj.leResults).then(function (xresults) {
|
||||
obj.parent.performServerCertUpdate(); // Reset the server, TODO: Reset all peers
|
||||
}, function (err) { }); // If we can't renew, ignore.
|
||||
}
|
||||
|
|
34
meshuser.js
34
meshuser.js
|
@ -873,6 +873,40 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'toast':
|
||||
{
|
||||
if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
|
||||
if (obj.common.validateString(command.title, 1, 512) == false) break; // Check title
|
||||
if (obj.common.validateString(command.msg, 1, 4096) == false) break; // Check message
|
||||
for (var i in command.nodeids) {
|
||||
var nodeid = command.nodeids[i], powerActions = 0;
|
||||
if (obj.common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
|
||||
if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
|
||||
// Get the device
|
||||
obj.db.Get(nodeid, function (err, nodes) {
|
||||
if (nodes.length != 1) return;
|
||||
var node = nodes[0];
|
||||
|
||||
// Get the mesh for this device
|
||||
var mesh = obj.parent.meshes[node.meshid];
|
||||
if (mesh) {
|
||||
|
||||
// Check if this user has rights to do this
|
||||
if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
|
||||
|
||||
// Get this device
|
||||
var agent = obj.parent.wsagents[node._id];
|
||||
if (agent != null) {
|
||||
// Send the power command
|
||||
agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg }));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'getnetworkinfo':
|
||||
{
|
||||
// Argument validation
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.6-q",
|
||||
"version": "0.1.6-s",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
|
@ -81,9 +81,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
|||
}
|
||||
}
|
||||
|
||||
// Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
|
||||
obj.xxCloseWebRTC = function () { obj.Stop(); }
|
||||
|
||||
obj.xxOnMessage = function (e) {
|
||||
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
|
||||
//console.log('Recv', e.data, obj.State);
|
||||
|
@ -111,7 +108,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
|||
}
|
||||
obj.webrtc.oniceconnectionstatechange = function () {
|
||||
if (obj.webrtc != null) {
|
||||
if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
|
||||
if (obj.webrtc.iceConnectionState == 'disconnected') { obj.Stop(); }
|
||||
else if (obj.webrtc.iceConnectionState == 'failed') { obj.xxCloseWebRTC(); }
|
||||
}
|
||||
}
|
||||
obj.webrtc.createOffer(function (offer) {
|
||||
|
@ -206,13 +204,18 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
|||
if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
|
||||
}
|
||||
|
||||
obj.Stop = function (x) {
|
||||
if (obj.debugmode == 1) { console.log('stop', x); }
|
||||
|
||||
// Close WebRTC
|
||||
// Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
|
||||
obj.xxCloseWebRTC = function () {
|
||||
if (obj.webchannel != null) { try { obj.webchannel.close(); } catch (e) { } obj.webchannel = null; }
|
||||
if (obj.webrtc != null) { try { obj.webrtc.close(); } catch (e) { } obj.webrtc = null; }
|
||||
obj.webRtcActive = false;
|
||||
}
|
||||
|
||||
obj.Stop = function (x) {
|
||||
if (obj.debugmode == 1) { console.log('stop', x); }
|
||||
|
||||
// Clean up WebRTC
|
||||
obj.xxCloseWebRTC();
|
||||
|
||||
//obj.debug("Agent Redir Socket Stopped");
|
||||
obj.connectstate = -1;
|
||||
|
|
|
@ -572,6 +572,7 @@
|
|||
<div id=p16events style="max-height:600px;overflow-y:scroll"></div>
|
||||
</div>
|
||||
<div id=p20 style=display:none>
|
||||
<img id=MainMeshImage src="images/mesh-200.png" style=border-width:0px;height:200px;width:200px;float:right>
|
||||
<h1><span id=p20meshName></span> - General</h1>
|
||||
<p id=p20info></p>
|
||||
</div>
|
||||
|
@ -2848,6 +2849,7 @@
|
|||
// Show action button, only show if we have permissions 4, 8, 64
|
||||
if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
|
||||
x += '<input type=button value=Notes title="View notes about this device" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
|
||||
if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="Display a text message of the remote device" onclick=deviceToastFunction() />'; }
|
||||
QH('p10html', x);
|
||||
|
||||
// Show node last 7 days timeline
|
||||
|
@ -2939,7 +2941,17 @@
|
|||
|
||||
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
|
||||
|
||||
function deviceToastFunction() {
|
||||
if (xxdialogMode) return;
|
||||
setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
|
||||
}
|
||||
|
||||
function deviceToastFunctionEx() {
|
||||
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
|
||||
}
|
||||
|
||||
function deviceActionFunction() {
|
||||
if (xxdialogMode) return;
|
||||
var meshrights = meshes[currentNode.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
|
||||
var x = "Select an operation to perform on this device.<br /><br />";
|
||||
var y = '<select id=d2deviceop style=float:right;width:250px>';
|
||||
|
@ -4542,7 +4554,7 @@
|
|||
|
||||
x += '<br><input type=button value=Notes title="View notes about this mesh" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
|
||||
|
||||
x += '<br><br>';
|
||||
x += '<br style=clear:both><br>';
|
||||
var currentMeshLinks = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
|
||||
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a onclick=p20showAddMeshUserDialog() style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Add User</a>'; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue