23#include <freerdp/config.h>
25#include <winpr/wtypes.h>
26#include <winpr/assert.h>
28#include <winpr/print.h>
29#include <winpr/clipboard.h>
31#include <freerdp/types.h>
32#include <freerdp/constants.h>
33#include <freerdp/freerdp.h>
34#include <freerdp/client/cliprdr.h>
36#include "../../../channels/client/addin.h"
38#include "cliprdr_main.h"
39#include "cliprdr_format.h"
40#include "../cliprdr_common.h"
42const char type_FileGroupDescriptorW[] =
"FileGroupDescriptorW";
43const char type_FileContents[] =
"FileContents";
45CliprdrClientContext* cliprdr_get_client_interface(
cliprdrPlugin* cliprdr)
47 CliprdrClientContext* pInterface = NULL;
52 pInterface = (CliprdrClientContext*)cliprdr->channelEntryPoints.pInterface;
63 UINT status = CHANNEL_RC_OK;
65 WINPR_ASSERT(cliprdr);
68 const size_t pos = Stream_GetPosition(s);
69 const size_t dataLen = pos - 8;
70 WINPR_ASSERT(dataLen <= UINT32_MAX);
72 Stream_SetPosition(s, 4);
73 Stream_Write_UINT32(s, (UINT32)dataLen);
74 Stream_SetPosition(s, pos);
76 WLog_Print(cliprdr->log, WLOG_DEBUG,
"Cliprdr Sending (%" PRIu32
" bytes)", dataLen + 8);
80 status = CHANNEL_RC_BAD_INIT_HANDLE;
84 WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelWriteEx);
85 status = cliprdr->channelEntryPoints.pVirtualChannelWriteEx(
86 cliprdr->InitHandle, cliprdr->OpenHandle, Stream_Buffer(s),
87 (UINT32)Stream_GetPosition(s), s);
90 if (status != CHANNEL_RC_OK)
93 WLog_Print(cliprdr->log, WLOG_ERROR,
"VirtualChannelWrite failed with %s [%08" PRIX32
"]",
94 WTSErrorToString(status), status);
100UINT cliprdr_send_error_response(
cliprdrPlugin* cliprdr, UINT16 type)
102 wStream* s = cliprdr_packet_new(type, CB_RESPONSE_FAIL, 0);
105 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
106 return ERROR_OUTOFMEMORY;
109 return cliprdr_packet_send(cliprdr, s);
112static void cliprdr_print_general_capability_flags(wLog* log, UINT32 flags)
114 WLog_Print(log, WLOG_DEBUG,
"generalFlags (0x%08" PRIX32
") {", flags);
116 if (flags & CB_USE_LONG_FORMAT_NAMES)
117 WLog_Print(log, WLOG_DEBUG,
"\tCB_USE_LONG_FORMAT_NAMES");
119 if (flags & CB_STREAM_FILECLIP_ENABLED)
120 WLog_Print(log, WLOG_DEBUG,
"\tCB_STREAM_FILECLIP_ENABLED");
122 if (flags & CB_FILECLIP_NO_FILE_PATHS)
123 WLog_Print(log, WLOG_DEBUG,
"\tCB_FILECLIP_NO_FILE_PATHS");
125 if (flags & CB_CAN_LOCK_CLIPDATA)
126 WLog_Print(log, WLOG_DEBUG,
"\tCB_CAN_LOCK_CLIPDATA");
128 if (flags & CB_HUGE_FILE_SUPPORT_ENABLED)
129 WLog_Print(log, WLOG_DEBUG,
"\tCB_HUGE_FILE_SUPPORT_ENABLED");
131 WLog_Print(log, WLOG_DEBUG,
"}");
142 UINT32 generalFlags = 0;
145 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
146 UINT error = CHANNEL_RC_OK;
148 WINPR_ASSERT(cliprdr);
153 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_get_client_interface failed!");
154 return ERROR_INTERNAL_ERROR;
157 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, 8))
158 return ERROR_INVALID_DATA;
160 Stream_Read_UINT32(s, version);
161 Stream_Read_UINT32(s, generalFlags);
162 WLog_Print(cliprdr->log, WLOG_DEBUG,
"Version: %" PRIu32
"", version);
164 cliprdr_print_general_capability_flags(cliprdr->log, generalFlags);
166 cliprdr->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE;
167 cliprdr->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE;
168 cliprdr->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE;
169 cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE;
170 cliprdr->hasHugeFileSupport = (generalFlags & CB_HUGE_FILE_SUPPORT_ENABLED) ? TRUE : FALSE;
171 cliprdr->capabilitiesReceived = TRUE;
173 capabilities.common.msgType = CB_CLIP_CAPS;
174 capabilities.cCapabilitiesSets = 1;
176 generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
177 generalCapabilitySet.capabilitySetLength = 12;
178 generalCapabilitySet.version = version;
179 generalCapabilitySet.generalFlags = generalFlags;
180 IFCALLRET(context->ServerCapabilities, error, context, &capabilities);
183 WLog_Print(cliprdr->log, WLOG_ERROR,
"ServerCapabilities failed with error %" PRIu32
"!",
195 WINPR_ATTR_UNUSED UINT32 length,
196 WINPR_ATTR_UNUSED UINT16 flags)
198 UINT16 lengthCapability = 0;
199 UINT16 cCapabilitiesSets = 0;
200 UINT16 capabilitySetType = 0;
201 UINT error = CHANNEL_RC_OK;
203 WINPR_ASSERT(cliprdr);
206 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, 4))
207 return ERROR_INVALID_DATA;
209 Stream_Read_UINT16(s, cCapabilitiesSets);
210 Stream_Seek_UINT16(s);
211 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ServerCapabilities");
213 for (UINT16 index = 0; index < cCapabilitiesSets; index++)
215 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, 4))
216 return ERROR_INVALID_DATA;
218 Stream_Read_UINT16(s, capabilitySetType);
219 Stream_Read_UINT16(s, lengthCapability);
221 if ((lengthCapability < 4) ||
222 (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, lengthCapability - 4U)))
223 return ERROR_INVALID_DATA;
225 switch (capabilitySetType)
227 case CB_CAPSTYPE_GENERAL:
228 if ((error = cliprdr_process_general_capability(cliprdr, s)))
230 WLog_Print(cliprdr->log, WLOG_ERROR,
231 "cliprdr_process_general_capability failed with error %" PRIu32
"!",
239 WLog_Print(cliprdr->log, WLOG_ERROR,
"unknown cliprdr capability set: %" PRIu16
"",
241 return CHANNEL_RC_BAD_PROC;
254 UINT32 length, UINT16 flags)
257 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
258 UINT error = CHANNEL_RC_OK;
260 WINPR_ASSERT(cliprdr);
263 WLog_Print(cliprdr->log, WLOG_DEBUG,
"MonitorReady");
265 if (!cliprdr->capabilitiesReceived)
273 cliprdr->useLongFormatNames = FALSE;
274 cliprdr->streamFileClipEnabled = FALSE;
275 cliprdr->fileClipNoFilePaths = TRUE;
276 cliprdr->canLockClipData = FALSE;
279 monitorReady.common.msgType = CB_MONITOR_READY;
280 monitorReady.common.msgFlags = flags;
281 monitorReady.common.dataLen = length;
282 IFCALLRET(context->MonitorReady, error, context, &monitorReady);
285 WLog_Print(cliprdr->log, WLOG_ERROR,
"MonitorReady failed with error %" PRIu32
"!", error);
295static UINT cliprdr_process_filecontents_request(
cliprdrPlugin* cliprdr,
wStream* s, UINT32 length,
299 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
300 UINT error = CHANNEL_RC_OK;
302 WINPR_ASSERT(cliprdr);
305 WLog_Print(cliprdr->log, WLOG_DEBUG,
"FileContentsRequest");
307 request.common.msgType = CB_FILECONTENTS_REQUEST;
308 request.common.msgFlags = flags;
309 request.common.dataLen = length;
311 if ((error = cliprdr_read_file_contents_request(s, &request)))
316 if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0)
318 WLog_Print(cliprdr->log, WLOG_WARN,
"local -> remote file copy disabled, ignoring request");
319 return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
321 IFCALLRET(context->ServerFileContentsRequest, error, context, &request);
324 WLog_Print(cliprdr->log, WLOG_ERROR,
325 "ServerFileContentsRequest failed with error %" PRIu32
"!", error);
335static UINT cliprdr_process_filecontents_response(
cliprdrPlugin* cliprdr,
wStream* s, UINT32 length,
339 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
340 UINT error = CHANNEL_RC_OK;
342 WINPR_ASSERT(cliprdr);
345 WLog_Print(cliprdr->log, WLOG_DEBUG,
"FileContentsResponse");
347 response.common.msgType = CB_FILECONTENTS_RESPONSE;
348 response.common.msgFlags = flags;
349 response.common.dataLen = length;
351 if ((error = cliprdr_read_file_contents_response(s, &response)))
354 IFCALLRET(context->ServerFileContentsResponse, error, context, &response);
357 WLog_Print(cliprdr->log, WLOG_ERROR,
358 "ServerFileContentsResponse failed with error %" PRIu32
"!", error);
372 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
373 UINT error = CHANNEL_RC_OK;
375 WINPR_ASSERT(cliprdr);
378 WLog_Print(cliprdr->log, WLOG_DEBUG,
"LockClipData");
380 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, 4))
381 return ERROR_INVALID_DATA;
383 lockClipboardData.common.msgType = CB_LOCK_CLIPDATA;
384 lockClipboardData.common.msgFlags = flags;
385 lockClipboardData.common.dataLen = length;
386 Stream_Read_UINT32(s, lockClipboardData.clipDataId);
387 IFCALLRET(context->ServerLockClipboardData, error, context, &lockClipboardData);
390 WLog_Print(cliprdr->log, WLOG_ERROR,
391 "ServerLockClipboardData failed with error %" PRIu32
"!", error);
405 CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
406 UINT error = CHANNEL_RC_OK;
408 WINPR_ASSERT(cliprdr);
411 WLog_Print(cliprdr->log, WLOG_DEBUG,
"UnlockClipData");
413 if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData)))
416 unlockClipboardData.common.msgType = CB_UNLOCK_CLIPDATA;
417 unlockClipboardData.common.msgFlags = flags;
418 unlockClipboardData.common.dataLen = length;
420 IFCALLRET(context->ServerUnlockClipboardData, error, context, &unlockClipboardData);
423 WLog_Print(cliprdr->log, WLOG_ERROR,
424 "ServerUnlockClipboardData failed with error %" PRIu32
"!", error);
434static UINT cliprdr_order_recv(LPVOID userdata,
wStream* s)
442 WINPR_ASSERT(cliprdr);
445 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, 8))
446 return ERROR_INVALID_DATA;
448 Stream_Read_UINT16(s, msgType);
449 Stream_Read_UINT16(s, msgFlags);
450 Stream_Read_UINT32(s, dataLen);
452 if (!Stream_CheckAndLogRequiredLengthWLog(cliprdr->log, s, dataLen))
453 return ERROR_INVALID_DATA;
455 char buffer1[64] = { 0 };
456 char buffer2[64] = { 0 };
457 WLog_Print(cliprdr->log, WLOG_DEBUG,
458 "msgType: %s (%" PRIu16
"), msgFlags: %s dataLen: %" PRIu32
"",
459 CB_MSG_TYPE_STRING(msgType, buffer1,
sizeof(buffer1)), msgType,
460 CB_MSG_FLAGS_STRING(msgFlags, buffer2,
sizeof(buffer2)), dataLen);
465 if ((error = cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags)))
466 WLog_Print(cliprdr->log, WLOG_ERROR,
467 "cliprdr_process_clip_caps failed with error %" PRIu32
"!", error);
471 case CB_MONITOR_READY:
472 if ((error = cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags)))
473 WLog_Print(cliprdr->log, WLOG_ERROR,
474 "cliprdr_process_monitor_ready failed with error %" PRIu32
"!", error);
479 if ((error = cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags)))
480 WLog_Print(cliprdr->log, WLOG_ERROR,
481 "cliprdr_process_format_list failed with error %" PRIu32
"!", error);
485 case CB_FORMAT_LIST_RESPONSE:
486 if ((error = cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags)))
487 WLog_Print(cliprdr->log, WLOG_ERROR,
488 "cliprdr_process_format_list_response failed with error %" PRIu32
"!",
493 case CB_FORMAT_DATA_REQUEST:
494 if ((error = cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags)))
495 WLog_Print(cliprdr->log, WLOG_ERROR,
496 "cliprdr_process_format_data_request failed with error %" PRIu32
"!",
501 case CB_FORMAT_DATA_RESPONSE:
502 if ((error = cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags)))
503 WLog_Print(cliprdr->log, WLOG_ERROR,
504 "cliprdr_process_format_data_response failed with error %" PRIu32
"!",
509 case CB_FILECONTENTS_REQUEST:
510 if ((error = cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags)))
511 WLog_Print(cliprdr->log, WLOG_ERROR,
512 "cliprdr_process_filecontents_request failed with error %" PRIu32
"!",
517 case CB_FILECONTENTS_RESPONSE:
518 if ((error = cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags)))
519 WLog_Print(cliprdr->log, WLOG_ERROR,
520 "cliprdr_process_filecontents_response failed with error %" PRIu32
"!",
525 case CB_LOCK_CLIPDATA:
526 if ((error = cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags)))
527 WLog_Print(cliprdr->log, WLOG_ERROR,
528 "cliprdr_process_lock_clipdata failed with error %" PRIu32
"!", error);
532 case CB_UNLOCK_CLIPDATA:
533 if ((error = cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags)))
534 WLog_Print(cliprdr->log, WLOG_ERROR,
535 "cliprdr_process_unlock_clipdata failed with error %" PRIu32
"!", error);
540 error = CHANNEL_RC_BAD_PROC;
541 WLog_Print(cliprdr->log, WLOG_ERROR,
"unknown msgType %" PRIu16
"", msgType);
545 Stream_Free(s, TRUE);
558static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
566 WINPR_ASSERT(context);
569 WINPR_ASSERT(cliprdr);
571 s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
575 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
576 return ERROR_INTERNAL_ERROR;
579 Stream_Write_UINT16(s, 1);
580 Stream_Write_UINT16(s, 0);
582 Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType);
583 Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength);
584 Stream_Write_UINT32(s, generalCapabilitySet->version);
585 flags = generalCapabilitySet->generalFlags;
591 if (!cliprdr->useLongFormatNames)
592 flags &= (uint32_t)~CB_USE_LONG_FORMAT_NAMES;
593 if (!cliprdr->streamFileClipEnabled)
594 flags &= (uint32_t)~CB_STREAM_FILECLIP_ENABLED;
595 if (!cliprdr->fileClipNoFilePaths)
596 flags &= (uint32_t)~CB_FILECLIP_NO_FILE_PATHS;
597 if (!cliprdr->canLockClipData)
598 flags &= (uint32_t)~CB_CAN_LOCK_CLIPDATA;
599 if (!cliprdr->hasHugeFileSupport)
600 flags &= (uint32_t)~CB_HUGE_FILE_SUPPORT_ENABLED;
602 cliprdr->useLongFormatNames = (flags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE;
603 cliprdr->streamFileClipEnabled = (flags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE;
604 cliprdr->fileClipNoFilePaths = (flags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE;
605 cliprdr->canLockClipData = (flags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE;
606 cliprdr->hasHugeFileSupport = (flags & CB_HUGE_FILE_SUPPORT_ENABLED) ? TRUE : FALSE;
608 Stream_Write_UINT32(s, flags);
609 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientCapabilities");
611 cliprdr->initialFormatListSent = FALSE;
613 return cliprdr_packet_send(cliprdr, s);
621static UINT cliprdr_temp_directory(CliprdrClientContext* context,
627 WINPR_ASSERT(context);
628 WINPR_ASSERT(tempDirectory);
631 WINPR_ASSERT(cliprdr);
633 const size_t tmpDirCharLen =
sizeof(tempDirectory->szTempDir) /
sizeof(WCHAR);
634 s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, tmpDirCharLen *
sizeof(WCHAR));
638 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
639 return ERROR_INTERNAL_ERROR;
642 if (Stream_Write_UTF16_String_From_UTF8(s, tmpDirCharLen - 1, tempDirectory->szTempDir,
643 ARRAYSIZE(tempDirectory->szTempDir), TRUE) < 0)
645 Stream_Free(s, TRUE);
646 return ERROR_INTERNAL_ERROR;
650 Stream_Write_UINT16(s, 0);
652 WLog_Print(cliprdr->log, WLOG_DEBUG,
"TempDirectory: %s", tempDirectory->szTempDir);
653 return cliprdr_packet_send(cliprdr, s);
661static UINT cliprdr_client_format_list(CliprdrClientContext* context,
667 WINPR_ASSERT(context);
668 WINPR_ASSERT(formatList);
671 WINPR_ASSERT(cliprdr);
674 const UINT32 mask = CB_RESPONSE_OK | CB_RESPONSE_FAIL;
675 if ((formatList->common.msgFlags & mask) != 0)
676 WLog_Print(cliprdr->log, WLOG_WARN,
677 "Sending clipboard request with invalid flags msgFlags = 0x%08" PRIx32
678 ". Correct in your client!",
679 formatList->common.msgFlags & mask);
685 formatList, mask, CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES);
688 if ((filterList.numFormats == 0) && cliprdr->initialFormatListSent)
690 cliprdr_free_format_list(&filterList);
691 return CHANNEL_RC_OK;
693 cliprdr->initialFormatListSent = TRUE;
695 const uint32_t level = WLOG_DEBUG;
696 if (WLog_IsLevelActive(cliprdr->log, level))
698 WLog_Print(cliprdr->log, level,
"ClientFormatList: numFormats: %" PRIu32
"",
699 formatList->numFormats);
700 for (
size_t x = 0; x < filterList.numFormats; x++)
703 WLog_Print(cliprdr->log, level,
"[%" PRIu32
"]: id=0x%08" PRIx32
" [%s|%s]", x,
704 format->formatId, ClipboardGetFormatIdString(format->formatId),
709 s = cliprdr_packet_format_list_new(&filterList, cliprdr->useLongFormatNames, FALSE);
710 cliprdr_free_format_list(&filterList);
714 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_format_list_new failed!");
715 return ERROR_INTERNAL_ERROR;
718 return cliprdr_packet_send(cliprdr, s);
727cliprdr_client_format_list_response(CliprdrClientContext* context,
733 WINPR_ASSERT(context);
734 WINPR_ASSERT(formatListResponse);
737 WINPR_ASSERT(cliprdr);
739 s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, formatListResponse->common.msgFlags, 0);
743 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
744 return ERROR_INTERNAL_ERROR;
747 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientFormatListResponse");
748 return cliprdr_packet_send(cliprdr, s);
756static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context,
762 WINPR_ASSERT(context);
763 WINPR_ASSERT(lockClipboardData);
766 WINPR_ASSERT(cliprdr);
768 s = cliprdr_packet_lock_clipdata_new(lockClipboardData);
772 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_lock_clipdata_new failed!");
773 return ERROR_INTERNAL_ERROR;
776 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientLockClipboardData: clipDataId: 0x%08" PRIX32
"",
777 lockClipboardData->clipDataId);
778 return cliprdr_packet_send(cliprdr, s);
787cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context,
793 WINPR_ASSERT(context);
794 WINPR_ASSERT(unlockClipboardData);
797 WINPR_ASSERT(cliprdr);
799 s = cliprdr_packet_unlock_clipdata_new(unlockClipboardData);
803 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_unlock_clipdata_new failed!");
804 return ERROR_INTERNAL_ERROR;
807 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientUnlockClipboardData: clipDataId: 0x%08" PRIX32
"",
808 unlockClipboardData->clipDataId);
809 return cliprdr_packet_send(cliprdr, s);
817static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
820 WINPR_ASSERT(context);
821 WINPR_ASSERT(formatDataRequest);
824 WINPR_ASSERT(cliprdr);
828 if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0)
830 WLog_Print(cliprdr->log, WLOG_WARN,
"remote -> local copy disabled, ignoring request");
831 return CHANNEL_RC_OK;
834 wStream* s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
837 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
838 return ERROR_INTERNAL_ERROR;
841 Stream_Write_UINT32(s, formatDataRequest->requestedFormatId);
842 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientFormatDataRequest(0x%08" PRIx32
" [%s])",
843 formatDataRequest->requestedFormatId,
844 ClipboardGetFormatIdString(formatDataRequest->requestedFormatId));
845 return cliprdr_packet_send(cliprdr, s);
854cliprdr_client_format_data_response(CliprdrClientContext* context,
857 WINPR_ASSERT(context);
858 WINPR_ASSERT(formatDataResponse);
861 WINPR_ASSERT(cliprdr);
865 (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) != 0);
867 wStream* s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->common.msgFlags,
868 formatDataResponse->common.dataLen);
872 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_new failed!");
873 return ERROR_INTERNAL_ERROR;
876 Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->common.dataLen);
877 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientFormatDataResponse");
878 return cliprdr_packet_send(cliprdr, s);
887cliprdr_client_file_contents_request(CliprdrClientContext* context,
892 WINPR_ASSERT(context);
893 WINPR_ASSERT(fileContentsRequest);
897 return ERROR_INTERNAL_ERROR;
901 if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES) == 0)
903 WLog_Print(cliprdr->log, WLOG_WARN,
"remote -> local file copy disabled, ignoring request");
904 return CHANNEL_RC_OK;
907 if (!cliprdr->hasHugeFileSupport)
909 if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) >
911 return ERROR_INVALID_PARAMETER;
912 if (fileContentsRequest->nPositionHigh != 0)
913 return ERROR_INVALID_PARAMETER;
916 s = cliprdr_packet_file_contents_request_new(fileContentsRequest);
920 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_file_contents_request_new failed!");
921 return ERROR_INTERNAL_ERROR;
924 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientFileContentsRequest: streamId: 0x%08" PRIX32
"",
925 fileContentsRequest->streamId);
926 return cliprdr_packet_send(cliprdr, s);
935cliprdr_client_file_contents_response(CliprdrClientContext* context,
941 WINPR_ASSERT(context);
942 WINPR_ASSERT(fileContentsResponse);
945 WINPR_ASSERT(cliprdr);
949 if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES) == 0)
950 return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
952 s = cliprdr_packet_file_contents_response_new(fileContentsResponse);
956 WLog_Print(cliprdr->log, WLOG_ERROR,
"cliprdr_packet_file_contents_response_new failed!");
957 return ERROR_INTERNAL_ERROR;
960 WLog_Print(cliprdr->log, WLOG_DEBUG,
"ClientFileContentsResponse: streamId: 0x%08" PRIX32
"",
961 fileContentsResponse->streamId);
962 return cliprdr_packet_send(cliprdr, s);
965static VOID VCAPITYPE cliprdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
966 UINT event, LPVOID pData,
967 UINT32 dataLength, UINT32 totalLength,
970 UINT error = CHANNEL_RC_OK;
972 WINPR_ASSERT(cliprdr);
976 case CHANNEL_EVENT_DATA_RECEIVED:
977 if (cliprdr->OpenHandle != openHandle)
979 WLog_Print(cliprdr->log, WLOG_ERROR,
"error no match");
982 if ((error = channel_client_post_message(cliprdr->MsgsHandle, pData, dataLength,
983 totalLength, dataFlags)))
984 WLog_Print(cliprdr->log, WLOG_ERROR,
"failed with error %" PRIu32
"", error);
988 case CHANNEL_EVENT_WRITE_CANCELLED:
989 case CHANNEL_EVENT_WRITE_COMPLETE:
992 Stream_Free(s, TRUE);
996 case CHANNEL_EVENT_USER:
1002 if (error && cliprdr->context->rdpcontext)
1003 setChannelError(cliprdr->context->rdpcontext, error,
1004 "cliprdr_virtual_channel_open_event_ex reported an error");
1012static UINT cliprdr_virtual_channel_event_connected(
cliprdrPlugin* cliprdr,
1013 WINPR_ATTR_UNUSED LPVOID pData,
1014 WINPR_ATTR_UNUSED UINT32 dataLength)
1017 WINPR_ASSERT(cliprdr);
1018 WINPR_ASSERT(cliprdr->context);
1020 WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelOpenEx);
1021 status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx(
1022 cliprdr->InitHandle, &cliprdr->OpenHandle, cliprdr->channelDef.name,
1023 cliprdr_virtual_channel_open_event_ex);
1024 if (status != CHANNEL_RC_OK)
1027 cliprdr->MsgsHandle = channel_client_create_handler(
1028 cliprdr->context->rdpcontext, cliprdr, cliprdr_order_recv, CLIPRDR_SVC_CHANNEL_NAME);
1029 if (!cliprdr->MsgsHandle)
1030 return ERROR_INTERNAL_ERROR;
1040static UINT cliprdr_virtual_channel_event_disconnected(
cliprdrPlugin* cliprdr)
1044 WINPR_ASSERT(cliprdr);
1046 channel_client_quit_handler(cliprdr->MsgsHandle);
1047 cliprdr->MsgsHandle = NULL;
1049 if (cliprdr->OpenHandle == 0)
1050 return CHANNEL_RC_OK;
1052 WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelCloseEx);
1053 rc = cliprdr->channelEntryPoints.pVirtualChannelCloseEx(cliprdr->InitHandle,
1054 cliprdr->OpenHandle);
1056 if (CHANNEL_RC_OK != rc)
1058 WLog_Print(cliprdr->log, WLOG_ERROR,
"pVirtualChannelClose failed with %s [%08" PRIX32
"]",
1059 WTSErrorToString(rc), rc);
1063 cliprdr->OpenHandle = 0;
1065 return CHANNEL_RC_OK;
1073static UINT cliprdr_virtual_channel_event_terminated(
cliprdrPlugin* cliprdr)
1075 WINPR_ASSERT(cliprdr);
1077 cliprdr->InitHandle = 0;
1078 free(cliprdr->context);
1080 return CHANNEL_RC_OK;
1083static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1084 UINT event, LPVOID pData,
1087 UINT error = CHANNEL_RC_OK;
1089 WINPR_ASSERT(cliprdr);
1091 if (cliprdr->InitHandle != pInitHandle)
1093 WLog_Print(cliprdr->log, WLOG_ERROR,
"error no match");
1099 case CHANNEL_EVENT_CONNECTED:
1100 if ((error = cliprdr_virtual_channel_event_connected(cliprdr, pData, dataLength)))
1101 WLog_Print(cliprdr->log, WLOG_ERROR,
1102 "cliprdr_virtual_channel_event_connected failed with error %" PRIu32
"!",
1107 case CHANNEL_EVENT_DISCONNECTED:
1108 if ((error = cliprdr_virtual_channel_event_disconnected(cliprdr)))
1109 WLog_Print(cliprdr->log, WLOG_ERROR,
1110 "cliprdr_virtual_channel_event_disconnected failed with error %" PRIu32
1116 case CHANNEL_EVENT_TERMINATED:
1117 if ((error = cliprdr_virtual_channel_event_terminated(cliprdr)))
1118 WLog_Print(cliprdr->log, WLOG_ERROR,
1119 "cliprdr_virtual_channel_event_terminated failed with error %" PRIu32
1127 if (error && cliprdr->context->rdpcontext)
1128 setChannelError(cliprdr->context->rdpcontext, error,
1129 "cliprdr_virtual_channel_init_event reported an error");
1133#define VirtualChannelEntryEx cliprdr_VirtualChannelEntryEx
1135FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
1142 wLog* log = WLog_Get(CHANNELS_TAG(
"cliprdr.client"));
1147 WLog_Print(log, WLOG_ERROR,
"calloc failed!");
1152 cliprdr->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1153 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1154 (void)sprintf_s(cliprdr->channelDef.name, ARRAYSIZE(cliprdr->channelDef.name),
1155 CLIPRDR_SVC_CHANNEL_NAME);
1157 WINPR_ASSERT(pEntryPointsEx);
1160 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1162 CliprdrClientContext* context =
1163 (CliprdrClientContext*)calloc(1,
sizeof(CliprdrClientContext));
1167 WLog_Print(cliprdr->log, WLOG_ERROR,
"calloc failed!");
1172 context->handle = (
void*)cliprdr;
1173 context->custom = NULL;
1174 context->ClientCapabilities = cliprdr_client_capabilities;
1175 context->TempDirectory = cliprdr_temp_directory;
1176 context->ClientFormatList = cliprdr_client_format_list;
1177 context->ClientFormatListResponse = cliprdr_client_format_list_response;
1178 context->ClientLockClipboardData = cliprdr_client_lock_clipboard_data;
1179 context->ClientUnlockClipboardData = cliprdr_client_unlock_clipboard_data;
1180 context->ClientFormatDataRequest = cliprdr_client_format_data_request;
1181 context->ClientFormatDataResponse = cliprdr_client_format_data_response;
1182 context->ClientFileContentsRequest = cliprdr_client_file_contents_request;
1183 context->ClientFileContentsResponse = cliprdr_client_file_contents_response;
1184 cliprdr->context = context;
1185 context->rdpcontext = pEntryPointsEx->context;
1188 WLog_Print(cliprdr->log, WLOG_DEBUG,
"VirtualChannelEntryEx");
1189 CopyMemory(&(cliprdr->channelEntryPoints), pEntryPoints,
1191 cliprdr->InitHandle = pInitHandle;
1192 rc = cliprdr->channelEntryPoints.pVirtualChannelInitEx(
1193 cliprdr, cliprdr->context, pInitHandle, &cliprdr->channelDef, 1,
1194 VIRTUAL_CHANNEL_VERSION_WIN2000, cliprdr_virtual_channel_init_event_ex);
1196 if (CHANNEL_RC_OK != rc)
1198 WLog_Print(cliprdr->log, WLOG_ERROR,
"pVirtualChannelInit failed with %s [%08" PRIX32
"]",
1199 WTSErrorToString(rc), rc);
1200 free(cliprdr->context);
1205 cliprdr->channelEntryPoints.pInterface = cliprdr->context;
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.