FreeRDP
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 
79 static 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;
104 fail:
105  Stream_Free(s, TRUE);
106  return rc;
107 }
108 
114 static 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 =
155  (const CLIPRDR_GENERAL_CAPABILITY_SET*)cap;
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 
186 static UINT cliprdr_server_monitor_ready(CliprdrServerContext* context,
187  const CLIPRDR_MONITOR_READY* monitorReady)
188 {
189  wStream* s = NULL;
190  CliprdrServerPrivate* cliprdr = NULL;
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 
218 static UINT cliprdr_server_format_list(CliprdrServerContext* context,
219  const CLIPRDR_FORMAT_LIST* formatList)
220 {
221  wStream* s = NULL;
222  CliprdrServerPrivate* cliprdr = NULL;
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 
245 static UINT
246 cliprdr_server_format_list_response(CliprdrServerContext* context,
247  const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
248 {
249  wStream* s = NULL;
250  CliprdrServerPrivate* cliprdr = NULL;
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 
277 static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context,
278  const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
279 {
280  wStream* s = NULL;
281  CliprdrServerPrivate* cliprdr = NULL;
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 
307 static UINT
308 cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context,
309  const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
310 {
311  wStream* s = NULL;
312  CliprdrServerPrivate* cliprdr = NULL;
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 
339 static UINT cliprdr_server_format_data_request(CliprdrServerContext* context,
340  const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
341 {
342  wStream* s = NULL;
343  CliprdrServerPrivate* cliprdr = NULL;
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 
371 static UINT
372 cliprdr_server_format_data_response(CliprdrServerContext* context,
373  const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
374 {
375  wStream* s = NULL;
376  CliprdrServerPrivate* cliprdr = NULL;
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 
405 static UINT
406 cliprdr_server_file_contents_request(CliprdrServerContext* context,
407  const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
408 {
409  wStream* s = NULL;
410  CliprdrServerPrivate* cliprdr = NULL;
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 
437 static UINT
438 cliprdr_server_file_contents_response(CliprdrServerContext* context,
439  const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
440 {
441  wStream* s = NULL;
442  CliprdrServerPrivate* cliprdr = NULL;
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 
469 static 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 =
483  (cap_set->generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE;
484 
485  if (context->streamFileClipEnabled)
486  context->streamFileClipEnabled =
487  (cap_set->generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE;
488 
489  if (context->fileClipNoFilePaths)
490  context->fileClipNoFilePaths =
491  (cap_set->generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE;
492 
493  if (context->canLockClipData)
494  context->canLockClipData = (cap_set->generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE;
495 
496  if (context->hasHugeFileSupport)
497  context->hasHugeFileSupport =
498  (cap_set->generalFlags & CB_HUGE_FILE_SUPPORT_ENABLED) ? TRUE : FALSE;
499 
500  return CHANNEL_RC_OK;
501 }
502 
508 static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s,
509  const CLIPRDR_HEADER* header)
510 {
511  UINT16 capabilitySetType = 0;
512  UINT16 capabilitySetLength = 0;
513  UINT error = ERROR_INVALID_DATA;
514  size_t cap_sets_size = 0;
515  CLIPRDR_CAPABILITIES capabilities = { 0 };
516  CLIPRDR_CAPABILITY_SET* capSet = NULL;
517 
518  WINPR_ASSERT(context);
519  WINPR_UNUSED(header);
520 
521  WLog_DBG(TAG, "CliprdrClientCapabilities");
522  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
523  return ERROR_INVALID_DATA;
524 
525  Stream_Read_UINT16(s, capabilities.cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
526  Stream_Seek_UINT16(s); /* pad1 (2 bytes) */
527 
528  for (size_t index = 0; index < capabilities.cCapabilitiesSets; index++)
529  {
530  void* tmp = NULL;
531  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
532  goto out;
533  Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
534  Stream_Read_UINT16(s, capabilitySetLength); /* capabilitySetLength (2 bytes) */
535 
536  cap_sets_size += capabilitySetLength;
537 
538  if (cap_sets_size > 0)
539  tmp = realloc(capabilities.capabilitySets, cap_sets_size);
540  if (tmp == NULL)
541  {
542  WLog_ERR(TAG, "capabilities.capabilitySets realloc failed!");
543  free(capabilities.capabilitySets);
544  return CHANNEL_RC_NO_MEMORY;
545  }
546 
547  capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)tmp;
548 
549  capSet = &(capabilities.capabilitySets[index]);
550 
551  capSet->capabilitySetType = capabilitySetType;
552  capSet->capabilitySetLength = capabilitySetLength;
553 
554  switch (capSet->capabilitySetType)
555  {
556  case CB_CAPSTYPE_GENERAL:
557  error = cliprdr_server_receive_general_capability(
558  context, s, (CLIPRDR_GENERAL_CAPABILITY_SET*)capSet);
559  if (error)
560  {
561  WLog_ERR(TAG,
562  "cliprdr_server_receive_general_capability failed with error %" PRIu32
563  "",
564  error);
565  goto out;
566  }
567  break;
568 
569  default:
570  WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "",
571  capSet->capabilitySetType);
572  goto out;
573  }
574  }
575 
576  error = CHANNEL_RC_OK;
577  IFCALLRET(context->ClientCapabilities, error, context, &capabilities);
578 out:
579  free(capabilities.capabilitySets);
580  return error;
581 }
582 
588 static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* context, wStream* s,
589  const CLIPRDR_HEADER* header)
590 {
591  size_t length = 0;
592  CLIPRDR_TEMP_DIRECTORY tempDirectory = { 0 };
593  CliprdrServerPrivate* cliprdr = NULL;
594  UINT error = CHANNEL_RC_OK;
595 
596  WINPR_ASSERT(context);
597  WINPR_UNUSED(header);
598 
599  cliprdr = (CliprdrServerPrivate*)context->handle;
600  WINPR_ASSERT(cliprdr);
601 
602  if (!Stream_CheckAndLogRequiredLength(TAG, s,
603  ARRAYSIZE(cliprdr->temporaryDirectory) * sizeof(WCHAR)))
604  return CHANNEL_RC_NO_MEMORY;
605 
606  const WCHAR* wszTempDir = Stream_ConstPointer(s);
607 
608  if (wszTempDir[ARRAYSIZE(cliprdr->temporaryDirectory) - 1] != 0)
609  {
610  WLog_ERR(TAG, "wszTempDir[259] was not 0");
611  return ERROR_INVALID_DATA;
612  }
613 
614  if (ConvertWCharNToUtf8(wszTempDir, ARRAYSIZE(cliprdr->temporaryDirectory),
615  cliprdr->temporaryDirectory,
616  ARRAYSIZE(cliprdr->temporaryDirectory)) < 0)
617  {
618  WLog_ERR(TAG, "failed to convert temporary directory name");
619  return ERROR_INVALID_DATA;
620  }
621 
622  length = strnlen(cliprdr->temporaryDirectory, ARRAYSIZE(cliprdr->temporaryDirectory));
623 
624  if (length >= ARRAYSIZE(cliprdr->temporaryDirectory))
625  length = ARRAYSIZE(cliprdr->temporaryDirectory) - 1;
626 
627  CopyMemory(tempDirectory.szTempDir, cliprdr->temporaryDirectory, length);
628  tempDirectory.szTempDir[length] = '\0';
629  WLog_DBG(TAG, "CliprdrTemporaryDirectory: %s", cliprdr->temporaryDirectory);
630  IFCALLRET(context->TempDirectory, error, context, &tempDirectory);
631 
632  if (error)
633  WLog_ERR(TAG, "TempDirectory failed with error %" PRIu32 "!", error);
634 
635  return error;
636 }
637 
643 static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s,
644  const CLIPRDR_HEADER* header)
645 {
646  CLIPRDR_FORMAT_LIST formatList = { 0 };
647  UINT error = CHANNEL_RC_OK;
648 
649  WINPR_ASSERT(context);
650  WINPR_ASSERT(header);
651 
652  formatList.common.msgType = CB_FORMAT_LIST;
653  formatList.common.msgFlags = header->msgFlags;
654  formatList.common.dataLen = header->dataLen;
655 
656  if ((error = cliprdr_read_format_list(s, &formatList, context->useLongFormatNames)))
657  goto out;
658 
659  WLog_DBG(TAG, "ClientFormatList: numFormats: %" PRIu32 "", formatList.numFormats);
660  IFCALLRET(context->ClientFormatList, error, context, &formatList);
661 
662  if (error)
663  WLog_ERR(TAG, "ClientFormatList failed with error %" PRIu32 "!", error);
664 
665 out:
666  cliprdr_free_format_list(&formatList);
667  return error;
668 }
669 
675 static UINT cliprdr_server_receive_format_list_response(CliprdrServerContext* context, wStream* s,
676  const CLIPRDR_HEADER* header)
677 {
678  CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 };
679  UINT error = CHANNEL_RC_OK;
680 
681  WINPR_ASSERT(context);
682  WINPR_ASSERT(header);
683 
684  WINPR_UNUSED(s);
685  WLog_DBG(TAG, "CliprdrClientFormatListResponse");
686  formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
687  formatListResponse.common.msgFlags = header->msgFlags;
688  formatListResponse.common.dataLen = header->dataLen;
689  IFCALLRET(context->ClientFormatListResponse, error, context, &formatListResponse);
690 
691  if (error)
692  WLog_ERR(TAG, "ClientFormatListResponse failed with error %" PRIu32 "!", error);
693 
694  return error;
695 }
696 
702 static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, wStream* s,
703  const CLIPRDR_HEADER* header)
704 {
705  CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData = { 0 };
706  UINT error = CHANNEL_RC_OK;
707 
708  WINPR_ASSERT(context);
709  WINPR_ASSERT(header);
710 
711  WLog_DBG(TAG, "CliprdrClientLockClipData");
712 
713  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
714  return ERROR_INVALID_DATA;
715 
716  lockClipboardData.common.msgType = CB_LOCK_CLIPDATA;
717  lockClipboardData.common.msgFlags = header->msgFlags;
718  lockClipboardData.common.dataLen = header->dataLen;
719  Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */
720  IFCALLRET(context->ClientLockClipboardData, error, context, &lockClipboardData);
721 
722  if (error)
723  WLog_ERR(TAG, "ClientLockClipboardData failed with error %" PRIu32 "!", error);
724 
725  return error;
726 }
727 
733 static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* context, wStream* s,
734  const CLIPRDR_HEADER* header)
735 {
736  CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData = { 0 };
737  UINT error = CHANNEL_RC_OK;
738 
739  WINPR_ASSERT(context);
740  WINPR_ASSERT(header);
741 
742  WLog_DBG(TAG, "CliprdrClientUnlockClipData");
743 
744  unlockClipboardData.common.msgType = CB_UNLOCK_CLIPDATA;
745  unlockClipboardData.common.msgFlags = header->msgFlags;
746  unlockClipboardData.common.dataLen = header->dataLen;
747 
748  if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData)))
749  return error;
750 
751  IFCALLRET(context->ClientUnlockClipboardData, error, context, &unlockClipboardData);
752 
753  if (error)
754  WLog_ERR(TAG, "ClientUnlockClipboardData failed with error %" PRIu32 "!", error);
755 
756  return error;
757 }
758 
764 static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* context, wStream* s,
765  const CLIPRDR_HEADER* header)
766 {
767  CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = { 0 };
768  UINT error = CHANNEL_RC_OK;
769 
770  WINPR_ASSERT(context);
771  WINPR_ASSERT(header);
772 
773  WLog_DBG(TAG, "CliprdrClientFormatDataRequest");
774  formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
775  formatDataRequest.common.msgFlags = header->msgFlags;
776  formatDataRequest.common.dataLen = header->dataLen;
777 
778  if ((error = cliprdr_read_format_data_request(s, &formatDataRequest)))
779  return error;
780 
781  context->lastRequestedFormatId = formatDataRequest.requestedFormatId;
782  IFCALLRET(context->ClientFormatDataRequest, error, context, &formatDataRequest);
783 
784  if (error)
785  WLog_ERR(TAG, "ClientFormatDataRequest failed with error %" PRIu32 "!", error);
786 
787  return error;
788 }
789 
795 static UINT cliprdr_server_receive_format_data_response(CliprdrServerContext* context, wStream* s,
796  const CLIPRDR_HEADER* header)
797 {
798  CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse = { 0 };
799  UINT error = CHANNEL_RC_OK;
800 
801  WINPR_ASSERT(context);
802  WINPR_ASSERT(header);
803 
804  WLog_DBG(TAG, "CliprdrClientFormatDataResponse");
805  formatDataResponse.common.msgType = CB_FORMAT_DATA_RESPONSE;
806  formatDataResponse.common.msgFlags = header->msgFlags;
807  formatDataResponse.common.dataLen = header->dataLen;
808 
809  if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
810  return error;
811 
812  IFCALLRET(context->ClientFormatDataResponse, error, context, &formatDataResponse);
813 
814  if (error)
815  WLog_ERR(TAG, "ClientFormatDataResponse failed with error %" PRIu32 "!", error);
816 
817  return error;
818 }
819 
825 static UINT cliprdr_server_receive_filecontents_request(CliprdrServerContext* context, wStream* s,
826  const CLIPRDR_HEADER* header)
827 {
828  CLIPRDR_FILE_CONTENTS_REQUEST request = { 0 };
829  UINT error = CHANNEL_RC_OK;
830 
831  WINPR_ASSERT(context);
832  WINPR_ASSERT(header);
833 
834  WLog_DBG(TAG, "CliprdrClientFileContentsRequest");
835  request.common.msgType = CB_FILECONTENTS_REQUEST;
836  request.common.msgFlags = header->msgFlags;
837  request.common.dataLen = header->dataLen;
838 
839  if ((error = cliprdr_read_file_contents_request(s, &request)))
840  return error;
841 
842  if (!context->hasHugeFileSupport)
843  {
844  if (request.nPositionHigh > 0)
845  return ERROR_INVALID_DATA;
846  if ((UINT64)request.nPositionLow + request.cbRequested > UINT32_MAX)
847  return ERROR_INVALID_DATA;
848  }
849  IFCALLRET(context->ClientFileContentsRequest, error, context, &request);
850 
851  if (error)
852  WLog_ERR(TAG, "ClientFileContentsRequest failed with error %" PRIu32 "!", error);
853 
854  return error;
855 }
856 
862 static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* context, wStream* s,
863  const CLIPRDR_HEADER* header)
864 {
865  CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
866  UINT error = CHANNEL_RC_OK;
867 
868  WINPR_ASSERT(context);
869  WINPR_ASSERT(header);
870 
871  WLog_DBG(TAG, "CliprdrClientFileContentsResponse");
872 
873  response.common.msgType = CB_FILECONTENTS_RESPONSE;
874  response.common.msgFlags = header->msgFlags;
875  response.common.dataLen = header->dataLen;
876 
877  if ((error = cliprdr_read_file_contents_response(s, &response)))
878  return error;
879 
880  IFCALLRET(context->ClientFileContentsResponse, error, context, &response);
881 
882  if (error)
883  WLog_ERR(TAG, "ClientFileContentsResponse failed with error %" PRIu32 "!", error);
884 
885  return error;
886 }
887 
893 static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s,
894  const CLIPRDR_HEADER* header)
895 {
896  UINT error = 0;
897 
898  WINPR_ASSERT(context);
899  WINPR_ASSERT(header);
900 
901  char buffer1[64] = { 0 };
902  char buffer2[64] = { 0 };
903  WLog_DBG(TAG, "CliprdrServerReceivePdu: msgType: %s, msgFlags: %s dataLen: %" PRIu32 "",
904  CB_MSG_TYPE_STRING(header->msgType, buffer1, sizeof(buffer1)),
905  CB_MSG_FLAGS_STRING(header->msgFlags, buffer2, sizeof(buffer2)), header->dataLen);
906 
907  switch (header->msgType)
908  {
909  case CB_CLIP_CAPS:
910  if ((error = cliprdr_server_receive_capabilities(context, s, header)))
911  WLog_ERR(TAG, "cliprdr_server_receive_capabilities failed with error %" PRIu32 "!",
912  error);
913 
914  break;
915 
916  case CB_TEMP_DIRECTORY:
917  if ((error = cliprdr_server_receive_temporary_directory(context, s, header)))
918  WLog_ERR(TAG,
919  "cliprdr_server_receive_temporary_directory failed with error %" PRIu32
920  "!",
921  error);
922 
923  break;
924 
925  case CB_FORMAT_LIST:
926  if ((error = cliprdr_server_receive_format_list(context, s, header)))
927  WLog_ERR(TAG, "cliprdr_server_receive_format_list failed with error %" PRIu32 "!",
928  error);
929 
930  break;
931 
932  case CB_FORMAT_LIST_RESPONSE:
933  if ((error = cliprdr_server_receive_format_list_response(context, s, header)))
934  WLog_ERR(TAG,
935  "cliprdr_server_receive_format_list_response failed with error %" PRIu32
936  "!",
937  error);
938 
939  break;
940 
941  case CB_LOCK_CLIPDATA:
942  if ((error = cliprdr_server_receive_lock_clipdata(context, s, header)))
943  WLog_ERR(TAG, "cliprdr_server_receive_lock_clipdata failed with error %" PRIu32 "!",
944  error);
945 
946  break;
947 
948  case CB_UNLOCK_CLIPDATA:
949  if ((error = cliprdr_server_receive_unlock_clipdata(context, s, header)))
950  WLog_ERR(TAG,
951  "cliprdr_server_receive_unlock_clipdata failed with error %" PRIu32 "!",
952  error);
953 
954  break;
955 
956  case CB_FORMAT_DATA_REQUEST:
957  if ((error = cliprdr_server_receive_format_data_request(context, s, header)))
958  WLog_ERR(TAG,
959  "cliprdr_server_receive_format_data_request failed with error %" PRIu32
960  "!",
961  error);
962 
963  break;
964 
965  case CB_FORMAT_DATA_RESPONSE:
966  if ((error = cliprdr_server_receive_format_data_response(context, s, header)))
967  WLog_ERR(TAG,
968  "cliprdr_server_receive_format_data_response failed with error %" PRIu32
969  "!",
970  error);
971 
972  break;
973 
974  case CB_FILECONTENTS_REQUEST:
975  if ((error = cliprdr_server_receive_filecontents_request(context, s, header)))
976  WLog_ERR(TAG,
977  "cliprdr_server_receive_filecontents_request failed with error %" PRIu32
978  "!",
979  error);
980 
981  break;
982 
983  case CB_FILECONTENTS_RESPONSE:
984  if ((error = cliprdr_server_receive_filecontents_response(context, s, header)))
985  WLog_ERR(TAG,
986  "cliprdr_server_receive_filecontents_response failed with error %" PRIu32
987  "!",
988  error);
989 
990  break;
991 
992  default:
993  error = ERROR_INVALID_DATA;
994  WLog_ERR(TAG, "Unexpected clipboard PDU type: %" PRIu16 "", header->msgType);
995  break;
996  }
997 
998  return error;
999 }
1000 
1006 static UINT cliprdr_server_init(CliprdrServerContext* context)
1007 {
1008  UINT32 generalFlags = 0;
1009  CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet = { 0 };
1010  UINT error = 0;
1011  CLIPRDR_MONITOR_READY monitorReady = { 0 };
1012  CLIPRDR_CAPABILITIES capabilities = { 0 };
1013 
1014  WINPR_ASSERT(context);
1015 
1016  monitorReady.common.msgType = CB_MONITOR_READY;
1017  capabilities.common.msgType = CB_CLIP_CAPS;
1018 
1019  if (context->useLongFormatNames)
1020  generalFlags |= CB_USE_LONG_FORMAT_NAMES;
1021 
1022  if (context->streamFileClipEnabled)
1023  generalFlags |= CB_STREAM_FILECLIP_ENABLED;
1024 
1025  if (context->fileClipNoFilePaths)
1026  generalFlags |= CB_FILECLIP_NO_FILE_PATHS;
1027 
1028  if (context->canLockClipData)
1029  generalFlags |= CB_CAN_LOCK_CLIPDATA;
1030 
1031  if (context->hasHugeFileSupport)
1032  generalFlags |= CB_HUGE_FILE_SUPPORT_ENABLED;
1033 
1034  capabilities.common.msgType = CB_CLIP_CAPS;
1035  capabilities.common.msgFlags = 0;
1036  capabilities.common.dataLen = 4 + CB_CAPSTYPE_GENERAL_LEN;
1037  capabilities.cCapabilitiesSets = 1;
1038  capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&generalCapabilitySet;
1039  generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
1040  generalCapabilitySet.capabilitySetLength = CB_CAPSTYPE_GENERAL_LEN;
1041  generalCapabilitySet.version = CB_CAPS_VERSION_2;
1042  generalCapabilitySet.generalFlags = generalFlags;
1043 
1044  if ((error = context->ServerCapabilities(context, &capabilities)))
1045  {
1046  WLog_ERR(TAG, "ServerCapabilities failed with error %" PRIu32 "!", error);
1047  return error;
1048  }
1049 
1050  if ((error = context->MonitorReady(context, &monitorReady)))
1051  {
1052  WLog_ERR(TAG, "MonitorReady failed with error %" PRIu32 "!", error);
1053  return error;
1054  }
1055 
1056  return error;
1057 }
1058 
1064 static UINT cliprdr_server_read(CliprdrServerContext* context)
1065 {
1066  wStream* s = NULL;
1067  size_t position = 0;
1068  DWORD BytesToRead = 0;
1069  DWORD BytesReturned = 0;
1070  CLIPRDR_HEADER header = { 0 };
1071  CliprdrServerPrivate* cliprdr = NULL;
1072  UINT error = 0;
1073  DWORD status = 0;
1074 
1075  WINPR_ASSERT(context);
1076 
1077  cliprdr = (CliprdrServerPrivate*)context->handle;
1078  WINPR_ASSERT(cliprdr);
1079 
1080  s = cliprdr->s;
1081 
1082  if (Stream_GetPosition(s) < CLIPRDR_HEADER_LENGTH)
1083  {
1084  BytesReturned = 0;
1085  BytesToRead = (UINT32)(CLIPRDR_HEADER_LENGTH - Stream_GetPosition(s));
1086  status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1087 
1088  if (status == WAIT_FAILED)
1089  {
1090  error = GetLastError();
1091  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1092  return error;
1093  }
1094 
1095  if (status == WAIT_TIMEOUT)
1096  return CHANNEL_RC_OK;
1097 
1098  if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1099  &BytesReturned))
1100  {
1101  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1102  return ERROR_INTERNAL_ERROR;
1103  }
1104 
1105  Stream_Seek(s, BytesReturned);
1106  }
1107 
1108  if (Stream_GetPosition(s) >= CLIPRDR_HEADER_LENGTH)
1109  {
1110  position = Stream_GetPosition(s);
1111  Stream_SetPosition(s, 0);
1112  Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
1113  Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
1114  Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */
1115 
1116  if (!Stream_EnsureCapacity(s, (header.dataLen + CLIPRDR_HEADER_LENGTH)))
1117  {
1118  WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1119  return CHANNEL_RC_NO_MEMORY;
1120  }
1121 
1122  Stream_SetPosition(s, position);
1123 
1124  if (Stream_GetPosition(s) < (header.dataLen + CLIPRDR_HEADER_LENGTH))
1125  {
1126  BytesReturned = 0;
1127  BytesToRead =
1128  (UINT32)((header.dataLen + CLIPRDR_HEADER_LENGTH) - Stream_GetPosition(s));
1129  status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1130 
1131  if (status == WAIT_FAILED)
1132  {
1133  error = GetLastError();
1134  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1135  return error;
1136  }
1137 
1138  if (status == WAIT_TIMEOUT)
1139  return CHANNEL_RC_OK;
1140 
1141  if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1142  &BytesReturned))
1143  {
1144  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1145  return ERROR_INTERNAL_ERROR;
1146  }
1147 
1148  Stream_Seek(s, BytesReturned);
1149  }
1150 
1151  if (Stream_GetPosition(s) >= (header.dataLen + CLIPRDR_HEADER_LENGTH))
1152  {
1153  Stream_SetPosition(s, (header.dataLen + CLIPRDR_HEADER_LENGTH));
1154  Stream_SealLength(s);
1155  Stream_SetPosition(s, CLIPRDR_HEADER_LENGTH);
1156 
1157  if ((error = cliprdr_server_receive_pdu(context, s, &header)))
1158  {
1159  WLog_ERR(TAG, "cliprdr_server_receive_pdu failed with error code %" PRIu32 "!",
1160  error);
1161  return error;
1162  }
1163 
1164  Stream_SetPosition(s, 0);
1165  /* check for trailing zero bytes */
1166  status = WaitForSingleObject(cliprdr->ChannelEvent, 0);
1167 
1168  if (status == WAIT_FAILED)
1169  {
1170  error = GetLastError();
1171  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1172  return error;
1173  }
1174 
1175  if (status == WAIT_TIMEOUT)
1176  return CHANNEL_RC_OK;
1177 
1178  BytesReturned = 0;
1179  BytesToRead = 4;
1180 
1181  if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, Stream_Pointer(s), BytesToRead,
1182  &BytesReturned))
1183  {
1184  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1185  return ERROR_INTERNAL_ERROR;
1186  }
1187 
1188  if (BytesReturned == 4)
1189  {
1190  Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */
1191  Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */
1192 
1193  if (!header.msgType)
1194  {
1195  /* ignore trailing bytes */
1196  Stream_SetPosition(s, 0);
1197  }
1198  }
1199  else
1200  {
1201  Stream_Seek(s, BytesReturned);
1202  }
1203  }
1204  }
1205 
1206  return CHANNEL_RC_OK;
1207 }
1208 
1209 static DWORD WINAPI cliprdr_server_thread(LPVOID arg)
1210 {
1211  DWORD status = 0;
1212  DWORD nCount = 0;
1213  HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 };
1214  HANDLE ChannelEvent = NULL;
1215  CliprdrServerContext* context = (CliprdrServerContext*)arg;
1216  CliprdrServerPrivate* cliprdr = NULL;
1217  UINT error = CHANNEL_RC_OK;
1218 
1219  WINPR_ASSERT(context);
1220 
1221  cliprdr = (CliprdrServerPrivate*)context->handle;
1222  WINPR_ASSERT(cliprdr);
1223 
1224  ChannelEvent = context->GetEventHandle(context);
1225 
1226  events[nCount++] = cliprdr->StopEvent;
1227  events[nCount++] = ChannelEvent;
1228 
1229  if (context->autoInitializationSequence)
1230  {
1231  if ((error = cliprdr_server_init(context)))
1232  {
1233  WLog_ERR(TAG, "cliprdr_server_init failed with error %" PRIu32 "!", error);
1234  goto out;
1235  }
1236  }
1237 
1238  while (1)
1239  {
1240  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1241 
1242  if (status == WAIT_FAILED)
1243  {
1244  error = GetLastError();
1245  WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1246  goto out;
1247  }
1248 
1249  status = WaitForSingleObject(cliprdr->StopEvent, 0);
1250 
1251  if (status == WAIT_FAILED)
1252  {
1253  error = GetLastError();
1254  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1255  goto out;
1256  }
1257 
1258  if (status == WAIT_OBJECT_0)
1259  break;
1260 
1261  status = WaitForSingleObject(ChannelEvent, 0);
1262 
1263  if (status == WAIT_FAILED)
1264  {
1265  error = GetLastError();
1266  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1267  goto out;
1268  }
1269 
1270  if (status == WAIT_OBJECT_0)
1271  {
1272  if ((error = context->CheckEventHandle(context)))
1273  {
1274  WLog_ERR(TAG, "CheckEventHandle failed with error %" PRIu32 "!", error);
1275  break;
1276  }
1277  }
1278  }
1279 
1280 out:
1281 
1282  if (error && context->rdpcontext)
1283  setChannelError(context->rdpcontext, error, "cliprdr_server_thread reported an error");
1284 
1285  ExitThread(error);
1286  return error;
1287 }
1288 
1294 static UINT cliprdr_server_open(CliprdrServerContext* context)
1295 {
1296  void* buffer = NULL;
1297  DWORD BytesReturned = 0;
1298  CliprdrServerPrivate* cliprdr = NULL;
1299 
1300  WINPR_ASSERT(context);
1301 
1302  cliprdr = (CliprdrServerPrivate*)context->handle;
1303  WINPR_ASSERT(cliprdr);
1304 
1305  cliprdr->ChannelHandle =
1306  WTSVirtualChannelOpen(cliprdr->vcm, WTS_CURRENT_SESSION, CLIPRDR_SVC_CHANNEL_NAME);
1307 
1308  if (!cliprdr->ChannelHandle)
1309  {
1310  WLog_ERR(TAG, "WTSVirtualChannelOpen for cliprdr failed!");
1311  return ERROR_INTERNAL_ERROR;
1312  }
1313 
1314  cliprdr->ChannelEvent = NULL;
1315 
1316  if (WTSVirtualChannelQuery(cliprdr->ChannelHandle, WTSVirtualEventHandle, &buffer,
1317  &BytesReturned))
1318  {
1319  if (BytesReturned != sizeof(HANDLE))
1320  {
1321  WLog_ERR(TAG, "BytesReturned has not size of HANDLE!");
1322  return ERROR_INTERNAL_ERROR;
1323  }
1324 
1325  CopyMemory(&(cliprdr->ChannelEvent), buffer, sizeof(HANDLE));
1326  WTSFreeMemory(buffer);
1327  }
1328 
1329  if (!cliprdr->ChannelEvent)
1330  {
1331  WLog_ERR(TAG, "WTSVirtualChannelQuery for cliprdr failed!");
1332  return ERROR_INTERNAL_ERROR;
1333  }
1334 
1335  return CHANNEL_RC_OK;
1336 }
1337 
1343 static UINT cliprdr_server_close(CliprdrServerContext* context)
1344 {
1345  CliprdrServerPrivate* cliprdr = NULL;
1346 
1347  WINPR_ASSERT(context);
1348 
1349  cliprdr = (CliprdrServerPrivate*)context->handle;
1350  WINPR_ASSERT(cliprdr);
1351 
1352  if (cliprdr->ChannelHandle)
1353  {
1354  (void)WTSVirtualChannelClose(cliprdr->ChannelHandle);
1355  cliprdr->ChannelHandle = NULL;
1356  }
1357 
1358  return CHANNEL_RC_OK;
1359 }
1360 
1366 static UINT cliprdr_server_start(CliprdrServerContext* context)
1367 {
1368  UINT error = 0;
1369  CliprdrServerPrivate* cliprdr = NULL;
1370 
1371  WINPR_ASSERT(context);
1372 
1373  cliprdr = (CliprdrServerPrivate*)context->handle;
1374  WINPR_ASSERT(cliprdr);
1375 
1376  if (!cliprdr->ChannelHandle)
1377  {
1378  if ((error = context->Open(context)))
1379  {
1380  WLog_ERR(TAG, "Open failed!");
1381  return error;
1382  }
1383  }
1384 
1385  if (!(cliprdr->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
1386  {
1387  WLog_ERR(TAG, "CreateEvent failed!");
1388  return ERROR_INTERNAL_ERROR;
1389  }
1390 
1391  if (!(cliprdr->Thread = CreateThread(NULL, 0, cliprdr_server_thread, (void*)context, 0, NULL)))
1392  {
1393  WLog_ERR(TAG, "CreateThread failed!");
1394  (void)CloseHandle(cliprdr->StopEvent);
1395  cliprdr->StopEvent = NULL;
1396  return ERROR_INTERNAL_ERROR;
1397  }
1398 
1399  return CHANNEL_RC_OK;
1400 }
1401 
1407 static UINT cliprdr_server_stop(CliprdrServerContext* context)
1408 {
1409  UINT error = CHANNEL_RC_OK;
1410  CliprdrServerPrivate* cliprdr = NULL;
1411 
1412  WINPR_ASSERT(context);
1413 
1414  cliprdr = (CliprdrServerPrivate*)context->handle;
1415  WINPR_ASSERT(cliprdr);
1416 
1417  if (cliprdr->StopEvent)
1418  {
1419  (void)SetEvent(cliprdr->StopEvent);
1420 
1421  if (WaitForSingleObject(cliprdr->Thread, INFINITE) == WAIT_FAILED)
1422  {
1423  error = GetLastError();
1424  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
1425  return error;
1426  }
1427 
1428  (void)CloseHandle(cliprdr->Thread);
1429  (void)CloseHandle(cliprdr->StopEvent);
1430  }
1431 
1432  if (cliprdr->ChannelHandle)
1433  return context->Close(context);
1434 
1435  return error;
1436 }
1437 
1438 static HANDLE cliprdr_server_get_event_handle(CliprdrServerContext* context)
1439 {
1440  CliprdrServerPrivate* cliprdr = NULL;
1441 
1442  WINPR_ASSERT(context);
1443 
1444  cliprdr = (CliprdrServerPrivate*)context->handle;
1445  WINPR_ASSERT(cliprdr);
1446  return cliprdr->ChannelEvent;
1447 }
1448 
1454 static UINT cliprdr_server_check_event_handle(CliprdrServerContext* context)
1455 {
1456  return cliprdr_server_read(context);
1457 }
1458 
1459 CliprdrServerContext* cliprdr_server_context_new(HANDLE vcm)
1460 {
1461  CliprdrServerPrivate* cliprdr = NULL;
1462  CliprdrServerContext* context = (CliprdrServerContext*)calloc(1, sizeof(CliprdrServerContext));
1463 
1464  if (context)
1465  {
1466  context->autoInitializationSequence = TRUE;
1467  context->Open = cliprdr_server_open;
1468  context->Close = cliprdr_server_close;
1469  context->Start = cliprdr_server_start;
1470  context->Stop = cliprdr_server_stop;
1471  context->GetEventHandle = cliprdr_server_get_event_handle;
1472  context->CheckEventHandle = cliprdr_server_check_event_handle;
1473  context->ServerCapabilities = cliprdr_server_capabilities;
1474  context->MonitorReady = cliprdr_server_monitor_ready;
1475  context->ServerFormatList = cliprdr_server_format_list;
1476  context->ServerFormatListResponse = cliprdr_server_format_list_response;
1477  context->ServerLockClipboardData = cliprdr_server_lock_clipboard_data;
1478  context->ServerUnlockClipboardData = cliprdr_server_unlock_clipboard_data;
1479  context->ServerFormatDataRequest = cliprdr_server_format_data_request;
1480  context->ServerFormatDataResponse = cliprdr_server_format_data_response;
1481  context->ServerFileContentsRequest = cliprdr_server_file_contents_request;
1482  context->ServerFileContentsResponse = cliprdr_server_file_contents_response;
1483  cliprdr = context->handle = (CliprdrServerPrivate*)calloc(1, sizeof(CliprdrServerPrivate));
1484 
1485  if (cliprdr)
1486  {
1487  cliprdr->vcm = vcm;
1488  cliprdr->s = Stream_New(NULL, 4096);
1489 
1490  if (!cliprdr->s)
1491  {
1492  WLog_ERR(TAG, "Stream_New failed!");
1493  free(context->handle);
1494  free(context);
1495  return NULL;
1496  }
1497  }
1498  else
1499  {
1500  WLog_ERR(TAG, "calloc failed!");
1501  free(context);
1502  return NULL;
1503  }
1504  }
1505 
1506  return context;
1507 }
1508 
1509 void cliprdr_server_context_free(CliprdrServerContext* context)
1510 {
1511  CliprdrServerPrivate* cliprdr = NULL;
1512 
1513  if (!context)
1514  return;
1515 
1516  cliprdr = (CliprdrServerPrivate*)context->handle;
1517 
1518  if (cliprdr)
1519  {
1520  Stream_Free(cliprdr->s, TRUE);
1521  }
1522 
1523  free(context->handle);
1524  free(context);
1525 }