diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 0ed0d20e9..8475b5c74 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -76,6 +77,11 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) Stream_Write_UINT32(s, dataLen); Stream_SetPosition(s, pos); +#ifdef WITH_DEBUG_CLIPRDR + printf("Cliprdr Sending (%d bytes)\n", dataLen + 8); + winpr_HexDump(Stream_Buffer(s), dataLen + 8); +#endif + svc_plugin_send((rdpSvcPlugin*) cliprdr, s); } @@ -206,6 +212,10 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d", CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); +#ifdef WITH_DEBUG_CLIPRDR + winpr_HexDump(Stream_Buffer(s), dataLen + 8); +#endif + switch (msgType) { case CB_CLIP_CAPS: diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index c8db646a1..5aef92961 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -40,6 +40,28 @@ * */ +/** + * 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 + * + */ + static int cliprdr_server_send_capabilities(CliprdrServerContext* context) { wStream* s; @@ -51,14 +73,14 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context) header.msgType = CB_CLIP_CAPS; header.msgFlags = 0; - header.dataLen = 24; + header.dataLen = 16; generalFlags = 0; if (context->priv->UseLongFormatNames) generalFlags |= CB_USE_LONG_FORMAT_NAMES; - s = Stream_New(NULL, header.dataLen); + s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH); Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */ Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */ @@ -91,9 +113,9 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context) header.msgType = CB_MONITOR_READY; header.msgFlags = 0; - header.dataLen = 8; + header.dataLen = 0; - s = Stream_New(NULL, header.dataLen); + s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH); Stream_Write_UINT16(s, header.msgType); /* msgType (2 bytes) */ Stream_Write_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */ @@ -110,6 +132,28 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context) static int cliprdr_server_send_format_list_response(CliprdrServerContext* context) { + wStream* s; + BOOL status; + CLIPRDR_HEADER header; + + printf("CliprdrServerSendFormatListResponse\n"); + + header.msgType = CB_FORMAT_LIST_RESPONSE; + header.msgFlags = CB_RESPONSE_OK; + header.dataLen = 0; + + s = Stream_New(NULL, header.dataLen + CLIPRDR_HEADER_LENGTH); + + 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; } @@ -163,6 +207,21 @@ int cliprdr_wcslen(const WCHAR* str, const WCHAR* end) return (p - str); } +static void cliprdr_free_format_list(UINT32 count, CLIPRDR_FORMAT_NAME* formatNames) +{ + int i; + + if (formatNames) + { + for (i = 0; i < count; i++) + { + free(formatNames[i].name); + } + + free(formatNames); + } +} + static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) { int i; @@ -171,11 +230,13 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context int position; position = Stream_GetPosition(s); - end = (WCHAR*) &(Stream_Buffer(s)[Stream_Length(s)]); - - winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); + Stream_SetPosition(s, Stream_Length(s)); + end = (WCHAR*) Stream_Pointer(s); + Stream_SetPosition(s, position); + cliprdr_free_format_list(context->priv->ClientFormatNameCount, context->priv->ClientFormatNames); context->priv->ClientFormatNameCount = 0; + context->priv->ClientFormatNames = NULL; while (Stream_GetRemainingLength(s) >= 6) { @@ -188,7 +249,7 @@ static int cliprdr_server_receive_long_format_list(CliprdrServerContext* context Stream_Seek(s, (length + 1) * 2); /* wszFormatName */ - context->priv->ClientFormatNameCount = 0; + context->priv->ClientFormatNameCount++; } context->priv->ClientFormatNames = (CLIPRDR_FORMAT_NAME*) @@ -235,31 +296,27 @@ static int cliprdr_server_receive_format_list(CliprdrServerContext* context, wSt status = cliprdr_server_receive_short_format_list(context, s, header); } + cliprdr_server_send_format_list_response(context); + return status; } -static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s) +static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) { - 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); + header->msgType, header->msgFlags, header->dataLen); - switch (header.msgType) + switch (header->msgType) { case CB_CLIP_CAPS: - cliprdr_server_receive_capabilities(context, s, &header); + 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); + cliprdr_server_receive_format_list(context, s, header); break; case CB_FORMAT_LIST_RESPONSE: @@ -284,7 +341,7 @@ static int cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s) break; default: - printf("Unexpected clipboard PDU type: %d\n", header.msgType); + printf("Unexpected clipboard PDU type: %d\n", header->msgType); break; } @@ -297,9 +354,11 @@ static void* cliprdr_server_thread(void* arg) DWORD status; DWORD nCount; void* buffer; + int position; HANDLE events[8]; HANDLE ChannelEvent; UINT32 BytesReturned; + CLIPRDR_HEADER header; CliprdrServerContext* context; context = (CliprdrServerContext*) arg; @@ -322,8 +381,8 @@ static void* cliprdr_server_thread(void* arg) events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; - context->SendCapabilities(context); - context->SendMonitorReady(context); + cliprdr_server_send_capabilities(context); + cliprdr_server_send_monitor_ready(context); while (1) { @@ -335,26 +394,36 @@ static void* cliprdr_server_thread(void* arg) } if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) + Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + { + if (BytesReturned) + Stream_Seek(s, BytesReturned); + } + else { - if (!BytesReturned) - break; - 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); + if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH) + { + position = Stream_GetPosition(s); + Stream_SetPosition(s, 0); - cliprdr_server_receive_pdu(context, s); + 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) */ + + Stream_SetPosition(s, position); + + if (Stream_GetPosition(s) >= (header.dataLen + CLIPRDR_HEADER_LENGTH)) + { + Stream_SealLength(s); + Stream_SetPosition(s, CLIPRDR_HEADER_LENGTH); + + cliprdr_server_receive_pdu(context, s, &header); + Stream_SetPosition(s, 0); + } + } } Stream_Free(s, TRUE); @@ -402,10 +471,6 @@ CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm) context->Start = cliprdr_server_start; context->Stop = cliprdr_server_stop; - context->SendCapabilities = cliprdr_server_send_capabilities; - context->SendMonitorReady = cliprdr_server_send_monitor_ready; - context->SendFormatListResponse = cliprdr_server_send_format_list_response; - context->priv = (CliprdrServerPrivate*) malloc(sizeof(CliprdrServerPrivate)); if (context->priv) @@ -413,6 +478,9 @@ CliprdrServerContext* cliprdr_server_context_new(WTSVirtualChannelManager* vcm) ZeroMemory(context->priv, sizeof(CliprdrServerPrivate)); context->priv->UseLongFormatNames = TRUE; + context->priv->StreamFileClipEnabled = TRUE; + context->priv->FileClipNoFilePaths = TRUE; + context->priv->CanLockClipData = TRUE; } } diff --git a/channels/cliprdr/server/cliprdr_main.h b/channels/cliprdr/server/cliprdr_main.h index b72902b64..ae6a85c24 100644 --- a/channels/cliprdr/server/cliprdr_main.h +++ b/channels/cliprdr/server/cliprdr_main.h @@ -26,6 +26,8 @@ #include +#define CLIPRDR_HEADER_LENGTH 8 + struct _CLIPRDR_HEADER { UINT16 msgType; @@ -39,10 +41,12 @@ struct _cliprdr_server_private HANDLE Thread; HANDLE StopEvent; void* ChannelHandle; + BOOL UseLongFormatNames; BOOL StreamFileClipEnabled; BOOL FileClipNoFilePaths; BOOL CanLockClipData; + UINT32 ClientFormatNameCount; CLIPRDR_FORMAT_NAME* ClientFormatNames; }; diff --git a/channels/server/channels.c b/channels/server/channels.c index 174df7f48..9ae0c08e5 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -749,7 +749,7 @@ BOOL WTSVirtualChannelRead( item = (wts_data_item*) list_peek(channel->receive_queue); - if (item == NULL) + if (!item) { ResetEvent(channel->receive_event); *pBytesRead = 0; @@ -771,7 +771,7 @@ BOOL WTSVirtualChannelRead( ReleaseMutex(channel->mutex); CopyMemory(Buffer, item->buffer, item->length); - wts_data_item_free(item) ; + wts_data_item_free(item); return TRUE; } diff --git a/include/freerdp/server/cliprdr.h b/include/freerdp/server/cliprdr.h index 01e612b70..946eb7652 100644 --- a/include/freerdp/server/cliprdr.h +++ b/include/freerdp/server/cliprdr.h @@ -35,10 +35,6 @@ typedef struct _cliprdr_server_private CliprdrServerPrivate; typedef int (*psCliprdrStart)(CliprdrServerContext* context); typedef int (*psCliprdrStop)(CliprdrServerContext* context); -typedef int (*psCliprdrSendCapabilities)(CliprdrServerContext* context); -typedef int (*psCliprdrSendMonitorReady)(CliprdrServerContext* context); -typedef int (*psCliprdrSendFormatListResponse)(CliprdrServerContext* context); - struct _cliprdr_server_context { WTSVirtualChannelManager* vcm; @@ -46,10 +42,6 @@ struct _cliprdr_server_context psCliprdrStart Start; psCliprdrStop Stop; - psCliprdrSendCapabilities SendCapabilities; - psCliprdrSendMonitorReady SendMonitorReady; - psCliprdrSendFormatListResponse SendFormatListResponse; - CliprdrServerPrivate* priv; };