channels/cliprdr: start exchanging messages with server-side cliprdr
This commit is contained in:
parent
0fd705c6c7
commit
bca442a477
@ -18,7 +18,6 @@
|
||||
define_channel_client("cliprdr")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
cliprdr_constants.h
|
||||
cliprdr_format.c
|
||||
cliprdr_format.h
|
||||
cliprdr_main.c
|
||||
|
@ -1,58 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Clipboard Virtual Channel
|
||||
*
|
||||
* Copyright 2009-2011 Jay Sorg
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CLIPRDR_CONSTANTS
|
||||
#define __CLIPRDR_CONSTANTS
|
||||
|
||||
/* CLIPRDR_HEADER.msgType */
|
||||
#define CB_MONITOR_READY 0x0001
|
||||
#define CB_FORMAT_LIST 0x0002
|
||||
#define CB_FORMAT_LIST_RESPONSE 0x0003
|
||||
#define CB_FORMAT_DATA_REQUEST 0x0004
|
||||
#define CB_FORMAT_DATA_RESPONSE 0x0005
|
||||
#define CB_TEMP_DIRECTORY 0x0006
|
||||
#define CB_CLIP_CAPS 0x0007
|
||||
#define CB_FILECONTENTS_REQUEST 0x0008
|
||||
#define CB_FILECONTENTS_RESPONSE 0x0009
|
||||
#define CB_LOCK_CLIPDATA 0x000A
|
||||
#define CB_UNLOCK_CLIPDATA 0x000B
|
||||
|
||||
/* CLIPRDR_HEADER.msgFlags */
|
||||
#define CB_RESPONSE_OK 0x0001
|
||||
#define CB_RESPONSE_FAIL 0x0002
|
||||
#define CB_ASCII_NAMES 0x0004
|
||||
|
||||
/* CLIPRDR_CAPS_SET.capabilitySetType */
|
||||
#define CB_CAPSTYPE_GENERAL 0x0001
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
|
||||
#define CB_CAPSTYPE_GENERAL_LEN 12
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.version */
|
||||
#define CB_CAPS_VERSION_1 0x00000001
|
||||
#define CB_CAPS_VERSION_2 0x00000002
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
|
||||
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
|
||||
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
|
||||
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
|
||||
#define CB_CAN_LOCK_CLIPDATA 0x00000010
|
||||
|
||||
#endif /* __CLIPRDR_CONSTANTS */
|
@ -34,7 +34,6 @@
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include "cliprdr_constants.h"
|
||||
#include "cliprdr_main.h"
|
||||
#include "cliprdr_format.h"
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include "cliprdr_constants.h"
|
||||
#include "cliprdr_main.h"
|
||||
#include "cliprdr_format.h"
|
||||
|
||||
|
@ -25,14 +25,6 @@
|
||||
|
||||
#include <freerdp/utils/debug.h>
|
||||
|
||||
struct _CLIPRDR_FORMAT_NAME
|
||||
{
|
||||
UINT32 id;
|
||||
char* name;
|
||||
int length;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
|
||||
|
||||
struct cliprdr_plugin
|
||||
{
|
||||
rdpSvcPlugin plugin;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "cliprdr_main.h"
|
||||
@ -41,11 +42,69 @@
|
||||
|
||||
static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
UINT32 generalFlags;
|
||||
CLIPRDR_HEADER header;
|
||||
|
||||
printf("CliprdrServerSendCapabilities\n");
|
||||
|
||||
header.msgType = CB_CLIP_CAPS;
|
||||
header.msgFlags = 0;
|
||||
header.dataLen = 24;
|
||||
|
||||
generalFlags = 0;
|
||||
|
||||
if (context->priv->UseLongFormatNames)
|
||||
generalFlags |= CB_USE_LONG_FORMAT_NAMES;
|
||||
|
||||
s = Stream_New(NULL, header.dataLen);
|
||||
|
||||
Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
|
||||
Stream_Write_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
|
||||
|
||||
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets (2 bytes) */
|
||||
Stream_Write_UINT16(s, 0); /* pad1 (2 bytes) */
|
||||
|
||||
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL); /* capabilitySetType (2 bytes) */
|
||||
Stream_Write_UINT16(s, CB_CAPSTYPE_GENERAL_LEN); /* lengthCapability (2 bytes) */
|
||||
Stream_Write_UINT32(s, CB_CAPS_VERSION_2); /* version (4 bytes) */
|
||||
Stream_Write_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
||||
{
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
|
||||
printf("CliprdrServerSendMonitorReady\n");
|
||||
|
||||
header.msgType = CB_MONITOR_READY;
|
||||
header.msgFlags = 0;
|
||||
header.dataLen = 8;
|
||||
|
||||
s = Stream_New(NULL, header.dataLen);
|
||||
|
||||
Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */
|
||||
Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
|
||||
Stream_Write_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -54,6 +113,184 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
UINT32 version;
|
||||
UINT32 generalFlags;
|
||||
UINT16 cCapabilitiesSets;
|
||||
UINT16 capabilitySetType;
|
||||
UINT16 lengthCapability;
|
||||
|
||||
Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
|
||||
Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
|
||||
|
||||
Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
|
||||
Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */
|
||||
|
||||
Stream_Read_UINT32(s, version); /* version (4 bytes) */
|
||||
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
||||
|
||||
if (generalFlags & CB_USE_LONG_FORMAT_NAMES)
|
||||
context->priv->UseLongFormatNames = TRUE;
|
||||
|
||||
if (generalFlags & CB_STREAM_FILECLIP_ENABLED)
|
||||
context->priv->StreamFileClipEnabled = TRUE;
|
||||
|
||||
if (generalFlags & CB_FILECLIP_NO_FILE_PATHS)
|
||||
context->priv->FileClipNoFilePaths = TRUE;
|
||||
|
||||
if (generalFlags & CB_CAN_LOCK_CLIPDATA)
|
||||
context->priv->CanLockClipData = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliprdr_wcslen(const WCHAR* str, const WCHAR* end)
|
||||
{
|
||||
WCHAR* p = (WCHAR*) str;
|
||||
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (p == end)
|
||||
return -1;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return (p - str);
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
int i;
|
||||
WCHAR* end;
|
||||
int length;
|
||||
int position;
|
||||
|
||||
position = Stream_GetPosition(s);
|
||||
end = (WCHAR*) &(Stream_Buffer(s)[Stream_Length(s)]);
|
||||
|
||||
winpr_HexDump(Stream_Buffer(s), Stream_Length(s));
|
||||
|
||||
context->priv->ClientFormatNameCount = 0;
|
||||
|
||||
while (Stream_GetRemainingLength(s) >= 6)
|
||||
{
|
||||
Stream_Seek(s, 4); /* formatId (4 bytes) */
|
||||
|
||||
length = cliprdr_wcslen((WCHAR*) Stream_Pointer(s), end);
|
||||
|
||||
if (length < 0)
|
||||
return -1;
|
||||
|
||||
Stream_Seek(s, (length + 1) * 2); /* wszFormatName */
|
||||
|
||||
context->priv->ClientFormatNameCount = 0;
|
||||
}
|
||||
|
||||
context->priv->ClientFormatNames = (CLIPRDR_FORMAT_NAME*)
|
||||
malloc(sizeof(CLIPRDR_FORMAT_NAME) * context->priv->ClientFormatNameCount);
|
||||
|
||||
Stream_SetPosition(s, position);
|
||||
|
||||
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
|
||||
{
|
||||
Stream_Read_UINT32(s, context->priv->ClientFormatNames[i].id); /* formatId (4 bytes) */
|
||||
|
||||
context->priv->ClientFormatNames[i].length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s),
|
||||
-1, &context->priv->ClientFormatNames[i].name, 0, NULL, NULL);
|
||||
|
||||
Stream_Seek(s, (context->priv->ClientFormatNames[i].length + 1) * 2);
|
||||
}
|
||||
|
||||
for (i = 0; i < context->priv->ClientFormatNameCount; i++)
|
||||
{
|
||||
printf("Format %d: Id: 0x%04X Name: %s\n", i,
|
||||
context->priv->ClientFormatNames[i].id,
|
||||
context->priv->ClientFormatNames[i].name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_short_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
printf("%s: unimplemented\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (context->priv->UseLongFormatNames)
|
||||
{
|
||||
status = cliprdr_server_receive_long_format_list(context, s, header);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = cliprdr_server_receive_short_format_list(context, s, header);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s)
|
||||
{
|
||||
CLIPRDR_HEADER header;
|
||||
|
||||
Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
|
||||
Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
|
||||
Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
|
||||
|
||||
printf("CliprdrServerReceivePdu: msgType: %d msgFlags: 0x%08X dataLen: %d\n",
|
||||
header.msgType, header.msgFlags, header.dataLen);
|
||||
|
||||
switch (header.msgType)
|
||||
{
|
||||
case CB_CLIP_CAPS:
|
||||
cliprdr_server_receive_capabilities(context, s, &header);
|
||||
break;
|
||||
|
||||
case CB_TEMP_DIRECTORY:
|
||||
break;
|
||||
|
||||
case CB_FORMAT_LIST:
|
||||
cliprdr_server_receive_format_list(context, s, &header);
|
||||
break;
|
||||
|
||||
case CB_FORMAT_LIST_RESPONSE:
|
||||
break;
|
||||
|
||||
case CB_LOCK_CLIPDATA:
|
||||
break;
|
||||
|
||||
case CB_UNLOCK_CLIPDATA:
|
||||
break;
|
||||
|
||||
case CB_FORMAT_DATA_REQUEST:
|
||||
break;
|
||||
|
||||
case CB_FORMAT_DATA_RESPONSE:
|
||||
break;
|
||||
|
||||
case CB_FILECONTENTS_REQUEST:
|
||||
break;
|
||||
|
||||
case CB_FILECONTENTS_RESPONSE:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unexpected clipboard PDU type: %d\n", header.msgType);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void* cliprdr_server_thread(void* arg)
|
||||
{
|
||||
wStream* s;
|
||||
@ -85,6 +322,9 @@ static void* cliprdr_server_thread(void* arg)
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
context->SendCapabilities(context);
|
||||
context->SendMonitorReady(context);
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
@ -97,17 +337,24 @@ static void* cliprdr_server_thread(void* arg)
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
if (BytesReturned == 0)
|
||||
if (!BytesReturned)
|
||||
break;
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, (int) BytesReturned);
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
|
||||
if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
|
||||
Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Seek(s, BytesReturned);
|
||||
}
|
||||
|
||||
Stream_SealLength(s);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
cliprdr_server_receive_pdu(context, s);
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
@ -164,6 +411,8 @@ CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
if (context->priv)
|
||||
{
|
||||
ZeroMemory(context->priv, sizeof(CliprdrServerPrivate));
|
||||
|
||||
context->priv->UseLongFormatNames = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,25 @@
|
||||
|
||||
#include <freerdp/server/cliprdr.h>
|
||||
|
||||
struct _CLIPRDR_HEADER
|
||||
{
|
||||
UINT16 msgType;
|
||||
UINT16 msgFlags;
|
||||
UINT32 dataLen;
|
||||
};
|
||||
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
|
||||
|
||||
struct _cliprdr_server_private
|
||||
{
|
||||
HANDLE Thread;
|
||||
HANDLE StopEvent;
|
||||
void* ChannelHandle;
|
||||
BOOL UseLongFormatNames;
|
||||
BOOL StreamFileClipEnabled;
|
||||
BOOL FileClipNoFilePaths;
|
||||
BOOL CanLockClipData;
|
||||
UINT32 ClientFormatNameCount;
|
||||
CLIPRDR_FORMAT_NAME* ClientFormatNames;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SERVER_CLIPRDR_MAIN_H */
|
||||
|
@ -474,8 +474,7 @@ void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
|
||||
}
|
||||
}
|
||||
|
||||
void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
|
||||
void** fds, int* fds_count)
|
||||
void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm, void** fds, int* fds_count)
|
||||
{
|
||||
void* fd;
|
||||
|
||||
@ -543,6 +542,11 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
|
||||
return result;
|
||||
}
|
||||
|
||||
HANDLE WTSVirtualChannelManagerGetEventHandle(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
return vcm->send_event;
|
||||
}
|
||||
|
||||
void* WTSVirtualChannelOpenEx(
|
||||
/* __in */ WTSVirtualChannelManager* vcm,
|
||||
/* __in */ const char* pVirtualName,
|
||||
@ -786,7 +790,7 @@ BOOL WTSVirtualChannelWrite(
|
||||
int first;
|
||||
UINT32 written;
|
||||
|
||||
if (channel == NULL)
|
||||
if (!channel)
|
||||
return FALSE;
|
||||
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
|
@ -60,6 +60,8 @@ FREERDP_API void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelMana
|
||||
void** fds, int* fds_count);
|
||||
FREERDP_API BOOL WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm);
|
||||
|
||||
FREERDP_API HANDLE WTSVirtualChannelManagerGetEventHandle(WTSVirtualChannelManager* vcm);
|
||||
|
||||
/**
|
||||
* Opens a static or dynamic virtual channel and return the handle. If the
|
||||
* operation fails, a NULL handle is returned.
|
||||
|
@ -54,6 +54,48 @@ struct _cliprdr_client_context
|
||||
#define CB_FORMAT_JPEG 0xD012
|
||||
#define CB_FORMAT_GIF 0xD013
|
||||
|
||||
/* CLIPRDR_HEADER.msgType */
|
||||
#define CB_MONITOR_READY 0x0001
|
||||
#define CB_FORMAT_LIST 0x0002
|
||||
#define CB_FORMAT_LIST_RESPONSE 0x0003
|
||||
#define CB_FORMAT_DATA_REQUEST 0x0004
|
||||
#define CB_FORMAT_DATA_RESPONSE 0x0005
|
||||
#define CB_TEMP_DIRECTORY 0x0006
|
||||
#define CB_CLIP_CAPS 0x0007
|
||||
#define CB_FILECONTENTS_REQUEST 0x0008
|
||||
#define CB_FILECONTENTS_RESPONSE 0x0009
|
||||
#define CB_LOCK_CLIPDATA 0x000A
|
||||
#define CB_UNLOCK_CLIPDATA 0x000B
|
||||
|
||||
/* CLIPRDR_HEADER.msgFlags */
|
||||
#define CB_RESPONSE_OK 0x0001
|
||||
#define CB_RESPONSE_FAIL 0x0002
|
||||
#define CB_ASCII_NAMES 0x0004
|
||||
|
||||
/* CLIPRDR_CAPS_SET.capabilitySetType */
|
||||
#define CB_CAPSTYPE_GENERAL 0x0001
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.lengthCapability */
|
||||
#define CB_CAPSTYPE_GENERAL_LEN 12
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.version */
|
||||
#define CB_CAPS_VERSION_1 0x00000001
|
||||
#define CB_CAPS_VERSION_2 0x00000002
|
||||
|
||||
/* CLIPRDR_GENERAL_CAPABILITY.generalFlags */
|
||||
#define CB_USE_LONG_FORMAT_NAMES 0x00000002
|
||||
#define CB_STREAM_FILECLIP_ENABLED 0x00000004
|
||||
#define CB_FILECLIP_NO_FILE_PATHS 0x00000008
|
||||
#define CB_CAN_LOCK_CLIPDATA 0x00000010
|
||||
|
||||
struct _CLIPRDR_FORMAT_NAME
|
||||
{
|
||||
UINT32 id;
|
||||
char* name;
|
||||
int length;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
|
||||
|
||||
/**
|
||||
* Clipboard Events
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user