mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	First pass at adding RDP clipboard support, #3810.
This commit is contained in:
		
							parent
							
								
									97ff7a1669
								
							
						
					
					
						commit
						af052ddfe7
					
				
					 10 changed files with 446 additions and 21 deletions
				
			
		| 
						 | 
					@ -198,6 +198,7 @@
 | 
				
			||||||
    <Compile Include="rdp\protocol\index.js" />
 | 
					    <Compile Include="rdp\protocol\index.js" />
 | 
				
			||||||
    <Compile Include="rdp\protocol\nla.js" />
 | 
					    <Compile Include="rdp\protocol\nla.js" />
 | 
				
			||||||
    <Compile Include="rdp\protocol\pdu\caps.js" />
 | 
					    <Compile Include="rdp\protocol\pdu\caps.js" />
 | 
				
			||||||
 | 
					    <Compile Include="rdp\protocol\pdu\cliprdr.js" />
 | 
				
			||||||
    <Compile Include="rdp\protocol\pdu\data.js" />
 | 
					    <Compile Include="rdp\protocol\pdu\data.js" />
 | 
				
			||||||
    <Compile Include="rdp\protocol\pdu\global.js" />
 | 
					    <Compile Include="rdp\protocol\pdu\global.js" />
 | 
				
			||||||
    <Compile Include="rdp\protocol\pdu\index.js" />
 | 
					    <Compile Include="rdp\protocol\pdu\index.js" />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -152,7 +152,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
 | 
				
			||||||
                        obj.wsClient._socket.pause();
 | 
					                        obj.wsClient._socket.pause();
 | 
				
			||||||
                        try {
 | 
					                        try {
 | 
				
			||||||
                            obj.relaySocket.write(data, function () {
 | 
					                            obj.relaySocket.write(data, function () {
 | 
				
			||||||
                                try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); }
 | 
					                                if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } }
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                        } catch (ex) { console.log(ex); obj.close(); }
 | 
					                        } catch (ex) { console.log(ex); obj.close(); }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -201,6 +201,10 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
 | 
				
			||||||
                try { ws.send(bitmap.data); } catch (ex) { } // Send the bitmap data as binary
 | 
					                try { ws.send(bitmap.data); } catch (ex) { } // Send the bitmap data as binary
 | 
				
			||||||
                delete bitmap.data;
 | 
					                delete bitmap.data;
 | 
				
			||||||
                send(['rdp-bitmap', bitmap]); // Send the bitmap metadata seperately, without bitmap data.
 | 
					                send(['rdp-bitmap', bitmap]); // Send the bitmap metadata seperately, without bitmap data.
 | 
				
			||||||
 | 
					            }).on('clipboard', function (content) {
 | 
				
			||||||
 | 
					                // Clipboard data changed
 | 
				
			||||||
 | 
					                console.log('RDP clipboard recv', content);
 | 
				
			||||||
 | 
					                send(['rdp-clipboard', content]);
 | 
				
			||||||
            }).on('close', function () {
 | 
					            }).on('close', function () {
 | 
				
			||||||
                send(['rdp-close']);
 | 
					                send(['rdp-close']);
 | 
				
			||||||
            }).on('error', function (err) {
 | 
					            }).on('error', function (err) {
 | 
				
			||||||
| 
						 | 
					@ -317,6 +321,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case 'mouse': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendPointerEvent(msg[1], msg[2], msg[3], msg[4]); } break; }
 | 
					                case 'mouse': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendPointerEvent(msg[1], msg[2], msg[3], msg[4]); } break; }
 | 
				
			||||||
                case 'wheel': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendWheelEvent(msg[1], msg[2], msg[3], msg[4]); } break; }
 | 
					                case 'wheel': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendWheelEvent(msg[1], msg[2], msg[3], msg[4]); } break; }
 | 
				
			||||||
 | 
					                case 'clipboard': { rdpClient.setClipboardData(msg[1]); break; }
 | 
				
			||||||
                case 'scancode': {
 | 
					                case 'scancode': {
 | 
				
			||||||
                    if (obj.limitedinput == true) { // Limit keyboard input
 | 
					                    if (obj.limitedinput == true) { // Limit keyboard input
 | 
				
			||||||
                        var ok = false, k = msg[1];
 | 
					                        var ok = false, k = msg[1];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,6 +83,10 @@ var CreateRDPDesktop = function (canvasid) {
 | 
				
			||||||
                        obj.Stop();
 | 
					                        obj.Stop();
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    case 'rdp-clipboard': {
 | 
				
			||||||
 | 
					                        console.log('clipboard', msg[1]);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    case 'ping': { obj.socket.send('["pong"]'); break; }
 | 
					                    case 'ping': { obj.socket.send('["pong"]'); break; }
 | 
				
			||||||
                    case 'pong': { break; }
 | 
					                    case 'pong': { break; }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -100,6 +104,14 @@ var CreateRDPDesktop = function (canvasid) {
 | 
				
			||||||
        if (obj.socket) { obj.socket.close(); }
 | 
					        if (obj.socket) { obj.socket.close(); }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    obj.m.setClipboard = function (content) {
 | 
				
			||||||
 | 
					        console.log('s1');
 | 
				
			||||||
 | 
					        if (obj.socket) {
 | 
				
			||||||
 | 
					            console.log('s2', content);
 | 
				
			||||||
 | 
					            obj.socket.send(JSON.stringify(['clipboard', content]));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function changeState(newstate) {
 | 
					    function changeState(newstate) {
 | 
				
			||||||
        if (obj.State == newstate) return;
 | 
					        if (obj.State == newstate) return;
 | 
				
			||||||
        obj.State = newstate;
 | 
					        obj.State = newstate;
 | 
				
			||||||
| 
						 | 
					@ -153,14 +165,14 @@ var CreateRDPDesktop = function (canvasid) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    obj.m.handleKeyUp = function (e) {
 | 
					    obj.m.handleKeyUp = function (e) {
 | 
				
			||||||
        if (!obj.socket || (obj.State != 3)) return;
 | 
					        if (!obj.socket || (obj.State != 3)) return;
 | 
				
			||||||
        console.log('handleKeyUp', Mstsc.scancode(e));
 | 
					        //console.log('handleKeyUp', Mstsc.scancode(e));
 | 
				
			||||||
        obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), false]));
 | 
					        obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), false]));
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    obj.m.handleKeyDown = function (e) {
 | 
					    obj.m.handleKeyDown = function (e) {
 | 
				
			||||||
        if (!obj.socket || (obj.State != 3)) return;
 | 
					        if (!obj.socket || (obj.State != 3)) return;
 | 
				
			||||||
        console.log('handleKeyDown', Mstsc.scancode(e));
 | 
					        //console.log('handleKeyDown', Mstsc.scancode(e));
 | 
				
			||||||
        obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), true]));
 | 
					        obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), true]));
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										327
									
								
								rdp/protocol/pdu/cliprdr.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								rdp/protocol/pdu/cliprdr.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,327 @@
 | 
				
			||||||
 | 
					const type = require('../../core').type;
 | 
				
			||||||
 | 
					const EventEmitter = require('events').EventEmitter;
 | 
				
			||||||
 | 
					const caps = require('./caps');
 | 
				
			||||||
 | 
					const log = require('../../core').log;
 | 
				
			||||||
 | 
					const data = require('./data');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Cliprdr channel for all clipboard
 | 
				
			||||||
 | 
					 * capabilities exchange
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class Cliprdr extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(transport) {
 | 
				
			||||||
 | 
					    super();
 | 
				
			||||||
 | 
					    this.transport = transport;
 | 
				
			||||||
 | 
					    // must be init via connect event
 | 
				
			||||||
 | 
					    this.userId = 0;
 | 
				
			||||||
 | 
					    this.serverCapabilities = [];
 | 
				
			||||||
 | 
					    this.clientCapabilities = [];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Client side of Cliprdr channel automata
 | 
				
			||||||
 | 
					 * @param transport
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class Client extends Cliprdr {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(transport, fastPathTransport) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    super(transport, fastPathTransport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.transport.once('connect', (gccCore, userId, channelId) => {
 | 
				
			||||||
 | 
					      this.connect(gccCore, userId, channelId);
 | 
				
			||||||
 | 
					    }).on('close', () => {
 | 
				
			||||||
 | 
					      this.emit('close');
 | 
				
			||||||
 | 
					    }).on('error', (err) => {
 | 
				
			||||||
 | 
					      this.emit('error', err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.content = '';
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * connect function
 | 
				
			||||||
 | 
					   * @param gccCore {type.Component(clientCoreData)}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  connect(gccCore, userId, channelId) {
 | 
				
			||||||
 | 
					    this.gccCore = gccCore;
 | 
				
			||||||
 | 
					    this.userId = userId;
 | 
				
			||||||
 | 
					    this.channelId = channelId;
 | 
				
			||||||
 | 
					    this.transport.once('cliprdr', (s) => {
 | 
				
			||||||
 | 
					      this.recv(s);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  send(message) {
 | 
				
			||||||
 | 
					    this.transport.send('cliprdr', new type.Component([
 | 
				
			||||||
 | 
					      // Channel PDU Header
 | 
				
			||||||
 | 
					      new type.UInt32Le(message.size()),
 | 
				
			||||||
 | 
					      // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL
 | 
				
			||||||
 | 
					      new type.UInt32Le(0x13),
 | 
				
			||||||
 | 
					      message
 | 
				
			||||||
 | 
					    ]));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recv(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (pdu.obj.header.obj.msgType.value) {
 | 
				
			||||||
 | 
					      case type.CB_MONITOR_READY:
 | 
				
			||||||
 | 
					        this.recvMonitorReadyPDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_FORMAT_LIST:
 | 
				
			||||||
 | 
					        this.recvFormatListPDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_FORMAT_LIST_RESPONSE:
 | 
				
			||||||
 | 
					        this.recvFormatListResponsePDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_FORMAT_DATA_REQUEST:
 | 
				
			||||||
 | 
					        this.recvFormatDataRequestPDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_FORMAT_DATA_RESPONSE:
 | 
				
			||||||
 | 
					        this.recvFormatDataResponsePDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_TEMP_DIRECTORY:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_CLIP_CAPS:
 | 
				
			||||||
 | 
					        this.recvClipboardCapsPDU(s);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case type.CB_FILECONTENTS_REQUEST:
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.transport.once('cliprdr', (s) => {
 | 
				
			||||||
 | 
					      this.recv(s);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Receive capabilities from server
 | 
				
			||||||
 | 
					   * @param s {type.Stream}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvClipboardCapsPDU(s) {
 | 
				
			||||||
 | 
					    // Start at 18
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    // console.log('recvClipboardCapsPDU', s);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Receive monitor ready from server
 | 
				
			||||||
 | 
					   * @param s {type.Stream}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvMonitorReadyPDU(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    // console.log('recvMonitorReadyPDU', s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.sendClipboardCapsPDU();
 | 
				
			||||||
 | 
					    // this.sendClientTemporaryDirectoryPDU();
 | 
				
			||||||
 | 
					    this.sendFormatListPDU();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send clipboard capabilities PDU
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  sendClipboardCapsPDU() {
 | 
				
			||||||
 | 
					    this.send(new type.Component({
 | 
				
			||||||
 | 
					      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS),
 | 
				
			||||||
 | 
					      msgFlags: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					      dataLen: new type.UInt32Le(0x10),
 | 
				
			||||||
 | 
					      cCapabilitiesSets: new type.UInt16Le(0x01),
 | 
				
			||||||
 | 
					      pad1: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					      capabilitySetType: new type.UInt16Le(0x01),
 | 
				
			||||||
 | 
					      lengthCapability: new type.UInt16Le(0x0c),
 | 
				
			||||||
 | 
					      version: new type.UInt32Le(0x02),
 | 
				
			||||||
 | 
					      capabilityFlags: new type.UInt32Le(0x02)
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send client temporary directory PDU
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  sendClientTemporaryDirectoryPDU(path = '') {
 | 
				
			||||||
 | 
					    // TODO
 | 
				
			||||||
 | 
					    this.send(new type.Component({
 | 
				
			||||||
 | 
					      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY),
 | 
				
			||||||
 | 
					      msgFlags: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					      dataLen: new type.UInt32Le(0x0208),
 | 
				
			||||||
 | 
					      wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength : new type.CallableValue(520)})
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send format list PDU
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  sendFormatListPDU() {
 | 
				
			||||||
 | 
					    this.send(new type.Component({
 | 
				
			||||||
 | 
					      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST),
 | 
				
			||||||
 | 
					      msgFlags: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      dataLen: new type.UInt32Le(0x24),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      formatId6: new type.UInt32Le(0xc004),
 | 
				
			||||||
 | 
					      formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      formatId8: new type.UInt32Le(0x0d),
 | 
				
			||||||
 | 
					      formatName8: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      formatId9: new type.UInt32Le(0x10),
 | 
				
			||||||
 | 
					      formatName9: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      formatId0: new type.UInt32Le(0x01),
 | 
				
			||||||
 | 
					      formatName0: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // dataLen: new type.UInt32Le(0xe0),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId1: new type.UInt32Le(0xc08a),
 | 
				
			||||||
 | 
					      // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId2: new type.UInt32Le(0xc145),
 | 
				
			||||||
 | 
					      // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId3: new type.UInt32Le(0xc143),
 | 
				
			||||||
 | 
					      // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId4: new type.UInt32Le(0x01),
 | 
				
			||||||
 | 
					      // formatName4: new type.BinaryString(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      formatId5: new type.UInt32Le(0x07),
 | 
				
			||||||
 | 
					      formatName5: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId6: new type.UInt32Le(0xc004),
 | 
				
			||||||
 | 
					      // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // formatId7: new type.UInt32Le(0xc00e),
 | 
				
			||||||
 | 
					      // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId8: new type.UInt32Le(0x03),
 | 
				
			||||||
 | 
					      // formatName8: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId9: new type.UInt32Le(0x10),
 | 
				
			||||||
 | 
					      // formatName9: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // formatId0: new type.UInt32Le(0x07),
 | 
				
			||||||
 | 
					      // formatName0: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Recvie format list PDU from server
 | 
				
			||||||
 | 
					   * @param {type.Stream} s 
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvFormatListPDU(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    // console.log('recvFormatListPDU', s);
 | 
				
			||||||
 | 
					    this.sendFormatListResponsePDU();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send format list reesponse
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					   sendFormatListResponsePDU() {
 | 
				
			||||||
 | 
					     this.send(new type.Component({
 | 
				
			||||||
 | 
					        msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE),
 | 
				
			||||||
 | 
					        msgFlags: new type.UInt16Le(0x01),
 | 
				
			||||||
 | 
					        dataLen: new type.UInt32Le(0x00),
 | 
				
			||||||
 | 
					     }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     this.sendFormatDataRequestPDU();
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Receive format list response from server
 | 
				
			||||||
 | 
					   * @param s {type.Stream}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvFormatListResponsePDU(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    // console.log('recvFormatListResponsePDU', s);
 | 
				
			||||||
 | 
					    // this.sendFormatDataRequestPDU();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send format data request PDU
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  sendFormatDataRequestPDU(formartId = 0x0d) {
 | 
				
			||||||
 | 
					    this.send(new type.Component({
 | 
				
			||||||
 | 
					      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST),
 | 
				
			||||||
 | 
					      msgFlags: new type.UInt16Le(0x00),
 | 
				
			||||||
 | 
					      dataLen: new type.UInt32Le(0x04),
 | 
				
			||||||
 | 
					      requestedFormatId: new type.UInt32Le(formartId),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Receive format data request PDU from server
 | 
				
			||||||
 | 
					   * @param s {type.Stream}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvFormatDataRequestPDU(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    // console.log('recvFormatDataRequestPDU', s);
 | 
				
			||||||
 | 
					    this.sendFormatDataResponsePDU();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Send format data reesponse PDU
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  sendFormatDataResponsePDU() {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const bufs = Buffer.from(this.content + '\x00' , 'ucs2');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.send(new type.Component({
 | 
				
			||||||
 | 
					      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE),
 | 
				
			||||||
 | 
					      msgFlags: new type.UInt16Le(0x01),
 | 
				
			||||||
 | 
					      dataLen: new type.UInt32Le(bufs.length),
 | 
				
			||||||
 | 
					      requestedFormatData: new type.BinaryString(bufs, { readLength : new type.CallableValue(bufs.length)})
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Receive format data response PDU from server
 | 
				
			||||||
 | 
					   * @param s {type.Stream}
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  recvFormatDataResponsePDU(s) {
 | 
				
			||||||
 | 
					    s.offset = 18;
 | 
				
			||||||
 | 
					    // const pdu = data.clipPDU().read(s);
 | 
				
			||||||
 | 
					    const str = s.buffer.toString('ucs2', 26, s.buffer.length-2);
 | 
				
			||||||
 | 
					    // console.log('recvFormatDataResponsePDU', str);
 | 
				
			||||||
 | 
					    this.content = str;
 | 
				
			||||||
 | 
					    this.emit('clipboard', str)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// =====================================================================================
 | 
				
			||||||
 | 
					  setClipboardData(content) {
 | 
				
			||||||
 | 
					    this.content = content;
 | 
				
			||||||
 | 
					    this.sendFormatListPDU();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1040,6 +1040,36 @@ function pdu(userId, pduMessage, opt) {
 | 
				
			||||||
	return new type.Component(self, opt);
 | 
						return new type.Component(self, opt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ClipPDUMsgType = {
 | 
				
			||||||
 | 
					    CB_MONITOR_READY: 0x0001,
 | 
				
			||||||
 | 
					    CB_FORMAT_LIST: 0x0002,
 | 
				
			||||||
 | 
					    CB_FORMAT_LIST_RESPONSE: 0x0003,
 | 
				
			||||||
 | 
					    CB_FORMAT_DATA_REQUEST: 0x0004,
 | 
				
			||||||
 | 
					    CB_FORMAT_DATA_RESPONSE: 0x0005,
 | 
				
			||||||
 | 
					    CB_TEMP_DIRECTORY: 0x0006,
 | 
				
			||||||
 | 
					    CB_CLIP_CAPS: 0x0007,
 | 
				
			||||||
 | 
					    CB_FILECONTENTS_REQUEST: 0x0008
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @returns {type.Component}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function clipPDU() {
 | 
				
			||||||
 | 
					    const self = {
 | 
				
			||||||
 | 
					        header: new type.Factory(function (s) {
 | 
				
			||||||
 | 
					            self.header = new type.Component({
 | 
				
			||||||
 | 
					                msgType: new type.UInt16Le().read(s),
 | 
				
			||||||
 | 
					                msgFlags: new type.UInt16Le().read(s),
 | 
				
			||||||
 | 
					                dataLen: new type.UInt32Le().read(s)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return new type.Component(self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
 | 
					 * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
 | 
				
			||||||
 * @param opt {object} type option
 | 
					 * @param opt {object} type option
 | 
				
			||||||
| 
						 | 
					@ -1147,5 +1177,7 @@ module.exports = {
 | 
				
			||||||
		updateDataPDU : updateDataPDU,
 | 
							updateDataPDU : updateDataPDU,
 | 
				
			||||||
		dataPDU : dataPDU,
 | 
							dataPDU : dataPDU,
 | 
				
			||||||
		fastPathBitmapUpdateDataPDU : fastPathBitmapUpdateDataPDU,
 | 
							fastPathBitmapUpdateDataPDU : fastPathBitmapUpdateDataPDU,
 | 
				
			||||||
		fastPathUpdatePDU : fastPathUpdatePDU
 | 
					        fastPathUpdatePDU: fastPathUpdatePDU,
 | 
				
			||||||
 | 
					        clipPDU: clipPDU,
 | 
				
			||||||
 | 
					        ClipPDUMsgType: ClipPDUMsgType
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -21,10 +21,12 @@ var lic = require('./lic');
 | 
				
			||||||
var sec = require('./sec');
 | 
					var sec = require('./sec');
 | 
				
			||||||
var global = require('./global');
 | 
					var global = require('./global');
 | 
				
			||||||
var data = require('./data');
 | 
					var data = require('./data');
 | 
				
			||||||
 | 
					var cliprdr = require('./cliprdr');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
	lic: lic,
 | 
						lic: lic,
 | 
				
			||||||
	sec: sec,
 | 
						sec: sec,
 | 
				
			||||||
	global: global,
 | 
						global: global,
 | 
				
			||||||
	data : data
 | 
					    data: data,
 | 
				
			||||||
 | 
					    cliprdr: cliprdr
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,6 +87,7 @@ function RdpClient(config) {
 | 
				
			||||||
    this.x224 = new x224.Client(this.tpkt, config);
 | 
					    this.x224 = new x224.Client(this.tpkt, config);
 | 
				
			||||||
    this.mcs = new t125.mcs.Client(this.x224);
 | 
					    this.mcs = new t125.mcs.Client(this.x224);
 | 
				
			||||||
    this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
 | 
					    this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
 | 
				
			||||||
 | 
					    this.cliprdr = new pdu.cliprdr.Client(this.mcs);
 | 
				
			||||||
    this.global = new pdu.global.Client(this.sec, this.sec);
 | 
					    this.global = new pdu.global.Client(this.sec, this.sec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // config log level
 | 
					    // config log level
 | 
				
			||||||
| 
						 | 
					@ -145,6 +146,9 @@ function RdpClient(config) {
 | 
				
			||||||
            this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
 | 
					            this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.cliprdr.on('clipboard', (content) => {
 | 
				
			||||||
 | 
					        this.emit('clipboard', content)
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //bind all events
 | 
					    //bind all events
 | 
				
			||||||
    var self = this;
 | 
					    var self = this;
 | 
				
			||||||
| 
						 | 
					@ -328,6 +332,14 @@ RdpClient.prototype.sendWheelEvent = function (x, y, step, isNegative, isHorizon
 | 
				
			||||||
    this.global.sendInputEvents([event]);
 | 
					    this.global.sendInputEvents([event]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clipboard event
 | 
				
			||||||
 | 
					 * @param data {String} content for clipboard
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					RdpClient.prototype.setClipboardData = function (content) {
 | 
				
			||||||
 | 
					    this.cliprdr.setClipboardData(content);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function createClient(config) {
 | 
					function createClient(config) {
 | 
				
			||||||
    return new RdpClient(config);
 | 
					    return new RdpClient(config);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ var error = require('../../core').error;
 | 
				
			||||||
var gcc = require('./gcc');
 | 
					var gcc = require('./gcc');
 | 
				
			||||||
var per = require('./per');
 | 
					var per = require('./per');
 | 
				
			||||||
var asn1 = require('../../asn1');
 | 
					var asn1 = require('../../asn1');
 | 
				
			||||||
 | 
					var cliprdr = require('../pdu/cliprdr');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Message = {
 | 
					var Message = {
 | 
				
			||||||
	MCS_TYPE_CONNECT_INITIAL : 0x65,
 | 
						MCS_TYPE_CONNECT_INITIAL : 0x65,
 | 
				
			||||||
| 
						 | 
					@ -44,9 +45,32 @@ var DomainMCSPDU = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Channel = {
 | 
					var Channel = {
 | 
				
			||||||
    MCS_GLOBAL_CHANNEL: 1003,
 | 
					    MCS_GLOBAL_CHANNEL: 1003,
 | 
				
			||||||
    MCS_USERCHANNEL_BASE : 1001
 | 
					    MCS_USERCHANNEL_BASE: 1001,
 | 
				
			||||||
 | 
					    MCS_CLIPRDR_CHANNEL: 1005
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Channel Definde
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const RdpdrChannelDef = new type.Component({
 | 
				
			||||||
 | 
					    name: new type.BinaryString(Buffer.from('rdpdr' + '\x00\x00\x00', 'binary'), { readLength: new type.CallableValue(8) }),
 | 
				
			||||||
 | 
					    options: new type.UInt32Le(0x80800000)
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RdpsndChannelDef = new type.Component({
 | 
				
			||||||
 | 
					    name: new type.BinaryString(Buffer.from('rdpsnd' + '\x00\x00', 'binary'), { readLength: new type.CallableValue(8) }),
 | 
				
			||||||
 | 
					    options: new type.UInt32Le(0xc0000000)
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CliprdrChannelDef = new type.Component({
 | 
				
			||||||
 | 
					    name: new type.BinaryString(Buffer.from('cliprdr' + '\x00', 'binary'), { readLength: new type.CallableValue(8) }),
 | 
				
			||||||
 | 
					    // CHANNEL_OPTION_INITIALIZED |
 | 
				
			||||||
 | 
					    // CHANNEL_OPTION_ENCRYPT_RDP |
 | 
				
			||||||
 | 
					    // CHANNEL_OPTION_COMPRESS_RDP |
 | 
				
			||||||
 | 
					    // CHANNEL_OPTION_SHOW_PROTOCOL
 | 
				
			||||||
 | 
					    options: new type.UInt32Le(0xc0a00000)
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 | 
					 * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 | 
				
			||||||
 * @returns {asn1.univ.Sequence}
 | 
					 * @returns {asn1.univ.Sequence}
 | 
				
			||||||
| 
						 | 
					@ -126,7 +150,10 @@ function MCS(transport, recvOpCode, sendOpCode) {
 | 
				
			||||||
	this.transport = transport;
 | 
						this.transport = transport;
 | 
				
			||||||
	this.recvOpCode = recvOpCode;
 | 
						this.recvOpCode = recvOpCode;
 | 
				
			||||||
	this.sendOpCode = sendOpCode;
 | 
						this.sendOpCode = sendOpCode;
 | 
				
			||||||
	this.channels = [{id : Channel.MCS_GLOBAL_CHANNEL, name : 'global'}];
 | 
					    this.channels = [
 | 
				
			||||||
 | 
					        { id: Channel.MCS_GLOBAL_CHANNEL, name: 'global' },
 | 
				
			||||||
 | 
					        { id: Channel.MCS_CLIPRDR_CHANNEL, name: 'cliprdr' }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
	this.channels.find = function(callback) {
 | 
						this.channels.find = function(callback) {
 | 
				
			||||||
		for(var i in this) {
 | 
							for(var i in this) {
 | 
				
			||||||
			if(callback(this[i])) return this[i];
 | 
								if(callback(this[i])) return this[i];
 | 
				
			||||||
| 
						 | 
					@ -208,7 +235,8 @@ function Client(transport) {
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	// init gcc information
 | 
						// init gcc information
 | 
				
			||||||
    this.clientCoreData = gcc.clientCoreData();
 | 
					    this.clientCoreData = gcc.clientCoreData();
 | 
				
			||||||
	this.clientNetworkData = gcc.clientNetworkData(new type.Component([]));
 | 
					    // cliprdr channel
 | 
				
			||||||
 | 
					    this.clientNetworkData = gcc.clientNetworkData(new type.Component([RdpdrChannelDef, CliprdrChannelDef, RdpsndChannelDef]));
 | 
				
			||||||
	this.clientSecurityData = gcc.clientSecurityData();
 | 
						this.clientSecurityData = gcc.clientSecurityData();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	// must be readed from protocol
 | 
						// must be readed from protocol
 | 
				
			||||||
| 
						 | 
					@ -317,7 +345,8 @@ Client.prototype.recvChannelJoinConfirm = function(s) {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    var channelId = per.readInteger16(s);
 | 
					    var channelId = per.readInteger16(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
 | 
					    //if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
 | 
				
			||||||
 | 
					    if ((confirm !== 0) && (channelId === Channel.MCS_CLIPRDR_CHANNEL || channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
 | 
				
			||||||
    	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL');
 | 
					    	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@
 | 
				
			||||||
      } else if (message.length === undefined) {
 | 
					      } else if (message.length === undefined) {
 | 
				
			||||||
        return method(message);
 | 
					        return method(message);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return crypto.createHash('md4').update(new Buffer(message)).digest('hex');
 | 
					      return crypto.createHash('md4').update(Buffer.from(message)).digest('hex');
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return nodeMethod;
 | 
					    return nodeMethod;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7566,7 +7566,7 @@
 | 
				
			||||||
            if ((navigator.clipboard != null) && (navigator.clipboard.readText != null)) {
 | 
					            if ((navigator.clipboard != null) && (navigator.clipboard.readText != null)) {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    navigator.clipboard.readText().then(function(text) {
 | 
					                    navigator.clipboard.readText().then(function(text) {
 | 
				
			||||||
                        meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text });
 | 
					                        if (desktop.m.setClipboard) { desktop.m.setClipboard(text); } else { meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text }); }
 | 
				
			||||||
                    }).catch(function(err) { console.log(err); });
 | 
					                    }).catch(function(err) { console.log(err); });
 | 
				
			||||||
                } catch (ex) { console.log(ex); }
 | 
					                } catch (ex) { console.log(ex); }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -8332,7 +8332,8 @@
 | 
				
			||||||
            var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
 | 
					            var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
 | 
				
			||||||
            QE('connectbutton1h', hwonline);
 | 
					            QE('connectbutton1h', hwonline);
 | 
				
			||||||
            QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
 | 
					            QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
 | 
				
			||||||
            QE('DeskClip', (deskState == 3) && (desktop.contype != 4));
 | 
					            QE('DeskClip', deskState == 3);
 | 
				
			||||||
 | 
					            //QE('DeskClip', (deskState == 3) && (desktop.contype != 4));
 | 
				
			||||||
            QV('DeskClip', (inputAllowed) && (currentNode.agent) && ((features2 & 0x1800) != 0x1800) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2)) && ((desktopsettings.autoclipboard != true) || (navigator.clipboard == null) || (navigator.clipboard.readText == null))); // Clipboard not supported on macOS
 | 
					            QV('DeskClip', (inputAllowed) && (currentNode.agent) && ((features2 & 0x1800) != 0x1800) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2)) && ((desktopsettings.autoclipboard != true) || (navigator.clipboard == null) || (navigator.clipboard.readText == null))); // Clipboard not supported on macOS
 | 
				
			||||||
            QE('DeskESC', (deskState == 3) && (desktop.contype != 4));
 | 
					            QE('DeskESC', (deskState == 3) && (desktop.contype != 4));
 | 
				
			||||||
            QV('DeskESC', browserfullscreen && inputAllowed);
 | 
					            QV('DeskESC', browserfullscreen && inputAllowed);
 | 
				
			||||||
| 
						 | 
					@ -8737,7 +8738,7 @@
 | 
				
			||||||
                    try {
 | 
					                    try {
 | 
				
			||||||
                        navigator.clipboard.readText().then(function(text) {
 | 
					                        navigator.clipboard.readText().then(function(text) {
 | 
				
			||||||
                            if ((text != null) && (deskLastClipboardSent != text)) {
 | 
					                            if ((text != null) && (deskLastClipboardSent != text)) {
 | 
				
			||||||
                                meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text });
 | 
					                                if (desktop.m.setClipboard) { desktop.m.setClipboard(text); } else { meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text }); }
 | 
				
			||||||
                                deskLastClipboardSent = text;
 | 
					                                deskLastClipboardSent = text;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }).catch(function(err) { });
 | 
					                        }).catch(function(err) { });
 | 
				
			||||||
| 
						 | 
					@ -9323,9 +9324,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        function showDeskClipSet() {
 | 
					        function showDeskClipSet() {
 | 
				
			||||||
            if (desktop == null || desktop.State != 3) return;
 | 
					            if (desktop == null || desktop.State != 3) return;
 | 
				
			||||||
 | 
					            if (desktop.m.setClipboard) {
 | 
				
			||||||
 | 
					                desktop.m.setClipboard(Q('d2clipText').value);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
 | 
					                meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
 | 
				
			||||||
                QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22) && (currentNode.agent.id != 34));
 | 
					                QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22) && (currentNode.agent.id != 34));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Send CTRL-ALT-DEL
 | 
					        // Send CTRL-ALT-DEL
 | 
				
			||||||
        function sendCAD() {
 | 
					        function sendCAD() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue