FreeRDP
Loading...
Searching...
No Matches
server/cliprdr_main.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/assert.h>
26#include <winpr/print.h>
27#include <winpr/stream.h>
28
29#include <freerdp/freerdp.h>
30#include <freerdp/channels/log.h>
31#include "cliprdr_main.h"
32#include "../cliprdr_common.h"
33
79static UINT cliprdr_server_packet_send(CliprdrServerPrivate* cliprdr, wStream* s)
80{
81 UINT rc = 0;
82 size_t pos = 0;
83 BOOL status = 0;
84 UINT32 dataLen = 0;
85 ULONG written = 0;
86
87 WINPR_ASSERT(cliprdr);
88
89 pos = Stream_GetPosition(s);
90 if ((pos < 8) || (pos > UINT32_MAX))
91 {
92 rc = ERROR_NO_DATA;
93 goto fail;
94 }
95
96 dataLen = (UINT32)(pos - 8);
97 Stream_SetPosition(s, 4);
98 Stream_Write_UINT32(s, dataLen);
99
100 WINPR_ASSERT(pos <= UINT32_MAX);
101 status = WTSVirtualChannelWrite(cliprdr->ChannelHandle, Stream_BufferAs(s, char), (UINT32)pos,
102 &written);
103 rc = status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
104fail:
105 Stream_Free(s, TRUE);
106 return rc;
107}
108
114static UINT cliprdr_server_capabilities(CliprdrServerContext* context,
115 const CLIPRDR_CAPABILITIES* capabilities)
116{
117 size_t offset = 0;
118
119 WINPR_ASSERT(context);
120 WINPR_ASSERT(capabilities);
121
122 CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle;
123
124 if (capabilities->common.msgType != CB_CLIP_CAPS)
125 WLog_WARN(TAG, "called with invalid type %08" PRIx32, capabilities->common.msgType);
126
127 if (capabilities->cCapabilitiesSets > UINT16_MAX)
128 {
129 WLog_ERR(TAG, "Invalid number of capability sets in clipboard caps");
130 return ERROR_INVALID_PARAMETER;
131 }
132
133 wStream* s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
134
135 if (!s)
136 {
137 WLog_ERR(TAG, "cliprdr_packet_new failed!");
138 return ERROR_INTERNAL_ERROR;
139 }
140
141 Stream_Write_UINT16(s,
142 (UINT16)capabilities->cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
143 Stream_Write_UINT16(s, 0); /* pad1 (2 bytes) */
144 for (UINT32 x = 0; x < capabilities->cCapabilitiesSets; x++)
145 {
146 const CLIPRDR_CAPABILITY_SET* cap =
147 (const CLIPRDR_CAPABILITY_SET*)(((const BYTE*)capabilities->capabilitySets) + offset);
148 offset += cap->capabilitySetLength;
149
150 switch (cap->capabilitySetType)
151 {
152 case CB_CAPSTYPE_GENERAL:
153 {
154 const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet =
156 Stream_Write_UINT16(
157 s, generalCapabilitySet->capabilitySetType); /* capabilitySetType (2 bytes) */
158 Stream_Write_UINT16(
159 s, generalCapabilitySet->capabilitySetLength); /* lengthCapability (2 bytes) */
160 Stream_Write_UINT32(s, generalCapabilitySet->version); /* version (4 bytes) */
161 Stream_Write_UINT32(
162 s, generalCapabilitySet->generalFlags); /* generalFlags (4 bytes) */
163 }
164 break;
165
166 default:
167 WLog_WARN(TAG, "Unknown capability set type %08" PRIx16, cap->capabilitySetType);
168 if (!Stream_SafeSeek(s, cap->capabilitySetLength))
169 {
170 WLog_ERR(TAG, "short stream");
171 Stream_Free(s, TRUE);
172 return ERROR_NO_DATA;
173 }
174 break;
175 }
176 }
177 WLog_DBG(TAG, "ServerCapabilities");
178 return cliprdr_server_packet_send(cliprdr, s);
179}
180
186static UINT cliprdr_server_monitor_ready(CliprdrServerContext* context,
187 const CLIPRDR_MONITOR_READY* monitorReady)
188{
189 wStream* s = nullptr;
190 CliprdrServerPrivate* cliprdr = nullptr;
191
192 WINPR_ASSERT(context);
193 WINPR_ASSERT(monitorReady);
194
195 cliprdr = (CliprdrServerPrivate*)context->handle;
196
197 if (monitorReady->common.msgType != CB_MONITOR_READY)
198 WLog_WARN(TAG, "called with invalid type %08" PRIx32, monitorReady->common.msgType);
199
200 s = cliprdr_packet_new(CB_MONITOR_READY, monitorReady->common.msgFlags,
201 monitorReady->common.dataLen);
202
203 if (!s)
204 {
205 WLog_ERR(TAG, "cliprdr_packet_new failed!");
206 return ERROR_INTERNAL_ERROR;
207 }
208
209 WLog_DBG(TAG, "ServerMonitorReady");
210 return cliprdr_server_packet_send(cliprdr, s);
211}
212
218static UINT cliprdr_server_format_list(CliprdrServerContext* context,
219 const CLIPRDR_FORMAT_LIST* formatList)
220{
221 wStream* s = nullptr;
222 CliprdrServerPrivate* cliprdr = nullptr;
223
224 WINPR_ASSERT(context);
225 WINPR_ASSERT(formatList);
226
227 cliprdr = (CliprdrServerPrivate*)context->handle;
228
229 s = cliprdr_packet_format_list_new(formatList, context->useLongFormatNames, FALSE);
230 if (!s)
231 {
232 WLog_ERR(TAG, "cliprdr_packet_format_list_new failed!");
233 return ERROR_INTERNAL_ERROR;
234 }
235
236 WLog_DBG(TAG, "ServerFormatList: numFormats: %" PRIu32 "", formatList->numFormats);
237 return cliprdr_server_packet_send(cliprdr, s);
238}
239
245static UINT
246cliprdr_server_format_list_response(CliprdrServerContext* context,
247 const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
248{
249 wStream* s = nullptr;
250 CliprdrServerPrivate* cliprdr = nullptr;
251
252 WINPR_ASSERT(context);
253 WINPR_ASSERT(formatListResponse);
254
255 cliprdr = (CliprdrServerPrivate*)context->handle;
256 if (formatListResponse->common.msgType != CB_FORMAT_LIST_RESPONSE)
257 WLog_WARN(TAG, "called with invalid type %08" PRIx32, formatListResponse->common.msgType);
258
259 s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, formatListResponse->common.msgFlags,
260 formatListResponse->common.dataLen);
261
262 if (!s)
263 {
264 WLog_ERR(TAG, "cliprdr_packet_new failed!");
265 return ERROR_INTERNAL_ERROR;
266 }
267
268 WLog_DBG(TAG, "ServerFormatListResponse");
269 return cliprdr_server_packet_send(cliprdr, s);
270}
271
277static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context,
278 const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
279{
280 wStream* s = nullptr;
281 CliprdrServerPrivate* cliprdr = nullptr;
282
283 WINPR_ASSERT(context);
284 WINPR_ASSERT(lockClipboardData);
285
286 cliprdr = (CliprdrServerPrivate*)context->handle;
287 if (lockClipboardData->common.msgType != CB_LOCK_CLIPDATA)
288 WLog_WARN(TAG, "called with invalid type %08" PRIx32, lockClipboardData->common.msgType);
289
290 s = cliprdr_packet_lock_clipdata_new(lockClipboardData);
291 if (!s)
292 {
293 WLog_ERR(TAG, "cliprdr_packet_lock_clipdata_new failed!");
294 return ERROR_INTERNAL_ERROR;
295 }
296
297 WLog_DBG(TAG, "ServerLockClipboardData: clipDataId: 0x%08" PRIX32 "",
298 lockClipboardData->clipDataId);
299 return cliprdr_server_packet_send(cliprdr, s);
300}
301
307static UINT
308cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context,
309 const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
310{
311 wStream* s = nullptr;
312 CliprdrServerPrivate* cliprdr = nullptr;
313
314 WINPR_ASSERT(context);
315 WINPR_ASSERT(unlockClipboardData);
316
317 cliprdr = (CliprdrServerPrivate*)context->handle;
318 if (unlockClipboardData->common.msgType != CB_UNLOCK_CLIPDATA)
319 WLog_WARN(TAG, "called with invalid type %08" PRIx32, unlockClipboardData->common.msgType);
320
321 s = cliprdr_packet_unlock_clipdata_new(unlockClipboardData);
322
323 if (!s)
324 {
325 WLog_ERR(TAG, "cliprdr_packet_unlock_clipdata_new failed!");
326 return ERROR_INTERNAL_ERROR;
327 }
328
329 WLog_DBG(TAG, "ServerUnlockClipboardData: clipDataId: 0x%08" PRIX32 "",
330 unlockClipboardData->clipDataId);
331 return cliprdr_server_packet_send(cliprdr, s);
332}
333
339static UINT cliprdr_server_format_data_request(CliprdrServerContext* context,
340 const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
341{
342 wStream* s = nullptr;
343 CliprdrServerPrivate* cliprdr = nullptr;
344
345 WINPR_ASSERT(context);
346 WINPR_ASSERT(formatDataRequest);
347
348 cliprdr = (CliprdrServerPrivate*)context->handle;
349 if (formatDataRequest->common.msgType != CB_FORMAT_DATA_REQUEST)
350 WLog_WARN(TAG, "called with invalid type %08" PRIx32, formatDataRequest->common.msgType);
351
352 s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, formatDataRequest->common.msgFlags,
353 formatDataRequest->common.dataLen);
354
355 if (!s)
356 {
357 WLog_ERR(TAG, "cliprdr_packet_new failed!");
358 return ERROR_INTERNAL_ERROR;
359 }
360
361 Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
362 WLog_DBG(TAG, "ClientFormatDataRequest");
363 return cliprdr_server_packet_send(cliprdr, s);
364}
365
371static UINT
372cliprdr_server_format_data_response(CliprdrServerContext* context,
373 const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
374{
375 wStream* s = nullptr;
376 CliprdrServerPrivate* cliprdr = nullptr;
377
378 WINPR_ASSERT(context);
379 WINPR_ASSERT(formatDataResponse);
380
381 cliprdr = (CliprdrServerPrivate*)context->handle;
382
383 if (formatDataResponse->common.msgType != CB_FORMAT_DATA_RESPONSE)
384 WLog_WARN(TAG, "called with invalid type %08" PRIx32, formatDataResponse->common.msgType);
385
386 s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->common.msgFlags,
387 formatDataResponse->common.dataLen);
388
389 if (!s)
390 {
391 WLog_ERR(TAG, "cliprdr_packet_new failed!");
392 return ERROR_INTERNAL_ERROR;
393 }
394
395 Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->common.dataLen);
396 WLog_DBG(TAG, "ServerFormatDataResponse");
397 return cliprdr_server_packet_send(cliprdr, s);
398}
399
405static UINT
406cliprdr_server_file_contents_request(CliprdrServerContext* context,
407 const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
408{
409 wStream* s = nullptr;
410 CliprdrServerPrivate* cliprdr = nullptr;
411
412 WINPR_ASSERT(context);
413 WINPR_ASSERT(fileContentsRequest);
414
415 cliprdr = (CliprdrServerPrivate*)context->handle;
416
417 if (fileContentsRequest->common.msgType != CB_FILECONTENTS_REQUEST)
418 WLog_WARN(TAG, "called with invalid type %08" PRIx32, fileContentsRequest->common.msgType);
419
420 s = cliprdr_packet_file_contents_request_new(fileContentsRequest);
421 if (!s)
422 {
423 WLog_ERR(TAG, "cliprdr_packet_file_contents_request_new failed!");
424 return ERROR_INTERNAL_ERROR;
425 }
426
427 WLog_DBG(TAG, "ServerFileContentsRequest: streamId: 0x%08" PRIX32 "",
428 fileContentsRequest->streamId);
429 return cliprdr_server_packet_send(cliprdr, s);
430}
431
437static UINT
438cliprdr_server_file_contents_response(CliprdrServerContext* context,
439 const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
440{
441 wStream* s = nullptr;
442 CliprdrServerPrivate* cliprdr = nullptr;
443
444 WINPR_ASSERT(context);
445 WINPR_ASSERT(fileContentsResponse);
446
447 cliprdr = (CliprdrServerPrivate*)context->handle;
448
449 if (fileContentsResponse->common.msgType != CB_FILECONTENTS_RESPONSE)
450 WLog_WARN(TAG, "called with invalid type %08" PRIx32, fileContentsResponse->common.msgType);
451
452 s = cliprdr_packet_file_contents_response_new(fileContentsResponse);
453 if (!s)
454 {
455 WLog_ERR(TAG, "cliprdr_packet_file_contents_response_new failed!");
456 return ERROR_INTERNAL_ERROR;
457 }
458
459 WLog_DBG(TAG, "ServerFileContentsResponse: streamId: 0x%08" PRIX32 "",
460 fileContentsResponse->streamId);
461 return cliprdr_server_packet_send(cliprdr, s);
462}
463
469static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* context, wStream* s,
471{
472 WINPR_ASSERT(context);
473 WINPR_ASSERT(cap_set);
474
475 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
476 return ERROR_INVALID_DATA;
477
478 Stream_Read_UINT32(s, cap_set->version); /* version (4 bytes) */
479 Stream_Read_UINT32(s, cap_set->generalFlags); /* generalFlags (4 bytes) */
480
481 if (context->useLongFormatNames)
482 context->useLongFormatNames = (cap_set->generalFlags & CB_USE_LONG_FORMAT_NAMES) != 0;
483
484 if (context->streamFileClipEnabled)
485 context->streamFileClipEnabled = (cap_set->generalFlags & CB_STREAM_FILECLIP_ENABLED) != 0;
486
487 if (context->fileClipNoFilePaths)
488 context->fileClipNoFilePaths = (cap_set->generalFlags & CB_FILECLIP_NO_FILE_PATHS) != 0;
489
490 if (context->canLockClipData)
491 context->canLockClipData = (cap_set->generalFlags & CB_CAN_LOCK_CLIPDATA) != 0;
492
493 if (context->hasHugeFileSupport)
494 context->hasHugeFileSupport = (cap_set->generalFlags & CB_HUGE_FILE_SUPPORT_ENABLED) != 0;
495
496 return CHANNEL_RC_OK;
497}
498
504static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s,
505 const CLIPRDR_HEADER* header)
506{
507 UINT16 capabilitySetType = 0;
508 UINT16 capabilitySetLength = 0;
509 UINT error = ERROR_INVALID_DATA;
510 size_t cap_sets_size = 0;
511 CLIPRDR_CAPABILITIES capabilities = WINPR_C_ARRAY_INIT;
512 CLIPRDR_CAPABILITY_SET* capSet = nullptr;
513
514 WINPR_ASSERT(context);
515 WINPR_UNUSED(header);
516
517 WLog_DBG(TAG, "CliprdrClientCapabilities");
518 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
519 return ERROR_INVALID_DATA;
520
521 Stream_Read_UINT16(s, capabilities.cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
522 Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
523
524 for (size_t index = 0; index < capabilities.cCapabilitiesSets; index++)
525 {
526 void* tmp = nullptr;
527 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
528 goto out;
529 Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
530 Stream_Read_UINT16(s, capabilitySetLength); /* capabilitySetLength (2 bytes) */
531
532 cap_sets_size += capabilitySetLength;
533
534 if (cap_sets_size > 0)
535 tmp = realloc(capabilities.capabilitySets, cap_sets_size);
536 if (tmp == nullptr)
537 {
538 WLog_ERR(TAG, "capabilities.capabilitySets realloc failed!");
539 free(capabilities.capabilitySets);
540 return CHANNEL_RC_NO_MEMORY;
541 }
542
543 capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)tmp;
544
545 capSet = &(capabilities.capabilitySets[index]);
546
547 capSet->capabilitySetType = capabilitySetType;
548 capSet->capabilitySetLength = capabilitySetLength;
549
550 switch (capSet->capabilitySetType)
551 {
552 case CB_CAPSTYPE_GENERAL:
553 error = cliprdr_server_receive_general_capability(
554 context, s, (CLIPRDR_GENERAL_CAPABILITY_SET*)capSet);
555 if (error)
556 {
557 WLog_ERR(TAG,
558 "cliprdr_server_receive_general_capability failed with error %" PRIu32
559 "",
560 error);
561 goto out;
562 }
563 break;
564
565 default:
566 WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "",
567 capSet->capabilitySetType);
568 goto out;
569 }
570 }
571
572 error = CHANNEL_RC_OK;
573 IFCALLRET(context->ClientCapabilities, error, context, &capabilities);
574out:
575 free(capabilities.capabilitySets);
576 return error;
577}
578
584static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* context, wStream* s,
585 const CLIPRDR_HEADER* header)
586{
587 size_t length = 0;
588 CLIPRDR_TEMP_DIRECTORY tempDirectory = WINPR_C_ARRAY_INIT;
589 CliprdrServerPrivate* cliprdr = nullptr;
590 UINT error = CHANNEL_RC_OK;
591
592 WINPR_ASSERT(context);
593 WINPR_UNUSED(header);
594
595 cliprdr = (CliprdrServerPrivate*)context->handle;
596 WINPR_ASSERT(cliprdr);
597
598 if (!Stream_CheckAndLogRequiredLength(TAG, s,
599 ARRAYSIZE(cliprdr->temporaryDirectory) * sizeof(WCHAR)))
600 return CHANNEL_RC_NO_MEMORY;
601
602 const WCHAR* wszTempDir = Stream_ConstPointer(s);
603
604 if (wszTempDir[ARRAYSIZE(cliprdr->temporaryDirectory) - 1] != 0)
605 {
606 WLog_ERR(TAG, "wszTempDir[259] was not 0");
607 return ERROR_INVALID_DATA;
608 }
609
610 if (ConvertWCharNToUtf8(wszTempDir, ARRAYSIZE(cliprdr->temporaryDirectory),
611 cliprdr->temporaryDirectory,
612 ARRAYSIZE(cliprdr->temporaryDirectory)) < 0)
613 {
614 WLog_ERR(TAG, "failed to convert temporary directory name");
615 return ERROR_INVALID_DATA;
616 }
617
618 length = strnlen(cliprdr->temporaryDirectory, ARRAYSIZE(cliprdr->temporaryDirectory));
619
620 if (length >= ARRAYSIZE(cliprdr->temporaryDirectory))
621 length = ARRAYSIZE(cliprdr->temporaryDirectory) - 1;
622
623 CopyMemory(tempDirectory.szTempDir, cliprdr->temporaryDirectory, length);
624 tempDirectory.szTempDir[length] = '\0';
625 WLog_DBG(TAG, "CliprdrTemporaryDirectory: %s", cliprdr->temporaryDirectory);
626 IFCALLRET(context->TempDirectory, error, context, &tempDirectory);
627
628 if (error)
629 WLog_ERR(TAG, "TempDirectory failed with error %" PRIu32 "!", error);
630
631 return error;
632}
633
639static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s,
640 const CLIPRDR_HEADER* header)
641{
642 CLIPRDR_FORMAT_LIST formatList = WINPR_C_ARRAY_INIT;
643 UINT error = CHANNEL_RC_OK;
644
645 WINPR_ASSERT(context);
646 WINPR_ASSERT(header);
647
648 formatList.common.msgType = CB_FORMAT_LIST;
649 formatList.common.msgFlags = header->msgFlags;
650 formatList.common.dataLen = header->dataLen;
651
652 wLog* log = WLog_Get(TAG);
653 if ((error = cliprdr_read_format_list(log, s, &formatList, context->useLongFormatNames)))
654 goto out;
655
656 WLog_Print(log, WLOG_DEBUG, "ClientFormatList: numFormats: %" PRIu32 "", formatList.numFormats);
657 IFCALLRET(context->ClientFormatList, error, context, &formatList);
658
659 if (error)
660 WLog_Print(log, WLOG_ERROR, "ClientFormatList failed with error %" PRIu32 "!", error);
661
662out:
663 cliprdr_free_format_list(&formatList);
664 return error;
665}
666
672static UINT cliprdr_server_receive_format_list_response(CliprdrServerContext* context, wStream* s,
673 const CLIPRDR_HEADER* header)
674{
675 CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = WINPR_C_ARRAY_INIT;
676 UINT error = CHANNEL_RC_OK;
677
678 WINPR_ASSERT(context);
679 WINPR_ASSERT(header);
680
681 WINPR_UNUSED(s);
682 WLog_DBG(TAG, "CliprdrClientFormatListResponse");
683 formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
684 formatListResponse.common.msgFlags = header->msgFlags;
685 formatListResponse.common.dataLen = header->dataLen;
686 IFCALLRET(context->ClientFormatListResponse, error, context, &formatListResponse);
687
688 if (error)
689 WLog_ERR(TAG, "ClientFormatListResponse failed with error %" PRIu32 "!", error);
690
691 return error;
692}
693
699static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, wStream* s,
700 const CLIPRDR_HEADER* header)
701{
702 CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData = WINPR_C_ARRAY_INIT;
703 UINT error = CHANNEL_RC_OK;
704
705 WINPR_ASSERT(context);
706 WINPR_ASSERT(header);
707
708 WLog_DBG(TAG, "CliprdrClientLockClipData");
709
710 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
711 return ERROR_INVALID_DATA;
712
713 lockClipboardData.common.msgType = CB_LOCK_CLIPDATA;
714 lockClipboardData.common.msgFlags = header->msgFlags;
715 lockClipboardData.common.dataLen = header->dataLen;
716 Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */
717 IFCALLRET(context->ClientLockClipboardData, error, context, &lockClipboardData);
718
719 if (error)
720 WLog_ERR(TAG, "ClientLockClipboardData failed with error %" PRIu32 "!", error);
721
722 return error;
723}
724
730static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* context, wStream* s,
731 const CLIPRDR_HEADER* header)
732{
733 CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData = WINPR_C_ARRAY_INIT;
734 UINT error = CHANNEL_RC_OK;
735
736 WINPR_ASSERT(context);
737 WINPR_ASSERT(header);
738
739 WLog_DBG(TAG, "CliprdrClientUnlockClipData");
740
741 unlockClipboardData.common.msgType = CB_UNLOCK_CLIPDATA;
742 unlockClipboardData.common.msgFlags = header->msgFlags;
743 unlockClipboardData.common.dataLen = header->dataLen;
744
745 if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData)))
746 return error;
747
748 IFCALLRET(context->ClientUnlockClipboardData, error, context, &unlockClipboardData);
749
750 if (error)
751 WLog_ERR(TAG, "ClientUnlockClipboardData failed with error %" PRIu32 "!", error);
752
753 return error;
754}
755
761static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* context, wStream* s,
762 const CLIPRDR_HEADER* header)
763{
764 CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = WINPR_C_ARRAY_INIT;
765 UINT error = CHANNEL_RC_OK;
766
767 WINPR_ASSERT(context);
768 WINPR_ASSERT(header);
769
770 WLog_DBG(TAG, "CliprdrClientFormatDataRequest");
771 formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
772 formatDataRequest.common.msgFlags = header->msgFlags;
773 formatDataRequest.common.dataLen = header->dataLen;
774
775 if ((error = cliprdr_read_format_data_request(s, &formatDataRequest)))
776 return error;
777
778 context->lastRequestedFormatId = formatDataRequest.requestedFormatId;
779 IFCALLRET(context->ClientFormatDataRequest, error, context, &formatDataRequest);
780
781 if (error)
782 WLog_ERR(TAG, "ClientFormatDataRequest failed with error %" PRIu32 "!", error);
783
784 return error;
785}
786
792static UINT cliprdr_server_receive_format_data_response(CliprdrServerContext* context, wStream* s,
793 const CLIPRDR_HEADER* header)
794{
795 CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse = WINPR_C_ARRAY_INIT;
796 UINT error = CHANNEL_RC_OK;
797
798 WINPR_ASSERT(context);
799 WINPR_ASSERT(header);
800
801 WLog_DBG(TAG, "CliprdrClientFormatDataResponse");
802 formatDataResponse.common.msgType = CB_FORMAT_DATA_RESPONSE;
803 formatDataResponse.common.msgFlags = header->msgFlags;
804 formatDataResponse.common.dataLen = header->dataLen;
805
806 if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
807 return error;
808
809 IFCALLRET(context->ClientFormatDataResponse, error, context, &formatDataResponse);
810
811 if (error)
812 WLog_ERR(TAG, "ClientFormatDataResponse failed with error %" PRIu32 "!", error);
813
814 return error;
815}
816
822static UINT cliprdr_server_receive_filecontents_request(CliprdrServerContext* context, wStream* s,
823 const CLIPRDR_HEADER* header)
824{
825 CLIPRDR_FILE_CONTENTS_REQUEST request = WINPR_C_ARRAY_INIT;
826 UINT error = CHANNEL_RC_OK;
827
828 WINPR_ASSERT(context);
829 WINPR_ASSERT(header);
830
831 WLog_DBG(TAG, "CliprdrClientFileContentsRequest");
832 request.common.msgType = CB_FILECONTENTS_REQUEST;
833 request.common.msgFlags = header->msgFlags;
834 request.common.dataLen = header->dataLen;
835
836 if ((error = cliprdr_read_file_contents_request(s, &request)))
837 return error;
838
839 if (!context->hasHugeFileSupport)
840 {
841 if (request.nPositionHigh > 0)
842 return ERROR_INVALID_DATA;
843 if ((UINT64)request.nPositionLow + request.cbRequested > UINT32_MAX)
844 return ERROR_INVALID_DATA;
845 }
846 IFCALLRET(context->ClientFileContentsRequest, error, context, &request);
847
848 if (error)
849 WLog_ERR(TAG, "ClientFileContentsRequest failed with error %" PRIu32 "!", error);
850
851 return error;
852}
853
859static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* context, wStream* s,
860 const CLIPRDR_HEADER* header)
861{
862 CLIPRDR_FILE_CONTENTS_RESPONSE response = WINPR_C_ARRAY_INIT;
863 UINT error = CHANNEL_RC_OK;
864
865 WINPR_ASSERT(context);
866 WINPR_ASSERT(header);
867
868 WLog_DBG(TAG, "CliprdrClientFileContentsResponse");
869
870 response.common.msgType = CB_FILECONTENTS_RESPONSE;
871 response.common.msgFlags = header->msgFlags;
872 response.common.dataLen = header->dataLen;
873
874 if ((error = cliprdr_read_file_contents_response(s, &response)))
875 return error;
876
877 IFCALLRET(context->ClientFileContentsResponse, error, context, &response);
878
879 if (error)
880 WLog_ERR(TAG, "ClientFileContentsResponse failed with error %" PRIu32 "!", error);
881
882 return error;
883}
884
890static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s,
891 const CLIPRDR_HEADER* header)
892{
893 UINT error = 0;
894
895 WINPR_ASSERT(context);
896 WINPR_ASSERT(header);
897
898 char buffer1[64] = WINPR_C_ARRAY_INIT;
899 char buffer2[64] = WINPR_C_ARRAY_INIT;
900 WLog_DBG(TAG, "CliprdrServerReceivePdu: msgType: %s, msgFlags: %s dataLen: %" PRIu32 "",
901 CB_MSG_TYPE_STRING(header->msgType, buffer1, sizeof(buffer1)),
902 CB_MSG_FLAGS_STRING(header->msgFlags, buffer2, sizeof(buffer2)), header->dataLen);
903
904 switch (header->msgType)
905 {
906 case CB_CLIP_CAPS:
907 if ((error = cliprdr_server_receive_capabilities(context, s, header)))
908 WLog_ERR(TAG, "cliprdr_server_receive_capabilities failed with error %" PRIu32 "!",
909 error);
910
911 break;
912
913 case CB_TEMP_DIRECTORY:
914 if ((error = cliprdr_server_receive_temporary_directory(context, s, header)))
915 WLog_ERR(TAG,
916 "cliprdr_server_receive_temporary_directory failed with error %" PRIu32
917 "!",
918 error);
919
920 break;
921
922 case CB_FORMAT_LIST:
923 if ((error = cliprdr_server_receive_format_list(context, s, header)))
924 WLog_ERR(TAG, "cliprdr_server_receive_format_list failed with error %" PRIu32 "!",
925 error);
926
927 break;
928
929 case CB_FORMAT_LIST_RESPONSE:
930 if ((error = cliprdr_server_receive_format_list_response(context, s, header)))
931 WLog_ERR(TAG,
932 "cliprdr_server_receive_format_list_response failed with error %" PRIu32
933 "!",
934 error);
935
936 break;
937
938 case CB_LOCK_CLIPDATA:
939 if ((error = cliprdr_server_receive_lock_clipdata(context, s, header)))
940 WLog_ERR(TAG, "cliprdr_server_receive_lock_clipdata failed with error %" PRIu32 "!",
941 error);
942
943 break;
944
945 case CB_UNLOCK_CLIPDATA:
946 if ((error = cliprdr_server_receive_unlock_clipdata(context, s, header)))
947 WLog_ERR(TAG,
948 "cliprdr_server_receive_unlock_clipdata failed with error %" PRIu32 "!",
949 error);
950
951 break;
952
953 case CB_FORMAT_DATA_REQUEST:
954 if ((error = cliprdr_server_receive_format_data_request(context, s, header)))
955 WLog_ERR(TAG,
956 "cliprdr_server_receive_format_data_request failed with error %" PRIu32
957 "!",
958 error);
959
960 break;
961
962 case CB_FORMAT_DATA_RESPONSE:
963 if ((error = cliprdr_server_receive_format_data_response(context, s, header)))
964 WLog_ERR(TAG,
965 "cliprdr_server_receive_format_data_response failed with error %" PRIu32
966 "!",
967 error);
968
969 break;
970
971 case CB_FILECONTENTS_REQUEST:
972 if ((error = cliprdr_server_receive_filecontents_request(context, s, header)))
973 WLog_ERR(TAG,
974 "cliprdr_server_receive_filecontents_request failed with error %" PRIu32
975 "!",
976 error);
977
978 break;
979
980 case CB_FILECONTENTS_RESPONSE:
981 if ((error = cliprdr_server_receive_filecontents_response(context, s, header)))
982 WLog_ERR(TAG,
983 "cliprdr_server_receive_filecontents_response failed with error %" PRIu32
984 "!",
985 error);
986
987 break;
988
989 default:
990 error = ERROR_INVALID_DATA;
991 WLog_ERR(TAG, "Unexpected clipboard PDU type: %" PRIu16 "", header->msgType);
992 break;
993 }
994
995 return error;
996}
997
1003static UINT cliprdr_server_init(CliprdrServerContext* context)
1004{
1005 UINT32 generalFlags = 0;
1006 CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet = WINPR_C_ARRAY_INIT;
1007 UINT error = 0;
1008 CLIPRDR_MONITOR_READY monitorReady = WINPR_C_ARRAY_INIT;
1009 CLIPRDR_CAPABILITIES capabilities = WINPR_C_ARRAY_INIT;
1010
1011 WINPR_ASSERT(context);
1012
1013 monitorReady.common.msgType = CB_MONITOR_READY;
1014 capabilities.common.msgType = CB_CLIP_CAPS;
1015
1016 if (context->useLongFormatNames)
1017 generalFlags |= CB_USE_LONG_FORMAT_NAMES;
1018
1019 if (context->streamFileClipEnabled)
1020 generalFlags |= CB_STREAM_FILECLIP_ENABLED;
1021
1022 if (context->fileClipNoFilePaths)
1023 generalFlags |= CB_FILECLIP_NO_FILE_PATHS;
1024
1025 if (context->canLockClipData)
1026 generalFlags |= CB_CAN_LOCK_CLIPDATA;
1027
1028 if (context->hasHugeFileSupport)
1029 generalFlags |= CB_HUGE_FILE_SUPPORT_ENABLED;
1030
1031 capabilities.common.msgType = CB_CLIP_CAPS;
1032 capabilities.common.msgFlags = 0;
1033 capabilities.common.dataLen = 4 + CB_CAPSTYPE_GENERAL_LEN;
1034 capabilities.cCapabilitiesSets = 1;
1035 capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&generalCapabilitySet;
1036 generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
1037 generalCapabilitySet.capabilitySetLength = CB_CAPSTYPE_GENERAL_LEN;
1038 generalCapabilitySet.version = CB_CAPS_VERSION_2;
1039 generalCapabilitySet.generalFlags = generalFlags;
1040
1041 if ((error = context->ServerCapabilities(context, &capabilities)))
1042 {
1043 WLog_ERR(TAG, "ServerCapabilities failed with error %" PRIu32 "!", error);
1044 return error;
1045 }
1046
1047 if ((error = context->MonitorReady(context, &monitorReady)))
1048 {
1049 WLog_ERR(TAG, "MonitorReady failed with error %" PRIu32 "!", error);
1050 return error;
1051 }
1052
1053 return error;
1054}
1055
1061static UINT cliprdr_server_read(CliprdrServerContext* context)
1062{
1063 wStream* s = nullptr;
1064 size_t position = 0;
1065 DWORD BytesToRead = 0;
1066 DWORD BytesReturned = 0;
1067 CLIPRDR_HEADER header = WINPR_C_ARRAY_INIT;
1068 CliprdrServerPrivate* cliprdr = nullptr;
1069 UINT error = 0;
1070 DWORD status = 0;
1071
1072 WINPR_ASSERT(context);
1073
1074 cliprdr = (CliprdrServerPrivate*)context->handle;
1075 WINPR_ASSERT(cliprdr);
1076
1077 s = cliprdr->s;
1078
1079 if (Stream_GetPosition(s) < CLIPRDR_HEADER_LENGTH)
1080 {
1081 BytesReturned = 0;
1082 BytesToRead = (UINT32)(CLIPRDR_HEADER_LENGTH - Stream_GetPosition(s));
1083 status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1084
1085 if (status == WAIT_FAILED)
1086 {
1087 error = GetLastError();
1088 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1089 return error;
1090 }
1091
1092 if (status == WAIT_TIMEOUT)
1093 return CHANNEL_RC_OK;
1094
1095 if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1096 &BytesReturned))
1097 {
1098 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1099 return ERROR_INTERNAL_ERROR;
1100 }
1101
1102 Stream_Seek(s, BytesReturned);
1103 }
1104
1105 if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH)
1106 {
1107 position = Stream_GetPosition(s);
1108 Stream_SetPosition(s, 0);
1109 Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
1110 Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
1111 Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
1112
1113 if (!Stream_EnsureRemainingCapacity(s, header.dataLen))
1114 {
1115 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1116 return CHANNEL_RC_NO_MEMORY;
1117 }
1118
1119 Stream_SetPosition(s, position);
1120
1121 if (Stream_GetPosition(s) < (header.dataLen + CLIPRDR_HEADER_LENGTH))
1122 {
1123 BytesReturned = 0;
1124 BytesToRead =
1125 (UINT32)((header.dataLen + CLIPRDR_HEADER_LENGTH) - Stream_GetPosition(s));
1126 status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1127
1128 if (status == WAIT_FAILED)
1129 {
1130 error = GetLastError();
1131 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1132 return error;
1133 }
1134
1135 if (status == WAIT_TIMEOUT)
1136 return CHANNEL_RC_OK;
1137
1138 if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1139 &BytesReturned))
1140 {
1141 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1142 return ERROR_INTERNAL_ERROR;
1143 }
1144
1145 Stream_Seek(s, BytesReturned);
1146 }
1147
1148 if (Stream_GetPosition(s) >= (header.dataLen + CLIPRDR_HEADER_LENGTH))
1149 {
1150 Stream_SetPosition(s, (header.dataLen + CLIPRDR_HEADER_LENGTH));
1151 Stream_SealLength(s);
1152 Stream_SetPosition(s, CLIPRDR_HEADER_LENGTH);
1153
1154 if ((error = cliprdr_server_receive_pdu(context, s, &header)))
1155 {
1156 WLog_ERR(TAG, "cliprdr_server_receive_pdu failed with error code %" PRIu32 "!",
1157 error);
1158 return error;
1159 }
1160
1161 Stream_SetPosition(s, 0);
1162 /* check for trailing zero bytes */
1163 status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1164
1165 if (status == WAIT_FAILED)
1166 {
1167 error = GetLastError();
1168 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1169 return error;
1170 }
1171
1172 if (status == WAIT_TIMEOUT)
1173 return CHANNEL_RC_OK;
1174
1175 BytesReturned = 0;
1176 BytesToRead = 4;
1177
1178 if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1179 &BytesReturned))
1180 {
1181 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1182 return ERROR_INTERNAL_ERROR;
1183 }
1184
1185 if (BytesReturned == 4)
1186 {
1187 Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
1188 Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
1189
1190 if (!header.msgType)
1191 {
1192 /* ignore trailing bytes */
1193 Stream_SetPosition(s, 0);
1194 }
1195 }
1196 else
1197 {
1198 Stream_Seek(s, BytesReturned);
1199 }
1200 }
1201 }
1202
1203 return CHANNEL_RC_OK;
1204}
1205
1206static DWORD WINAPI cliprdr_server_thread(LPVOID arg)
1207{
1208 DWORD status = 0;
1209 DWORD nCount = 0;
1210 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
1211 HANDLE ChannelEvent = nullptr;
1212 CliprdrServerContext* context = (CliprdrServerContext*)arg;
1213 CliprdrServerPrivate* cliprdr = nullptr;
1214 UINT error = CHANNEL_RC_OK;
1215
1216 WINPR_ASSERT(context);
1217
1218 cliprdr = (CliprdrServerPrivate*)context->handle;
1219 WINPR_ASSERT(cliprdr);
1220
1221 ChannelEvent = context->GetEventHandle(context);
1222
1223 events[nCount++] = cliprdr->StopEvent;
1224 events[nCount++] = ChannelEvent;
1225
1226 if (context->autoInitializationSequence)
1227 {
1228 if ((error = cliprdr_server_init(context)))
1229 {
1230 WLog_ERR(TAG, "cliprdr_server_init failed with error %" PRIu32 "!", error);
1231 goto out;
1232 }
1233 }
1234
1235 while (1)
1236 {
1237 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1238
1239 if (status == WAIT_FAILED)
1240 {
1241 error = GetLastError();
1242 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1243 goto out;
1244 }
1245
1246 status = WaitForSingleObject(cliprdr->StopEvent, 0);
1247
1248 if (status == WAIT_FAILED)
1249 {
1250 error = GetLastError();
1251 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1252 goto out;
1253 }
1254
1255 if (status == WAIT_OBJECT_0)
1256 break;
1257
1258 status = WaitForSingleObject(ChannelEvent, 0);
1259
1260 if (status == WAIT_FAILED)
1261 {
1262 error = GetLastError();
1263 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1264 goto out;
1265 }
1266
1267 if (status == WAIT_OBJECT_0)
1268 {
1269 if ((error = context->CheckEventHandle(context)))
1270 {
1271 WLog_ERR(TAG, "CheckEventHandle failed with error %" PRIu32 "!", error);
1272 break;
1273 }
1274 }
1275 }
1276
1277out:
1278
1279 if (error && context->rdpcontext)
1280 setChannelError(context->rdpcontext, error, "cliprdr_server_thread reported an error");
1281
1282 ExitThread(error);
1283 return error;
1284}
1285
1291static UINT cliprdr_server_open(CliprdrServerContext* context)
1292{
1293 void* buffer = nullptr;
1294 DWORD BytesReturned = 0;
1295 CliprdrServerPrivate* cliprdr = nullptr;
1296
1297 WINPR_ASSERT(context);
1298
1299 cliprdr = (CliprdrServerPrivate*)context->handle;
1300 WINPR_ASSERT(cliprdr);
1301
1302 cliprdr->ChannelHandle =
1303 WTSVirtualChannelOpen(cliprdr->vcm, WTS_CURRENT_SESSION, CLIPRDR_SVC_CHANNEL_NAME);
1304
1305 if (!cliprdr->ChannelHandle)
1306 {
1307 WLog_ERR(TAG, "WTSVirtualChannelOpen for cliprdr failed!");
1308 return ERROR_INTERNAL_ERROR;
1309 }
1310
1311 cliprdr->ChannelEvent = nullptr;
1312
1313 if (WTSVirtualChannelQuery(cliprdr->ChannelHandle, WTSVirtualEventHandle, &buffer,
1314 &BytesReturned))
1315 {
1316 if (BytesReturned != sizeof(HANDLE))
1317 {
1318 WLog_ERR(TAG, "BytesReturned has not size of HANDLE!");
1319 return ERROR_INTERNAL_ERROR;
1320 }
1321
1322 cliprdr->ChannelEvent = *(HANDLE*)buffer;
1323 WTSFreeMemory(buffer);
1324 }
1325
1326 if (!cliprdr->ChannelEvent)
1327 {
1328 WLog_ERR(TAG, "WTSVirtualChannelQuery for cliprdr failed!");
1329 return ERROR_INTERNAL_ERROR;
1330 }
1331
1332 return CHANNEL_RC_OK;
1333}
1334
1340static UINT cliprdr_server_close(CliprdrServerContext* context)
1341{
1342 CliprdrServerPrivate* cliprdr = nullptr;
1343
1344 WINPR_ASSERT(context);
1345
1346 cliprdr = (CliprdrServerPrivate*)context->handle;
1347 WINPR_ASSERT(cliprdr);
1348
1349 if (cliprdr->ChannelHandle)
1350 {
1351 (void)WTSVirtualChannelClose(cliprdr->ChannelHandle);
1352 cliprdr->ChannelHandle = nullptr;
1353 }
1354
1355 return CHANNEL_RC_OK;
1356}
1357
1363static UINT cliprdr_server_start(CliprdrServerContext* context)
1364{
1365 UINT error = 0;
1366 CliprdrServerPrivate* cliprdr = nullptr;
1367
1368 WINPR_ASSERT(context);
1369
1370 cliprdr = (CliprdrServerPrivate*)context->handle;
1371 WINPR_ASSERT(cliprdr);
1372
1373 if (!cliprdr->ChannelHandle)
1374 {
1375 if ((error = context->Open(context)))
1376 {
1377 WLog_ERR(TAG, "Open failed!");
1378 return error;
1379 }
1380 }
1381
1382 if (!(cliprdr->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1383 {
1384 WLog_ERR(TAG, "CreateEvent failed!");
1385 return ERROR_INTERNAL_ERROR;
1386 }
1387
1388 if (!(cliprdr->Thread =
1389 CreateThread(nullptr, 0, cliprdr_server_thread, (void*)context, 0, nullptr)))
1390 {
1391 WLog_ERR(TAG, "CreateThread failed!");
1392 (void)CloseHandle(cliprdr->StopEvent);
1393 cliprdr->StopEvent = nullptr;
1394 return ERROR_INTERNAL_ERROR;
1395 }
1396
1397 return CHANNEL_RC_OK;
1398}
1399
1405static UINT cliprdr_server_stop(CliprdrServerContext* context)
1406{
1407 UINT error = CHANNEL_RC_OK;
1408 CliprdrServerPrivate* cliprdr = nullptr;
1409
1410 WINPR_ASSERT(context);
1411
1412 cliprdr = (CliprdrServerPrivate*)context->handle;
1413 WINPR_ASSERT(cliprdr);
1414
1415 if (cliprdr->StopEvent)
1416 {
1417 (void)SetEvent(cliprdr->StopEvent);
1418
1419 if (WaitForSingleObject(cliprdr->Thread, INFINITE) == WAIT_FAILED)
1420 {
1421 error = GetLastError();
1422 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1423 return error;
1424 }
1425
1426 (void)CloseHandle(cliprdr->Thread);
1427 (void)CloseHandle(cliprdr->StopEvent);
1428 }
1429
1430 if (cliprdr->ChannelHandle)
1431 return context->Close(context);
1432
1433 return error;
1434}
1435
1436static HANDLE cliprdr_server_get_event_handle(CliprdrServerContext* context)
1437{
1438 CliprdrServerPrivate* cliprdr = nullptr;
1439
1440 WINPR_ASSERT(context);
1441
1442 cliprdr = (CliprdrServerPrivate*)context->handle;
1443 WINPR_ASSERT(cliprdr);
1444 return cliprdr->ChannelEvent;
1445}
1446
1452static UINT cliprdr_server_check_event_handle(CliprdrServerContext* context)
1453{
1454 return cliprdr_server_read(context);
1455}
1456
1457CliprdrServerContext* cliprdr_server_context_new(HANDLE vcm)
1458{
1459 CliprdrServerPrivate* cliprdr = nullptr;
1460 CliprdrServerContext* context = (CliprdrServerContext*)calloc(1, sizeof(CliprdrServerContext));
1461
1462 if (context)
1463 {
1464 context->autoInitializationSequence = TRUE;
1465 context->Open = cliprdr_server_open;
1466 context->Close = cliprdr_server_close;
1467 context->Start = cliprdr_server_start;
1468 context->Stop = cliprdr_server_stop;
1469 context->GetEventHandle = cliprdr_server_get_event_handle;
1470 context->CheckEventHandle = cliprdr_server_check_event_handle;
1471 context->ServerCapabilities = cliprdr_server_capabilities;
1472 context->MonitorReady = cliprdr_server_monitor_ready;
1473 context->ServerFormatList = cliprdr_server_format_list;
1474 context->ServerFormatListResponse = cliprdr_server_format_list_response;
1475 context->ServerLockClipboardData = cliprdr_server_lock_clipboard_data;
1476 context->ServerUnlockClipboardData = cliprdr_server_unlock_clipboard_data;
1477 context->ServerFormatDataRequest = cliprdr_server_format_data_request;
1478 context->ServerFormatDataResponse = cliprdr_server_format_data_response;
1479 context->ServerFileContentsRequest = cliprdr_server_file_contents_request;
1480 context->ServerFileContentsResponse = cliprdr_server_file_contents_response;
1481 cliprdr = context->handle = (CliprdrServerPrivate*)calloc(1, sizeof(CliprdrServerPrivate));
1482
1483 if (cliprdr)
1484 {
1485 cliprdr->vcm = vcm;
1486 cliprdr->s = Stream_New(nullptr, 4096);
1487
1488 if (!cliprdr->s)
1489 {
1490 WLog_ERR(TAG, "Stream_New failed!");
1491 free(context->handle);
1492 free(context);
1493 return nullptr;
1494 }
1495 }
1496 else
1497 {
1498 WLog_ERR(TAG, "calloc failed!");
1499 free(context);
1500 return nullptr;
1501 }
1502 }
1503
1504 return context;
1505}
1506
1507void cliprdr_server_context_free(CliprdrServerContext* context)
1508{
1509 CliprdrServerPrivate* cliprdr = nullptr;
1510
1511 if (!context)
1512 return;
1513
1514 cliprdr = (CliprdrServerPrivate*)context->handle;
1515
1516 if (cliprdr)
1517 {
1518 Stream_Free(cliprdr->s, TRUE);
1519 }
1520
1521 free(context->handle);
1522 free(context);
1523}