mirror of
https://github.com/yv1ing/ShotRDP.git
synced 2025-09-16 15:10:57 +08:00
基本适应win7,win10,win server 08,win server 12,win server 16的截图
This commit is contained in:
771
grdp/plugin/cliprdr/cliprdr.go
Normal file
771
grdp/plugin/cliprdr/cliprdr.go
Normal file
@@ -0,0 +1,771 @@
|
||||
package cliprdr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/lunixbochs/struc"
|
||||
|
||||
"ShotRDP/grdp/core"
|
||||
"ShotRDP/grdp/glog"
|
||||
"ShotRDP/grdp/plugin"
|
||||
)
|
||||
|
||||
/**
|
||||
* Initialization Sequence\n
|
||||
* Client Server\n
|
||||
* | |\n
|
||||
* |<----------------------Server Clipboard Capabilities PDU-----------------|\n
|
||||
* |<-----------------------------Monitor Ready PDU--------------------------|\n
|
||||
* |-----------------------Client Clipboard Capabilities PDU---------------->|\n
|
||||
* |---------------------------Temporary Directory PDU---------------------->|\n
|
||||
* |-------------------------------Format List PDU-------------------------->|\n
|
||||
* |<--------------------------Format List Response PDU----------------------|\n
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data Transfer Sequences\n
|
||||
* Shared Local\n
|
||||
* Clipboard Owner Clipboard Owner\n
|
||||
* | |\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |-------------------------------Format List PDU-------------------------->|\n |
|
||||
* |<--------------------------Format List Response PDU----------------------|\n _| Copy
|
||||
* Sequence
|
||||
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |<--------------------------Format Data Request PDU-----------------------|\n | Paste
|
||||
* Sequence Palette,
|
||||
* |---------------------------Format Data Response PDU--------------------->|\n _| Metafile,
|
||||
* File List Data
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
* |-------------------------------------------------------------------------|\n _
|
||||
* |<------------------------Format Contents Request PDU---------------------|\n | Paste
|
||||
* Sequence
|
||||
* |-------------------------Format Contents Response PDU------------------->|\n _| File
|
||||
* Stream Data
|
||||
* |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n
|
||||
* |-------------------------------------------------------------------------|\n
|
||||
*
|
||||
*/
|
||||
|
||||
const (
|
||||
ChannelName = plugin.CLIPRDR_SVC_CHANNEL_NAME
|
||||
ChannelOption = plugin.CHANNEL_OPTION_INITIALIZED | plugin.CHANNEL_OPTION_ENCRYPT_RDP |
|
||||
plugin.CHANNEL_OPTION_COMPRESS_RDP | plugin.CHANNEL_OPTION_SHOW_PROTOCOL
|
||||
)
|
||||
|
||||
type MsgType uint16
|
||||
|
||||
const (
|
||||
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
|
||||
CB_FILECONTENTS_RESPONSE = 0x0009
|
||||
CB_LOCK_CLIPDATA = 0x000A
|
||||
CB_UNLOCK_CLIPDATA = 0x000B
|
||||
)
|
||||
|
||||
type MsgFlags uint16
|
||||
|
||||
const (
|
||||
CB_RESPONSE_OK = 0x0001
|
||||
CB_RESPONSE_FAIL = 0x0002
|
||||
CB_ASCII_NAMES = 0x0004
|
||||
)
|
||||
|
||||
type DwFlags uint32
|
||||
|
||||
const (
|
||||
FILECONTENTS_SIZE = 0x00000001
|
||||
FILECONTENTS_RANGE = 0x00000002
|
||||
)
|
||||
|
||||
type CliprdrPDUHeader struct {
|
||||
MsgType uint16 `struc:"little"`
|
||||
MsgFlags uint16 `struc:"little"`
|
||||
DataLen uint32 `struc:"little"`
|
||||
}
|
||||
|
||||
func NewCliprdrPDUHeader(mType, flags uint16, ln uint32) *CliprdrPDUHeader {
|
||||
return &CliprdrPDUHeader{
|
||||
MsgType: mType,
|
||||
MsgFlags: flags,
|
||||
DataLen: ln,
|
||||
}
|
||||
}
|
||||
func (h *CliprdrPDUHeader) serialize() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt16LE(h.MsgType, b)
|
||||
core.WriteUInt16LE(h.MsgFlags, b)
|
||||
core.WriteUInt32LE(h.DataLen, b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
type CliprdrGeneralCapabilitySet struct {
|
||||
CapabilitySetType uint16 `struc:"little"`
|
||||
CapabilitySetLength uint16 `struc:"little"`
|
||||
Version uint32 `struc:"little"`
|
||||
GeneralFlags uint32 `struc:"little"`
|
||||
}
|
||||
|
||||
const (
|
||||
CB_CAPSTYPE_GENERAL = 0x0001
|
||||
)
|
||||
|
||||
type CliprdrCapabilitySets struct {
|
||||
CapabilitySetType uint16 `struc:"little"`
|
||||
LengthCapability uint16 `struc:"little"`
|
||||
Version uint32 `struc:"little"`
|
||||
GeneralFlags uint32 `struc:"little"`
|
||||
//CapabilityData []byte `struc:"little"`
|
||||
}
|
||||
type CliprdrCapabilitiesPDU struct {
|
||||
CCapabilitiesSets uint16 `struc:"little,sizeof=CapabilitySets"`
|
||||
Pad1 uint16 `struc:"little"`
|
||||
CapabilitySets []CliprdrGeneralCapabilitySet `struc:"little"`
|
||||
}
|
||||
|
||||
type CliprdrMonitorReady struct {
|
||||
}
|
||||
|
||||
type GeneralFlags uint32
|
||||
|
||||
const (
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
|
||||
CB_USE_LONG_FORMAT_NAMES = 0x00000002
|
||||
CB_STREAM_FILECLIP_ENABLED = 0x00000004
|
||||
CB_FILECLIP_NO_FILE_PATHS = 0x00000008
|
||||
CB_CAN_LOCK_CLIPDATA = 0x00000010
|
||||
CB_HUGE_FILE_SUPPORT_ENABLED = 0x00000020
|
||||
)
|
||||
|
||||
const (
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.version */
|
||||
CB_CAPS_VERSION_1 = 0x00000001
|
||||
CB_CAPS_VERSION_2 = 0x00000002
|
||||
)
|
||||
const (
|
||||
CB_CAPSTYPE_GENERAL_LEN = 12
|
||||
)
|
||||
|
||||
const (
|
||||
FD_CLSID = 0x00000001
|
||||
FD_SIZEPOINT = 0x00000002
|
||||
FD_ATTRIBUTES = 0x00000004
|
||||
FD_CREATETIME = 0x00000008
|
||||
FD_ACCESSTIME = 0x00000010
|
||||
FD_WRITESTIME = 0x00000020
|
||||
FD_FILESIZE = 0x00000040
|
||||
FD_PROGRESSUI = 0x00004000
|
||||
FD_LINKUI = 0x00008000
|
||||
)
|
||||
|
||||
type FileGroupDescriptor struct {
|
||||
CItems uint32 `struc:"little"`
|
||||
Fgd []FileDescriptor `struc:"sizefrom=CItems"`
|
||||
}
|
||||
type FileDescriptor struct {
|
||||
Flags uint32 `struc:"little"`
|
||||
Clsid [16]byte `struc:"little"`
|
||||
Sizel [8]byte `struc:"little"`
|
||||
Pointl [8]byte `struc:"little"`
|
||||
FileAttributes uint32 `struc:"little"`
|
||||
CreationTime [8]byte `struc:"little"`
|
||||
LastAccessTime [8]byte `struc:"little"`
|
||||
LastWriteTime []byte `struc:"[8]byte"` //8
|
||||
FileSizeHigh uint32 `struc:"little"`
|
||||
FileSizeLow uint32 `struc:"little"`
|
||||
FileName []byte `struc:"[512]byte"`
|
||||
}
|
||||
|
||||
func (f *FileGroupDescriptor) Unpack(b []byte) error {
|
||||
r := bytes.NewReader(b)
|
||||
err := struc.Unpack(r, f)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *FileDescriptor) serialize() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt32LE(f.Flags, b)
|
||||
for i := 0; i < 32; i++ {
|
||||
core.WriteByte(0, b)
|
||||
}
|
||||
core.WriteUInt32LE(f.FileAttributes, b)
|
||||
for i := 0; i < 16; i++ {
|
||||
core.WriteByte(0, b)
|
||||
}
|
||||
core.WriteBytes(f.LastWriteTime[:], b)
|
||||
core.WriteUInt32LE(f.FileSizeHigh, b)
|
||||
core.WriteUInt32LE(f.FileSizeLow, b)
|
||||
name := make([]byte, 512)
|
||||
copy(name, f.FileName)
|
||||
core.WriteBytes(name, b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (f *FileDescriptor) isDir() bool {
|
||||
if f.Flags&FD_ATTRIBUTES != 0 {
|
||||
return f.FileAttributes&FILE_ATTRIBUTE_DIRECTORY != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *FileDescriptor) hasFileSize() bool {
|
||||
return f.Flags&FD_FILESIZE != 0
|
||||
}
|
||||
|
||||
// temp dir
|
||||
type CliprdrTempDirectory struct {
|
||||
SzTempDir []byte `struc:"[260]byte"`
|
||||
}
|
||||
|
||||
// format list
|
||||
type CliprdrFormat struct {
|
||||
FormatId uint32
|
||||
FormatName string
|
||||
}
|
||||
type CliprdrFormatList struct {
|
||||
NumFormats uint32
|
||||
Formats []CliprdrFormat
|
||||
}
|
||||
type ClipboardFormats uint16
|
||||
|
||||
const (
|
||||
CB_FORMAT_HTML = 0xD010
|
||||
CB_FORMAT_PNG = 0xD011
|
||||
CB_FORMAT_JPEG = 0xD012
|
||||
CB_FORMAT_GIF = 0xD013
|
||||
CB_FORMAT_TEXTURILIST = 0xD014
|
||||
CB_FORMAT_GNOMECOPIEDFILES = 0xD015
|
||||
CB_FORMAT_MATECOPIEDFILES = 0xD016
|
||||
)
|
||||
|
||||
// lock or unlock
|
||||
type CliprdrCtrlClipboardData struct {
|
||||
ClipDataId uint32
|
||||
}
|
||||
|
||||
// format data
|
||||
type CliprdrFormatDataRequest struct {
|
||||
RequestedFormatId uint32
|
||||
}
|
||||
type CliprdrFormatDataResponse struct {
|
||||
RequestedFormatData []byte
|
||||
}
|
||||
|
||||
// file contents
|
||||
type CliprdrFileContentsRequest struct {
|
||||
StreamId uint32 `struc:"little"`
|
||||
Lindex uint32 `struc:"little"`
|
||||
DwFlags uint32 `struc:"little"`
|
||||
NPositionLow uint32 `struc:"little"`
|
||||
NPositionHigh uint32 `struc:"little"`
|
||||
CbRequested uint32 `struc:"little"`
|
||||
ClipDataId uint32 `struc:"little"`
|
||||
}
|
||||
|
||||
func FileContentsSizeRequest(i uint32) *CliprdrFileContentsRequest {
|
||||
return &CliprdrFileContentsRequest{
|
||||
StreamId: 1,
|
||||
Lindex: i,
|
||||
DwFlags: FILECONTENTS_SIZE,
|
||||
NPositionLow: 0,
|
||||
NPositionHigh: 0,
|
||||
CbRequested: 65535,
|
||||
ClipDataId: 0,
|
||||
}
|
||||
}
|
||||
|
||||
type CliprdrFileContentsResponse struct {
|
||||
StreamId uint32
|
||||
CbRequested uint32
|
||||
RequestedData []byte
|
||||
}
|
||||
|
||||
func (resp *CliprdrFileContentsResponse) Unpack(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
resp.StreamId, _ = core.ReadUInt32LE(r)
|
||||
resp.CbRequested = uint32(r.Len())
|
||||
resp.RequestedData, _ = core.ReadBytes(int(resp.CbRequested), r)
|
||||
}
|
||||
|
||||
type CliprdrClient struct {
|
||||
w core.ChannelSender
|
||||
useLongFormatNames bool
|
||||
streamFileClipEnabled bool
|
||||
fileClipNoFilePaths bool
|
||||
canLockClipData bool
|
||||
hasHugeFileSupport bool
|
||||
formatIdMap map[uint32]uint32
|
||||
Files []FileDescriptor
|
||||
reply chan []byte
|
||||
Control
|
||||
}
|
||||
|
||||
func NewCliprdrClient() *CliprdrClient {
|
||||
c := &CliprdrClient{
|
||||
formatIdMap: make(map[uint32]uint32, 20),
|
||||
Files: make([]FileDescriptor, 0, 20),
|
||||
reply: make(chan []byte, 100),
|
||||
}
|
||||
|
||||
go ClipWatcher(c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) Send(s []byte) (int, error) {
|
||||
glog.Debug("len:", len(s), "data:", hex.EncodeToString(s))
|
||||
name, _ := c.GetType()
|
||||
return c.w.SendToChannel(name, s)
|
||||
}
|
||||
func (c *CliprdrClient) Sender(f core.ChannelSender) {
|
||||
c.w = f
|
||||
}
|
||||
func (c *CliprdrClient) GetType() (string, uint32) {
|
||||
return ChannelName, ChannelOption
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) Process(s []byte) {
|
||||
glog.Debug("recv:", hex.EncodeToString(s))
|
||||
r := bytes.NewReader(s)
|
||||
|
||||
msgType, _ := core.ReadUint16LE(r)
|
||||
flag, _ := core.ReadUint16LE(r)
|
||||
length, _ := core.ReadUInt32LE(r)
|
||||
glog.Debugf("cliprdr: type=0x%x flag=%d length=%d, all=%d", msgType, flag, length, r.Len())
|
||||
|
||||
b, _ := core.ReadBytes(int(length), r)
|
||||
|
||||
switch msgType {
|
||||
case CB_CLIP_CAPS:
|
||||
glog.Info("CB_CLIP_CAPS")
|
||||
c.processClipCaps(b)
|
||||
|
||||
case CB_MONITOR_READY:
|
||||
glog.Info("CB_MONITOR_READY")
|
||||
c.processMonitorReady(b)
|
||||
|
||||
case CB_FORMAT_LIST:
|
||||
glog.Info("CB_FORMAT_LIST")
|
||||
c.processFormatList(b)
|
||||
|
||||
case CB_FORMAT_LIST_RESPONSE:
|
||||
glog.Info("CB_FORMAT_LIST_RESPONSE")
|
||||
c.processFormatListResponse(flag, b)
|
||||
|
||||
case CB_FORMAT_DATA_REQUEST:
|
||||
glog.Info("CB_FORMAT_DATA_REQUEST")
|
||||
c.processFormatDataRequest(b)
|
||||
|
||||
case CB_FORMAT_DATA_RESPONSE:
|
||||
glog.Info("CB_FORMAT_DATA_RESPONSE")
|
||||
c.processFormatDataResponse(flag, b)
|
||||
|
||||
case CB_FILECONTENTS_REQUEST:
|
||||
glog.Info("CB_FILECONTENTS_REQUEST")
|
||||
c.processFileContentsRequest(b)
|
||||
|
||||
case CB_FILECONTENTS_RESPONSE:
|
||||
glog.Info("CB_FILECONTENTS_RESPONSE")
|
||||
c.processFileContentsResponse(flag, b)
|
||||
|
||||
case CB_LOCK_CLIPDATA:
|
||||
glog.Info("CB_LOCK_CLIPDATA")
|
||||
c.processLockClipData(b)
|
||||
|
||||
case CB_UNLOCK_CLIPDATA:
|
||||
glog.Info("CB_UNLOCK_CLIPDATA")
|
||||
c.processUnlockClipData(b)
|
||||
|
||||
default:
|
||||
glog.Errorf("type 0x%x not supported", msgType)
|
||||
}
|
||||
}
|
||||
func (c *CliprdrClient) processClipCaps(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
var cp CliprdrCapabilitiesPDU
|
||||
err := struc.Unpack(r, &cp)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
glog.Debugf("Capabilities:%+v", cp)
|
||||
c.useLongFormatNames = cp.CapabilitySets[0].GeneralFlags&CB_USE_LONG_FORMAT_NAMES != 0
|
||||
c.streamFileClipEnabled = cp.CapabilitySets[0].GeneralFlags&CB_STREAM_FILECLIP_ENABLED != 0
|
||||
c.fileClipNoFilePaths = cp.CapabilitySets[0].GeneralFlags&CB_FILECLIP_NO_FILE_PATHS != 0
|
||||
c.canLockClipData = cp.CapabilitySets[0].GeneralFlags&CB_CAN_LOCK_CLIPDATA != 0
|
||||
c.hasHugeFileSupport = cp.CapabilitySets[0].GeneralFlags&CB_HUGE_FILE_SUPPORT_ENABLED != 0
|
||||
glog.Info("UseLongFormatNames:", c.useLongFormatNames)
|
||||
glog.Info("StreamFileClipEnabled:", c.streamFileClipEnabled)
|
||||
glog.Info("FileClipNoFilePaths:", c.fileClipNoFilePaths)
|
||||
glog.Info("CanLockClipData:", c.canLockClipData)
|
||||
glog.Info("HasHugeFileSupport:", c.hasHugeFileSupport)
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) processMonitorReady(b []byte) {
|
||||
//Client Clipboard Capabilities PDU
|
||||
c.sendClientCapabilitiesPDU()
|
||||
|
||||
//Temporary Directory PDU
|
||||
//c.sendTemporaryDirectoryPDU()
|
||||
|
||||
//Format List PDU
|
||||
c.sendFormatListPDU()
|
||||
|
||||
}
|
||||
func (c *CliprdrClient) processFormatList(b []byte) {
|
||||
c.withOpenClipboard(func() {
|
||||
if !EmptyClipboard() {
|
||||
glog.Error("EmptyClipboard failed")
|
||||
}
|
||||
})
|
||||
fl, hasFile := c.readForamtList(b)
|
||||
glog.Info("numFormats:", fl.NumFormats)
|
||||
|
||||
if hasFile {
|
||||
c.SendCliprdrMessage()
|
||||
} else {
|
||||
c.withOpenClipboard(func() {
|
||||
if !EmptyClipboard() {
|
||||
glog.Error("EmptyClipboard failed")
|
||||
}
|
||||
for i := range c.formatIdMap {
|
||||
glog.Debug("i:", i)
|
||||
SetClipboardData(i, 0)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
c.sendFormatListResponse(CB_RESPONSE_OK)
|
||||
}
|
||||
func (c *CliprdrClient) processFormatListResponse(flag uint16, b []byte) {
|
||||
if flag != CB_RESPONSE_OK {
|
||||
glog.Error("Format List Response Failed")
|
||||
return
|
||||
}
|
||||
glog.Error("Format List Response OK")
|
||||
}
|
||||
func getFilesDescriptor(name string) (FileDescriptor, error) {
|
||||
var fd FileDescriptor
|
||||
fd.Flags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI
|
||||
f, e := os.Stat(name)
|
||||
if e != nil {
|
||||
glog.Error(e.Error())
|
||||
return fd, e
|
||||
}
|
||||
fd.FileAttributes, fd.LastWriteTime,
|
||||
fd.FileSizeHigh, fd.FileSizeLow = GetFileInfo(f.Sys())
|
||||
fd.FileName = core.UnicodeEncode(name)
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
func (c *CliprdrClient) processFormatDataRequest(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
requestId, _ := core.ReadUInt32LE(r)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
if requestId == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW) {
|
||||
fs := GetFileNames()
|
||||
core.WriteUInt32LE(uint32(len(fs)), buff)
|
||||
c.Files = c.Files[:0]
|
||||
for _, v := range fs {
|
||||
glog.Info("Name:", v)
|
||||
f, _ := getFilesDescriptor(v)
|
||||
buff.Write(f.serialize())
|
||||
for i := 0; i < 8; i++ {
|
||||
buff.WriteByte(0)
|
||||
}
|
||||
c.Files = append(c.Files, f)
|
||||
|
||||
}
|
||||
} else {
|
||||
c.withOpenClipboard(func() {
|
||||
data := GetClipboardData(requestId)
|
||||
glog.Debug("data:", data)
|
||||
buff.Write(core.UnicodeEncode(data))
|
||||
buff.Write([]byte{0, 0})
|
||||
})
|
||||
}
|
||||
|
||||
c.sendFormatDataResponse(buff.Bytes())
|
||||
}
|
||||
func (c *CliprdrClient) processFormatDataResponse(flag uint16, b []byte) {
|
||||
if flag != CB_RESPONSE_OK {
|
||||
glog.Error("Format Data Response Failed")
|
||||
}
|
||||
c.reply <- b
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) processFileContentsRequest(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
var req CliprdrFileContentsRequest
|
||||
struc.Unpack(r, &req)
|
||||
if len(c.Files) <= int(req.Lindex) {
|
||||
glog.Error("No found file:", req.Lindex)
|
||||
c.sendFormatContentsResponse(req.StreamId, []byte{})
|
||||
return
|
||||
}
|
||||
buff := &bytes.Buffer{}
|
||||
/*o := OleGetClipboard()
|
||||
var format_etc FORMATETC
|
||||
var stg_medium STGMEDIUM
|
||||
format_etc.CFormat = RegisterClipboardFormat(CFSTR_FILECONTENTS)
|
||||
format_etc.Tymed = TYMED_ISTREAM
|
||||
format_etc.Aspect = 1
|
||||
format_etc.Index = req.Lindex
|
||||
o.GetData(&format_etc, &stg_medium)
|
||||
s, _ := stg_medium.Stream()*/
|
||||
f := c.Files[req.Lindex]
|
||||
if req.DwFlags == FILECONTENTS_SIZE {
|
||||
core.WriteUInt32LE(f.FileSizeLow, buff)
|
||||
core.WriteUInt32LE(f.FileSizeHigh, buff)
|
||||
c.sendFormatContentsResponse(req.StreamId, buff.Bytes())
|
||||
} else if req.DwFlags == FILECONTENTS_RANGE {
|
||||
name := core.UnicodeDecode(f.FileName)
|
||||
fi, err := os.Open(name)
|
||||
if err != nil {
|
||||
glog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
defer fi.Close()
|
||||
data := make([]byte, req.CbRequested)
|
||||
n, _ := fi.ReadAt(data, int64(f.FileSizeHigh))
|
||||
c.sendFormatContentsResponse(req.StreamId, data[:n])
|
||||
}
|
||||
}
|
||||
func (c *CliprdrClient) processFileContentsResponse(flag uint16, b []byte) {
|
||||
if flag != CB_RESPONSE_OK {
|
||||
glog.Error("File Contents Response Failed")
|
||||
}
|
||||
var resp CliprdrFileContentsResponse
|
||||
resp.Unpack(b)
|
||||
glog.Debug("Get File Contents Response:", resp.StreamId, resp.CbRequested)
|
||||
c.reply <- resp.RequestedData
|
||||
}
|
||||
func (c *CliprdrClient) processLockClipData(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
var l CliprdrCtrlClipboardData
|
||||
l.ClipDataId, _ = core.ReadUInt32LE(r)
|
||||
}
|
||||
func (c *CliprdrClient) processUnlockClipData(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
var l CliprdrCtrlClipboardData
|
||||
l.ClipDataId, _ = core.ReadUInt32LE(r)
|
||||
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendClientCapabilitiesPDU() {
|
||||
glog.Info("Send Client Clipboard Capabilities PDU")
|
||||
var cs CliprdrGeneralCapabilitySet
|
||||
cs.CapabilitySetLength = 12
|
||||
cs.CapabilitySetType = CB_CAPSTYPE_GENERAL
|
||||
cs.Version = CB_CAPS_VERSION_2
|
||||
cs.GeneralFlags = CB_USE_LONG_FORMAT_NAMES |
|
||||
CB_STREAM_FILECLIP_ENABLED |
|
||||
CB_FILECLIP_NO_FILE_PATHS
|
||||
var cc CliprdrCapabilitiesPDU
|
||||
cc.CCapabilitiesSets = 1
|
||||
cc.Pad1 = 0
|
||||
cc.CapabilitySets = make([]CliprdrGeneralCapabilitySet, 0, 1)
|
||||
cc.CapabilitySets = append(cc.CapabilitySets, cs)
|
||||
header := NewCliprdrPDUHeader(CB_CLIP_CAPS, 0, 16)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt16LE(cc.CCapabilitiesSets, buff)
|
||||
core.WriteUInt16LE(cc.Pad1, buff)
|
||||
for _, v := range cc.CapabilitySets {
|
||||
struc.Pack(buff, v)
|
||||
}
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendTemporaryDirectoryPDU() {
|
||||
glog.Info("Send Temporary Directory PDU")
|
||||
var t CliprdrTempDirectory
|
||||
header := &CliprdrPDUHeader{CB_TEMP_DIRECTORY, 0, 260}
|
||||
t.SzTempDir = core.UnicodeEncode(os.TempDir())
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
core.WriteBytes(header.serialize(), buff)
|
||||
core.WriteBytes(t.SzTempDir, buff)
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
func (c *CliprdrClient) sendFormatListPDU() {
|
||||
glog.Info("Send Format List PDU")
|
||||
var f CliprdrFormatList
|
||||
|
||||
f.Formats = GetFormatList(c.hwnd)
|
||||
f.NumFormats = uint32(len(f.Formats))
|
||||
|
||||
glog.Info("NumFormats:", f.NumFormats)
|
||||
glog.Debug("Formats:", f.Formats)
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
for _, v := range f.Formats {
|
||||
core.WriteUInt32LE(v.FormatId, b)
|
||||
if v.FormatName == "" {
|
||||
core.WriteUInt16LE(0, b)
|
||||
} else {
|
||||
n := core.UnicodeEncode(v.FormatName)
|
||||
core.WriteBytes(n, b)
|
||||
b.Write([]byte{0, 0})
|
||||
}
|
||||
}
|
||||
|
||||
header := NewCliprdrPDUHeader(CB_FORMAT_LIST, 0, uint32(b.Len()))
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteBytes(b.Bytes(), buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
func (c *CliprdrClient) readForamtList(b []byte) (*CliprdrFormatList, bool) {
|
||||
r := bytes.NewReader(b)
|
||||
fs := make([]CliprdrFormat, 0, 20)
|
||||
var numFormats uint32 = 0
|
||||
hasFile := false
|
||||
c.formatIdMap = make(map[uint32]uint32, 0)
|
||||
for r.Len() > 0 {
|
||||
foramtId, _ := core.ReadUInt32LE(r)
|
||||
bs := make([]uint16, 0, 20)
|
||||
ln := r.Len()
|
||||
for j := 0; j < ln; j++ {
|
||||
b, _ := core.ReadUint16LE(r)
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
bs = append(bs, b)
|
||||
}
|
||||
name := string(utf16.Decode(bs))
|
||||
if strings.EqualFold(name, CFSTR_FILEDESCRIPTORW) {
|
||||
hasFile = true
|
||||
}
|
||||
glog.Infof("Foramt:%d Name:<%s>", foramtId, name)
|
||||
if name != "" {
|
||||
localId := RegisterClipboardFormat(name)
|
||||
glog.Info("local:", localId, "remote:", foramtId)
|
||||
c.formatIdMap[localId] = foramtId
|
||||
} else {
|
||||
c.formatIdMap[foramtId] = foramtId
|
||||
}
|
||||
|
||||
numFormats++
|
||||
fs = append(fs, CliprdrFormat{foramtId, name})
|
||||
}
|
||||
|
||||
return &CliprdrFormatList{numFormats, fs}, hasFile
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendFormatListResponse(flags uint16) {
|
||||
glog.Info("Send Format List Response")
|
||||
header := NewCliprdrPDUHeader(CB_FORMAT_LIST_RESPONSE, flags, 0)
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendFormatDataRequest(id uint32) {
|
||||
glog.Info("Send Format Data Request")
|
||||
var r CliprdrFormatDataRequest
|
||||
r.RequestedFormatId = id
|
||||
header := NewCliprdrPDUHeader(CB_FORMAT_DATA_REQUEST, 0, 4)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt32LE(r.RequestedFormatId, buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
func (c *CliprdrClient) sendFormatDataResponse(b []byte) {
|
||||
glog.Info("Send Format Data Response")
|
||||
var resp CliprdrFormatDataResponse
|
||||
resp.RequestedFormatData = b
|
||||
|
||||
header := NewCliprdrPDUHeader(CB_FORMAT_DATA_RESPONSE, CB_RESPONSE_OK, uint32(len(resp.RequestedFormatData)))
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
buff.Write(resp.RequestedFormatData)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendFormatContentsRequest(r CliprdrFileContentsRequest) uint32 {
|
||||
glog.Info("Send Format Contents Request")
|
||||
glog.Debugf("Format Contents Request:%+v", r)
|
||||
header := NewCliprdrPDUHeader(CB_FILECONTENTS_REQUEST, 0, 28)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt32LE(r.StreamId, buff)
|
||||
core.WriteUInt32LE(uint32(r.Lindex), buff)
|
||||
core.WriteUInt32LE(r.DwFlags, buff)
|
||||
core.WriteUInt32LE(r.NPositionLow, buff)
|
||||
core.WriteUInt32LE(r.NPositionHigh, buff)
|
||||
core.WriteUInt32LE(r.CbRequested, buff)
|
||||
core.WriteUInt32LE(r.ClipDataId, buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
|
||||
return uint32(buff.Len())
|
||||
}
|
||||
func (c *CliprdrClient) sendFormatContentsResponse(streamId uint32, b []byte) {
|
||||
glog.Info("Send Format Contents Response")
|
||||
var r CliprdrFileContentsResponse
|
||||
r.StreamId = streamId
|
||||
r.RequestedData = b
|
||||
r.CbRequested = uint32(len(b))
|
||||
header := NewCliprdrPDUHeader(CB_FILECONTENTS_RESPONSE, CB_RESPONSE_OK, uint32(4+r.CbRequested))
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt32LE(r.StreamId, buff)
|
||||
core.WriteBytes(r.RequestedData, buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendLockClipData() {
|
||||
glog.Info("Send Lock Clip Data")
|
||||
var r CliprdrCtrlClipboardData
|
||||
header := NewCliprdrPDUHeader(CB_LOCK_CLIPDATA, 0, 4)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt32LE(r.ClipDataId, buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (c *CliprdrClient) sendUnlockClipData() {
|
||||
glog.Info("Send Unlock Clip Data")
|
||||
var r CliprdrCtrlClipboardData
|
||||
header := NewCliprdrPDUHeader(CB_UNLOCK_CLIPDATA, 0, 4)
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
buff.Write(header.serialize())
|
||||
core.WriteUInt32LE(r.ClipDataId, buff)
|
||||
|
||||
c.Send(buff.Bytes())
|
||||
}
|
||||
Reference in New Issue
Block a user