1const type = require('../../core').type;
2const EventEmitter = require('events').EventEmitter;
3const caps = require('./caps');
4const log = require('../../core').log;
5const data = require('./data');
10 * Cliprdr channel for all clipboard
11 * capabilities exchange
13class Cliprdr extends EventEmitter {
15 constructor(transport) {
17 this.transport = transport;
18 // must be init via connect event
20 this.serverCapabilities = [];
21 this.clientCapabilities = [];
28 * Client side of Cliprdr channel automata
31class Client extends Cliprdr {
33 constructor(transport, fastPathTransport) {
35 super(transport, fastPathTransport);
37 this.transport.once('connect', (gccCore, userId, channelId) => {
38 this.connect(gccCore, userId, channelId);
39 }).on('close', function () {
41 }).on('error', function (err) {
42 //this.emit('error', err);
51 * @param gccCore {type.Component(clientCoreData)}
53 connect(gccCore, userId, channelId) {
54 this.gccCore = gccCore;
56 this.channelId = channelId;
57 this.transport.once('cliprdr', (s) => {
64 this.transport.send('cliprdr', new type.Component([
66 new type.UInt32Le(message.size()),
67 // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL
68 new type.UInt32Le(0x13),
75 const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType;
77 switch (pdu.obj.header.obj.msgType.value) {
78 case type.CB_MONITOR_READY:
79 this.recvMonitorReadyPDU(s);
81 case type.CB_FORMAT_LIST:
82 this.recvFormatListPDU(s);
84 case type.CB_FORMAT_LIST_RESPONSE:
85 this.recvFormatListResponsePDU(s);
87 case type.CB_FORMAT_DATA_REQUEST:
88 this.recvFormatDataRequestPDU(s);
90 case type.CB_FORMAT_DATA_RESPONSE:
91 this.recvFormatDataResponsePDU(s);
93 case type.CB_TEMP_DIRECTORY:
95 case type.CB_CLIP_CAPS:
96 this.recvClipboardCapsPDU(s);
98 case type.CB_FILECONTENTS_REQUEST:
101 this.transport.once('cliprdr', (s) => {
107 * Receive capabilities from server
108 * @param s {type.Stream}
110 recvClipboardCapsPDU(s) {
113 // const pdu = data.clipPDU().read(s);
114 // console.log('recvClipboardCapsPDU', s);
119 * Receive monitor ready from server
120 * @param s {type.Stream}
122 recvMonitorReadyPDU(s) {
124 // const pdu = data.clipPDU().read(s);
125 // console.log('recvMonitorReadyPDU', s);
127 this.sendClipboardCapsPDU();
128 // this.sendClientTemporaryDirectoryPDU();
129 this.sendFormatListPDU();
134 * Send clipboard capabilities PDU
136 sendClipboardCapsPDU() {
137 this.send(new type.Component({
138 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS),
139 msgFlags: new type.UInt16Le(0x00),
140 dataLen: new type.UInt32Le(0x10),
141 cCapabilitiesSets: new type.UInt16Le(0x01),
142 pad1: new type.UInt16Le(0x00),
143 capabilitySetType: new type.UInt16Le(0x01),
144 lengthCapability: new type.UInt16Le(0x0c),
145 version: new type.UInt32Le(0x02),
146 capabilityFlags: new type.UInt32Le(0x02)
152 * Send client temporary directory PDU
154 sendClientTemporaryDirectoryPDU(path = '') {
156 this.send(new type.Component({
157 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY),
158 msgFlags: new type.UInt16Le(0x00),
159 dataLen: new type.UInt32Le(0x0208),
160 wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength: new type.CallableValue(520) })
166 * Send format list PDU
168 sendFormatListPDU() {
169 this.send(new type.Component({
170 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST),
171 msgFlags: new type.UInt16Le(0x00),
173 dataLen: new type.UInt32Le(0x24),
175 formatId6: new type.UInt32Le(0xc004),
176 formatName6: new type.BinaryString(Buffer.from('Native\x00', 'ucs2'), { readLength: new type.CallableValue(14) }),
178 formatId8: new type.UInt32Le(0x0d),
179 formatName8: new type.UInt16Le(0x00),
181 formatId9: new type.UInt32Le(0x10),
182 formatName9: new type.UInt16Le(0x00),
184 formatId0: new type.UInt32Le(0x01),
185 formatName0: new type.UInt16Le(0x00),
187 // dataLen: new type.UInt32Le(0xe0),
189 // formatId1: new type.UInt32Le(0xc08a),
190 // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}),
192 // formatId2: new type.UInt32Le(0xc145),
193 // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}),
195 // formatId3: new type.UInt32Le(0xc143),
196 // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}),
198 // formatId4: new type.UInt32Le(0x01),
199 // formatName4: new type.BinaryString(0x00),
201 formatId5: new type.UInt32Le(0x07),
202 formatName5: new type.UInt16Le(0x00),
204 // formatId6: new type.UInt32Le(0xc004),
205 // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),
207 // formatId7: new type.UInt32Le(0xc00e),
208 // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}),
210 // formatId8: new type.UInt32Le(0x03),
211 // formatName8: new type.UInt16Le(0x00),
213 // formatId9: new type.UInt32Le(0x10),
214 // formatName9: new type.UInt16Le(0x00),
216 // formatId0: new type.UInt32Le(0x07),
217 // formatName0: new type.UInt16Le(0x00),
223 * Recvie format list PDU from server
224 * @param {type.Stream} s
226 recvFormatListPDU(s) {
228 // const pdu = data.clipPDU().read(s);
229 // console.log('recvFormatListPDU', s);
230 this.sendFormatListResponsePDU();
235 * Send format list reesponse
237 sendFormatListResponsePDU() {
238 this.send(new type.Component({
239 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE),
240 msgFlags: new type.UInt16Le(0x01),
241 dataLen: new type.UInt32Le(0x00),
244 this.sendFormatDataRequestPDU();
249 * Receive format list response from server
250 * @param s {type.Stream}
252 recvFormatListResponsePDU(s) {
254 // const pdu = data.clipPDU().read(s);
255 // console.log('recvFormatListResponsePDU', s);
256 // this.sendFormatDataRequestPDU();
261 * Send format data request PDU
263 sendFormatDataRequestPDU(formartId = 0x0d) {
264 this.send(new type.Component({
265 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST),
266 msgFlags: new type.UInt16Le(0x00),
267 dataLen: new type.UInt32Le(0x04),
268 requestedFormatId: new type.UInt32Le(formartId),
274 * Receive format data request PDU from server
275 * @param s {type.Stream}
277 recvFormatDataRequestPDU(s) {
279 // const pdu = data.clipPDU().read(s);
280 // console.log('recvFormatDataRequestPDU', s);
281 this.sendFormatDataResponsePDU();
286 * Send format data reesponse PDU
288 sendFormatDataResponsePDU() {
290 const bufs = Buffer.from(this.content + '\x00', 'ucs2');
292 this.send(new type.Component({
293 msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE),
294 msgFlags: new type.UInt16Le(0x01),
295 dataLen: new type.UInt32Le(bufs.length),
296 requestedFormatData: new type.BinaryString(bufs, { readLength: new type.CallableValue(bufs.length) })
303 * Receive format data response PDU from server
304 * @param s {type.Stream}
306 recvFormatDataResponsePDU(s) {
308 // const pdu = data.clipPDU().read(s);
309 const str = s.buffer.toString('ucs2', 26, s.buffer.length - 2);
310 // console.log('recvFormatDataResponsePDU', str);
312 this.emit('clipboard', str)
316 // =====================================================================================
317 setClipboardData(content) {
318 this.content = content;
319 this.sendFormatListPDU();