FreeRDP
Loading...
Searching...
No Matches
wlf_cliprdr.c
1
21#include <freerdp/config.h>
22
23#include <stdlib.h>
24
25#include <winpr/crt.h>
26#include <winpr/image.h>
27#include <winpr/stream.h>
28#include <winpr/clipboard.h>
29
30#include <freerdp/log.h>
31#include <freerdp/client/cliprdr.h>
32#include <freerdp/channels/channels.h>
33#include <freerdp/channels/cliprdr.h>
34
35#include <freerdp/client/client_cliprdr_file.h>
36
37#include "wlf_cliprdr.h"
38
39#define TAG CLIENT_TAG("wayland.cliprdr")
40
41#define mime_text_plain "text/plain"
42// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
43static const char mime_text_utf8[] = mime_text_plain ";charset=utf-8";
44
45// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
46static const char* mime_text[] = { mime_text_plain, mime_text_utf8, "UTF8_STRING",
47 "COMPOUND_TEXT", "TEXT", "STRING" };
48
49static const char mime_png[] = "image/png";
50static const char mime_webp[] = "image/webp";
51static const char mime_jpg[] = "image/jpeg";
52static const char mime_tiff[] = "image/tiff";
53static const char mime_uri_list[] = "text/uri-list";
54static const char mime_html[] = "text/html";
55
56#define BMP_MIME_LIST "image/bmp", "image/x-bmp", "image/x-MS-bmp", "image/x-win-bitmap"
57static const char* mime_bitmap[] = { BMP_MIME_LIST };
58static const char* mime_image[] = { mime_png, mime_webp, mime_jpg, mime_tiff, BMP_MIME_LIST };
59
60static const char mime_gnome_copied_files[] = "x-special/gnome-copied-files";
61static const char mime_mate_copied_files[] = "x-special/mate-copied-files";
62
63static const char type_FileGroupDescriptorW[] = "FileGroupDescriptorW";
64static const char type_HtmlFormat[] = "HTML Format";
65
66typedef struct
67{
68 FILE* responseFile;
69 UINT32 responseFormat;
70 char* responseMime;
71} wlf_request;
72
73typedef struct
74{
75 const FILE* responseFile;
76 UINT32 responseFormat;
77 const char* responseMime;
78} wlf_const_request;
79
80struct wlf_clipboard
81{
82 wlfContext* wfc;
83 rdpChannels* channels;
84 CliprdrClientContext* context;
85 wLog* log;
86
87 UwacSeat* seat;
88 wClipboard* system;
89
90 size_t numClientFormats;
91 CLIPRDR_FORMAT* clientFormats;
92
93 size_t numServerFormats;
94 CLIPRDR_FORMAT* serverFormats;
95
96 BOOL sync;
97
99 CliprdrFileContext* file;
100
101 wQueue* request_queue;
102};
103
104static void wlf_request_free(void* rq)
105{
106 wlf_request* request = rq;
107 if (request)
108 {
109 free(request->responseMime);
110 if (request->responseFile)
111 (void)fclose(request->responseFile);
112 }
113 free(request);
114}
115
116static wlf_request* wlf_request_new(void)
117{
118 return calloc(1, sizeof(wlf_request));
119}
120
121static void* wlf_request_clone(const void* oth)
122{
123 const wlf_request* other = (const wlf_request*)oth;
124 wlf_request* copy = wlf_request_new();
125 if (!copy)
126 return NULL;
127 *copy = *other;
128 if (other->responseMime)
129 {
130 copy->responseMime = _strdup(other->responseMime);
131 if (!copy->responseMime)
132 goto fail;
133 }
134 return copy;
135fail:
136 wlf_request_free(copy);
137 return NULL;
138}
139
140static BOOL wlf_mime_is_file(const char* mime)
141{
142 if (strncmp(mime_uri_list, mime, sizeof(mime_uri_list)) == 0)
143 return TRUE;
144 if (strncmp(mime_gnome_copied_files, mime, sizeof(mime_gnome_copied_files)) == 0)
145 return TRUE;
146 if (strncmp(mime_mate_copied_files, mime, sizeof(mime_mate_copied_files)) == 0)
147 return TRUE;
148 return FALSE;
149}
150
151static BOOL wlf_mime_is_text(const char* mime)
152{
153 for (size_t x = 0; x < ARRAYSIZE(mime_text); x++)
154 {
155 if (strcmp(mime, mime_text[x]) == 0)
156 return TRUE;
157 }
158
159 return FALSE;
160}
161
162static BOOL wlf_mime_is_image(const char* mime)
163{
164 for (size_t x = 0; x < ARRAYSIZE(mime_image); x++)
165 {
166 if (strcmp(mime, mime_image[x]) == 0)
167 return TRUE;
168 }
169
170 return FALSE;
171}
172
173static BOOL wlf_mime_is_html(const char* mime)
174{
175 if (strcmp(mime, mime_html) == 0)
176 return TRUE;
177
178 return FALSE;
179}
180
181static void wlf_cliprdr_free_server_formats(wfClipboard* clipboard)
182{
183 if (clipboard && clipboard->serverFormats)
184 {
185 for (size_t j = 0; j < clipboard->numServerFormats; j++)
186 {
187 CLIPRDR_FORMAT* format = &clipboard->serverFormats[j];
188 free(format->formatName);
189 }
190
191 free(clipboard->serverFormats);
192 clipboard->serverFormats = NULL;
193 clipboard->numServerFormats = 0;
194 }
195
196 if (clipboard)
197 UwacClipboardOfferDestroy(clipboard->seat);
198}
199
200static void wlf_cliprdr_free_client_formats(wfClipboard* clipboard)
201{
202 if (clipboard && clipboard->numClientFormats)
203 {
204 for (size_t j = 0; j < clipboard->numClientFormats; j++)
205 {
206 CLIPRDR_FORMAT* format = &clipboard->clientFormats[j];
207 free(format->formatName);
208 }
209
210 free(clipboard->clientFormats);
211 clipboard->clientFormats = NULL;
212 clipboard->numClientFormats = 0;
213 }
214
215 if (clipboard)
216 UwacClipboardOfferDestroy(clipboard->seat);
217}
218
224static UINT wlf_cliprdr_send_client_format_list(wfClipboard* clipboard)
225{
226 WINPR_ASSERT(clipboard);
227
228 const CLIPRDR_FORMAT_LIST formatList = { .common.msgFlags = 0,
229 .numFormats = (UINT32)clipboard->numClientFormats,
230 .formats = clipboard->clientFormats,
231 .common.msgType = CB_FORMAT_LIST };
232
233 cliprdr_file_context_clear(clipboard->file);
234
235 WLog_VRB(TAG, "-------------- client format list [%" PRIu32 "] ------------------",
236 formatList.numFormats);
237 for (UINT32 x = 0; x < formatList.numFormats; x++)
238 {
239 const CLIPRDR_FORMAT* format = &formatList.formats[x];
240 WLog_VRB(TAG, "client announces %" PRIu32 " [%s][%s]", format->formatId,
241 ClipboardGetFormatIdString(format->formatId), format->formatName);
242 }
243 WINPR_ASSERT(clipboard->context);
244 WINPR_ASSERT(clipboard->context->ClientFormatList);
245 return clipboard->context->ClientFormatList(clipboard->context, &formatList);
246}
247
248static void wfl_cliprdr_add_client_format_id(wfClipboard* clipboard, UINT32 formatId)
249{
250 CLIPRDR_FORMAT* format = NULL;
251 const char* name = ClipboardGetFormatName(clipboard->system, formatId);
252
253 for (size_t x = 0; x < clipboard->numClientFormats; x++)
254 {
255 format = &clipboard->clientFormats[x];
256
257 if (format->formatId == formatId)
258 return;
259 }
260
261 format = realloc(clipboard->clientFormats,
262 (clipboard->numClientFormats + 1) * sizeof(CLIPRDR_FORMAT));
263
264 if (!format)
265 return;
266
267 clipboard->clientFormats = format;
268 format = &clipboard->clientFormats[clipboard->numClientFormats++];
269 format->formatId = formatId;
270 format->formatName = NULL;
271
272 if (name && (formatId >= CF_MAX))
273 format->formatName = _strdup(name);
274}
275
276static BOOL wlf_cliprdr_add_client_format(wfClipboard* clipboard, const char* mime)
277{
278 WINPR_ASSERT(mime);
279 ClipboardLock(clipboard->system);
280 if (wlf_mime_is_html(mime))
281 {
282 UINT32 formatId = ClipboardGetFormatId(clipboard->system, type_HtmlFormat);
283 wfl_cliprdr_add_client_format_id(clipboard, formatId);
284 }
285 else if (wlf_mime_is_text(mime))
286 {
287 wfl_cliprdr_add_client_format_id(clipboard, CF_TEXT);
288 wfl_cliprdr_add_client_format_id(clipboard, CF_OEMTEXT);
289 wfl_cliprdr_add_client_format_id(clipboard, CF_UNICODETEXT);
290 }
291 else if (wlf_mime_is_image(mime))
292 {
293 for (size_t x = 0; x < ARRAYSIZE(mime_image); x++)
294 {
295 const char* mime_bmp = mime_image[x];
296 UINT32 formatId = ClipboardGetFormatId(clipboard->system, mime_bmp);
297 if (formatId != 0)
298 wfl_cliprdr_add_client_format_id(clipboard, formatId);
299 }
300 wfl_cliprdr_add_client_format_id(clipboard, CF_DIB);
301 wfl_cliprdr_add_client_format_id(clipboard, CF_TIFF);
302 }
303 else if (wlf_mime_is_file(mime))
304 {
305 const UINT32 fileFormatId =
306 ClipboardGetFormatId(clipboard->system, type_FileGroupDescriptorW);
307 wfl_cliprdr_add_client_format_id(clipboard, fileFormatId);
308 }
309
310 ClipboardUnlock(clipboard->system);
311 if (wlf_cliprdr_send_client_format_list(clipboard) != CHANNEL_RC_OK)
312 return FALSE;
313 return TRUE;
314}
315
321static UINT wlf_cliprdr_send_data_request(wfClipboard* clipboard, const wlf_const_request* rq)
322{
323 WINPR_ASSERT(rq);
324
325 CLIPRDR_FORMAT_DATA_REQUEST request = { .requestedFormatId = rq->responseFormat };
326
327 if (!Queue_Enqueue(clipboard->request_queue, rq))
328 return ERROR_INTERNAL_ERROR;
329
330 WINPR_ASSERT(clipboard);
331 WINPR_ASSERT(clipboard->context);
332 WINPR_ASSERT(clipboard->context->ClientFormatDataRequest);
333 return clipboard->context->ClientFormatDataRequest(clipboard->context, &request);
334}
335
341static UINT wlf_cliprdr_send_data_response(wfClipboard* clipboard, const BYTE* data, size_t size)
342{
343 CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
344
345 if (size > UINT32_MAX)
346 return ERROR_INVALID_PARAMETER;
347
348 response.common.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
349 response.common.dataLen = (UINT32)size;
350 response.requestedFormatData = data;
351
352 WINPR_ASSERT(clipboard);
353 WINPR_ASSERT(clipboard->context);
354 WINPR_ASSERT(clipboard->context->ClientFormatDataResponse);
355 return clipboard->context->ClientFormatDataResponse(clipboard->context, &response);
356}
357
358BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event)
359{
360 if (!clipboard || !event)
361 return FALSE;
362
363 if (!clipboard->context)
364 return TRUE;
365
366 switch (event->type)
367 {
368 case UWAC_EVENT_CLIPBOARD_AVAILABLE:
369 clipboard->seat = event->seat;
370 return TRUE;
371
372 case UWAC_EVENT_CLIPBOARD_OFFER:
373 WLog_Print(clipboard->log, WLOG_DEBUG, "client announces mime %s", event->mime);
374 return wlf_cliprdr_add_client_format(clipboard, event->mime);
375
376 case UWAC_EVENT_CLIPBOARD_SELECT:
377 WLog_Print(clipboard->log, WLOG_DEBUG, "client announces new data");
378 wlf_cliprdr_free_client_formats(clipboard);
379 return TRUE;
380
381 default:
382 return FALSE;
383 }
384}
385
391static UINT wlf_cliprdr_send_client_capabilities(wfClipboard* clipboard)
392{
393 WINPR_ASSERT(clipboard);
394
395 CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet = {
396 .capabilitySetType = CB_CAPSTYPE_GENERAL,
397 .capabilitySetLength = 12,
398 .version = CB_CAPS_VERSION_2,
399 .generalFlags =
400 CB_USE_LONG_FORMAT_NAMES | cliprdr_file_context_current_flags(clipboard->file)
401 };
402 CLIPRDR_CAPABILITIES capabilities = { .cCapabilitiesSets = 1,
403 .capabilitySets =
404 (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet) };
405
406 WINPR_ASSERT(clipboard);
407 WINPR_ASSERT(clipboard->context);
408 WINPR_ASSERT(clipboard->context->ClientCapabilities);
409 return clipboard->context->ClientCapabilities(clipboard->context, &capabilities);
410}
411
417static UINT wlf_cliprdr_send_client_format_list_response(wfClipboard* clipboard, BOOL status)
418{
419 const CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = {
420 .common.msgType = CB_FORMAT_LIST_RESPONSE,
421 .common.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL,
422 .common.dataLen = 0
423 };
424 WINPR_ASSERT(clipboard);
425 WINPR_ASSERT(clipboard->context);
426 WINPR_ASSERT(clipboard->context->ClientFormatListResponse);
427 return clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse);
428}
429
435static UINT wlf_cliprdr_monitor_ready(CliprdrClientContext* context,
436 const CLIPRDR_MONITOR_READY* monitorReady)
437{
438 UINT ret = 0;
439
440 WINPR_UNUSED(monitorReady);
441 WINPR_ASSERT(context);
442 WINPR_ASSERT(monitorReady);
443
444 wfClipboard* clipboard = cliprdr_file_context_get_context(context->custom);
445 WINPR_ASSERT(clipboard);
446
447 if ((ret = wlf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK)
448 return ret;
449
450 if ((ret = wlf_cliprdr_send_client_format_list(clipboard)) != CHANNEL_RC_OK)
451 return ret;
452
453 clipboard->sync = TRUE;
454 return CHANNEL_RC_OK;
455}
456
462static UINT wlf_cliprdr_server_capabilities(CliprdrClientContext* context,
463 const CLIPRDR_CAPABILITIES* capabilities)
464{
465 WINPR_ASSERT(context);
466 WINPR_ASSERT(capabilities);
467
468 const BYTE* capsPtr = (const BYTE*)capabilities->capabilitySets;
469 WINPR_ASSERT(capsPtr);
470
471 wfClipboard* clipboard = cliprdr_file_context_get_context(context->custom);
472 WINPR_ASSERT(clipboard);
473
474 if (!cliprdr_file_context_remote_set_flags(clipboard->file, 0))
475 return ERROR_INTERNAL_ERROR;
476
477 for (UINT32 i = 0; i < capabilities->cCapabilitiesSets; i++)
478 {
479 const CLIPRDR_CAPABILITY_SET* caps = (const CLIPRDR_CAPABILITY_SET*)capsPtr;
480
481 if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
482 {
483 const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps =
485
486 if (!cliprdr_file_context_remote_set_flags(clipboard->file, generalCaps->generalFlags))
487 return ERROR_INTERNAL_ERROR;
488 }
489
490 capsPtr += caps->capabilitySetLength;
491 }
492
493 return CHANNEL_RC_OK;
494}
495
496static UINT32 wlf_get_server_format_id(const wfClipboard* clipboard, const char* name)
497{
498 WINPR_ASSERT(clipboard);
499 WINPR_ASSERT(name);
500
501 for (UINT32 x = 0; x < clipboard->numServerFormats; x++)
502 {
503 const CLIPRDR_FORMAT* format = &clipboard->serverFormats[x];
504 if (!format->formatName)
505 continue;
506 if (strcmp(name, format->formatName) == 0)
507 return format->formatId;
508 }
509 return 0;
510}
511
512static const char* wlf_get_server_format_name(const wfClipboard* clipboard, UINT32 formatId)
513{
514 WINPR_ASSERT(clipboard);
515
516 for (UINT32 x = 0; x < clipboard->numServerFormats; x++)
517 {
518 const CLIPRDR_FORMAT* format = &clipboard->serverFormats[x];
519 if (format->formatId == formatId)
520 return format->formatName;
521 }
522 return NULL;
523}
524
525static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* mime, int fd)
526{
527 wfClipboard* clipboard = (wfClipboard*)context;
528 WINPR_UNUSED(seat);
529
530 EnterCriticalSection(&clipboard->lock);
531
532 wlf_const_request request = { 0 };
533 if (wlf_mime_is_html(mime))
534 {
535 request.responseMime = mime_html;
536 request.responseFormat = wlf_get_server_format_id(clipboard, type_HtmlFormat);
537 }
538 else if (wlf_mime_is_file(mime))
539 {
540 request.responseMime = mime;
541 request.responseFormat = wlf_get_server_format_id(clipboard, type_FileGroupDescriptorW);
542 }
543 else if (wlf_mime_is_text(mime))
544 {
545 request.responseMime = mime_text_plain;
546 request.responseFormat = CF_UNICODETEXT;
547 }
548 else if (wlf_mime_is_image(mime))
549 {
550 request.responseMime = mime;
551 if (strcmp(mime, mime_tiff) == 0)
552 request.responseFormat = CF_TIFF;
553 else
554 request.responseFormat = CF_DIB;
555 }
556
557 if (request.responseMime != NULL)
558 {
559 request.responseFile = fdopen(fd, "w");
560
561 if (request.responseFile)
562 wlf_cliprdr_send_data_request(clipboard, &request);
563 else
564 WLog_Print(clipboard->log, WLOG_ERROR,
565 "failed to open clipboard file descriptor for MIME %s",
566 request.responseMime);
567 }
568
569 LeaveCriticalSection(&clipboard->lock);
570}
571
572static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context)
573{
574 wfClipboard* clipboard = (wfClipboard*)context;
575
576 WINPR_UNUSED(seat);
577 WINPR_ASSERT(clipboard);
578 cliprdr_file_context_clear(clipboard->file);
579}
580
589static UINT wlf_cliprdr_server_format_list(CliprdrClientContext* context,
590 const CLIPRDR_FORMAT_LIST* formatList)
591{
592 BOOL html = FALSE;
593 BOOL text = FALSE;
594 BOOL image = FALSE;
595 BOOL file = FALSE;
596
597 if (!context || !context->custom)
598 return ERROR_INVALID_PARAMETER;
599
600 wfClipboard* clipboard = cliprdr_file_context_get_context(context->custom);
601 WINPR_ASSERT(clipboard);
602
603 wlf_cliprdr_free_server_formats(clipboard);
604 cliprdr_file_context_clear(clipboard->file);
605
606 if (!(clipboard->serverFormats =
607 (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT))))
608 {
609 WLog_Print(clipboard->log, WLOG_ERROR,
610 "failed to allocate %" PRIuz " CLIPRDR_FORMAT structs",
611 clipboard->numServerFormats);
612 return CHANNEL_RC_NO_MEMORY;
613 }
614
615 clipboard->numServerFormats = formatList->numFormats;
616
617 if (!clipboard->seat)
618 {
619 WLog_Print(clipboard->log, WLOG_ERROR,
620 "clipboard->seat=NULL, check your client implementation");
621 return ERROR_INTERNAL_ERROR;
622 }
623
624 for (UINT32 i = 0; i < formatList->numFormats; i++)
625 {
626 const CLIPRDR_FORMAT* format = &formatList->formats[i];
627 CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i];
628 srvFormat->formatId = format->formatId;
629
630 if (format->formatName)
631 {
632 srvFormat->formatName = _strdup(format->formatName);
633
634 if (!srvFormat->formatName)
635 {
636 wlf_cliprdr_free_server_formats(clipboard);
637 return CHANNEL_RC_NO_MEMORY;
638 }
639 }
640
641 if (format->formatName)
642 {
643 if (strcmp(format->formatName, type_HtmlFormat) == 0)
644 {
645 text = TRUE;
646 html = TRUE;
647 }
648 else if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0)
649 {
650 file = TRUE;
651 text = TRUE;
652 }
653 }
654 else
655 {
656 switch (format->formatId)
657 {
658 case CF_TEXT:
659 case CF_OEMTEXT:
660 case CF_UNICODETEXT:
661 text = TRUE;
662 break;
663
664 case CF_DIB:
665 image = TRUE;
666 break;
667
668 default:
669 break;
670 }
671 }
672 }
673
674 if (html)
675 {
676 UwacClipboardOfferCreate(clipboard->seat, mime_html);
677 }
678
679 if (file && cliprdr_file_context_has_local_support(clipboard->file))
680 {
681 UwacClipboardOfferCreate(clipboard->seat, mime_uri_list);
682 UwacClipboardOfferCreate(clipboard->seat, mime_gnome_copied_files);
683 UwacClipboardOfferCreate(clipboard->seat, mime_mate_copied_files);
684 }
685
686 if (text)
687 {
688 for (size_t x = 0; x < ARRAYSIZE(mime_text); x++)
689 UwacClipboardOfferCreate(clipboard->seat, mime_text[x]);
690 }
691
692 if (image)
693 {
694 for (size_t x = 0; x < ARRAYSIZE(mime_image); x++)
695 UwacClipboardOfferCreate(clipboard->seat, mime_image[x]);
696 }
697
698 UwacClipboardOfferAnnounce(clipboard->seat, clipboard, wlf_cliprdr_transfer_data,
699 wlf_cliprdr_cancel_data);
700 return wlf_cliprdr_send_client_format_list_response(clipboard, TRUE);
701}
702
708static UINT
709wlf_cliprdr_server_format_list_response(WINPR_ATTR_UNUSED CliprdrClientContext* context,
710 const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
711{
712 WINPR_ASSERT(context);
713 WINPR_ASSERT(formatListResponse);
714
715 if (formatListResponse->common.msgFlags & CB_RESPONSE_FAIL)
716 WLog_WARN(TAG, "format list update failed");
717 return CHANNEL_RC_OK;
718}
719
725static UINT
726wlf_cliprdr_server_format_data_request(CliprdrClientContext* context,
727 const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
728{
729 UINT rc = CHANNEL_RC_OK;
730 char* data = NULL;
731 size_t size = 0;
732 const char* mime = NULL;
733 UINT32 formatId = 0;
734 UINT32 localFormatId = 0;
735 wfClipboard* clipboard = 0;
736
737 UINT32 dsize = 0;
738 BYTE* ddata = NULL;
739
740 WINPR_ASSERT(context);
741 WINPR_ASSERT(formatDataRequest);
742
743 localFormatId = formatId = formatDataRequest->requestedFormatId;
744 clipboard = cliprdr_file_context_get_context(context->custom);
745 WINPR_ASSERT(clipboard);
746
747 ClipboardLock(clipboard->system);
748 const UINT32 fileFormatId = ClipboardGetFormatId(clipboard->system, type_FileGroupDescriptorW);
749 const UINT32 htmlFormatId = ClipboardGetFormatId(clipboard->system, type_HtmlFormat);
750
751 switch (formatId)
752 {
753 case CF_TEXT:
754 case CF_OEMTEXT:
755 case CF_UNICODETEXT:
756 localFormatId = ClipboardGetFormatId(clipboard->system, mime_text_plain);
757 mime = mime_text_utf8;
758 break;
759
760 case CF_DIB:
761 case CF_DIBV5:
762 mime = mime_bitmap[0];
763 break;
764
765 case CF_TIFF:
766 mime = mime_tiff;
767 break;
768
769 default:
770 if (formatId == fileFormatId)
771 {
772 localFormatId = ClipboardGetFormatId(clipboard->system, mime_uri_list);
773 mime = mime_uri_list;
774 }
775 else if (formatId == htmlFormatId)
776 {
777 localFormatId = ClipboardGetFormatId(clipboard->system, mime_html);
778 mime = mime_html;
779 }
780 else
781 goto fail;
782 break;
783 }
784
785 data = UwacClipboardDataGet(clipboard->seat, mime, &size);
786
787 if (!data || (size > UINT32_MAX))
788 goto fail;
789
790 if (fileFormatId == formatId)
791 {
792 if (!cliprdr_file_context_update_client_data(clipboard->file, data, size))
793 goto fail;
794 }
795
796 {
797 const BOOL res = ClipboardSetData(clipboard->system, localFormatId, data, (UINT32)size);
798 free(data);
799
800 UINT32 len = 0;
801 data = NULL;
802 if (res)
803 data = ClipboardGetData(clipboard->system, formatId, &len);
804
805 if (!res || !data)
806 goto fail;
807
808 if (fileFormatId == formatId)
809 {
810 const UINT32 flags = cliprdr_file_context_remote_get_flags(clipboard->file);
811 const UINT32 error = cliprdr_serialize_file_list_ex(
812 flags, (const FILEDESCRIPTORW*)data, len / sizeof(FILEDESCRIPTORW), &ddata, &dsize);
813 if (error)
814 goto fail;
815 }
816 }
817fail:
818 ClipboardUnlock(clipboard->system);
819 rc = wlf_cliprdr_send_data_response(clipboard, ddata, dsize);
820 free(data);
821 return rc;
822}
823
829static UINT
830wlf_cliprdr_server_format_data_response(CliprdrClientContext* context,
831 const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
832{
833 UINT rc = ERROR_INTERNAL_ERROR;
834
835 WINPR_ASSERT(context);
836 WINPR_ASSERT(formatDataResponse);
837
838 const UINT32 size = formatDataResponse->common.dataLen;
839 const BYTE* data = formatDataResponse->requestedFormatData;
840
841 wfClipboard* clipboard = cliprdr_file_context_get_context(context->custom);
842 WINPR_ASSERT(clipboard);
843
844 wlf_request* request = Queue_Dequeue(clipboard->request_queue);
845 if (!request)
846 goto fail;
847
848 rc = CHANNEL_RC_OK;
849 if (formatDataResponse->common.msgFlags & CB_RESPONSE_FAIL)
850 {
851 WLog_WARN(TAG, "clipboard data request for format %" PRIu32 " [%s], mime %s failed",
852 request->responseFormat, ClipboardGetFormatIdString(request->responseFormat),
853 request->responseMime);
854 goto fail;
855 }
856 rc = ERROR_INTERNAL_ERROR;
857
858 ClipboardLock(clipboard->system);
859 EnterCriticalSection(&clipboard->lock);
860 {
861 BYTE* cdata = NULL;
862 UINT32 srcFormatId = 0;
863 UINT32 dstFormatId = 0;
864 switch (request->responseFormat)
865 {
866 case CF_TEXT:
867 case CF_OEMTEXT:
868 case CF_UNICODETEXT:
869 srcFormatId = request->responseFormat;
870 dstFormatId = ClipboardGetFormatId(clipboard->system, request->responseMime);
871 break;
872
873 case CF_DIB:
874 case CF_DIBV5:
875 srcFormatId = request->responseFormat;
876 dstFormatId = ClipboardGetFormatId(clipboard->system, request->responseMime);
877 break;
878
879 default:
880 {
881 const char* name = wlf_get_server_format_name(clipboard, request->responseFormat);
882 if (name)
883 {
884 if (strcmp(type_FileGroupDescriptorW, name) == 0)
885 {
886 srcFormatId =
887 ClipboardGetFormatId(clipboard->system, type_FileGroupDescriptorW);
888 dstFormatId =
889 ClipboardGetFormatId(clipboard->system, request->responseMime);
890
891 if (!cliprdr_file_context_update_server_data(clipboard->file,
892 clipboard->system, data, size))
893 goto unlock;
894 }
895 else if (strcmp(type_HtmlFormat, name) == 0)
896 {
897 srcFormatId = ClipboardGetFormatId(clipboard->system, type_HtmlFormat);
898 dstFormatId =
899 ClipboardGetFormatId(clipboard->system, request->responseMime);
900 }
901 }
902 }
903 break;
904 }
905 {
906 UINT32 len = 0;
907
908 {
909 const BOOL sres = ClipboardSetData(clipboard->system, srcFormatId, data, size);
910 if (sres)
911 cdata = ClipboardGetData(clipboard->system, dstFormatId, &len);
912
913 if (!sres || !cdata)
914 goto unlock;
915 }
916
917 if (request->responseFile)
918 {
919 const size_t res = fwrite(cdata, 1, len, request->responseFile);
920 if (res == len)
921 rc = CHANNEL_RC_OK;
922 }
923 else
924 rc = CHANNEL_RC_OK;
925 }
926
927 unlock:
928 free(cdata);
929 }
930 ClipboardUnlock(clipboard->system);
931 LeaveCriticalSection(&clipboard->lock);
932fail:
933 wlf_request_free(request);
934 return rc;
935}
936
937wfClipboard* wlf_clipboard_new(wlfContext* wfc)
938{
939 rdpChannels* channels = NULL;
940 wfClipboard* clipboard = NULL;
941
942 WINPR_ASSERT(wfc);
943
944 clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard));
945
946 if (!clipboard)
947 goto fail;
948
949 InitializeCriticalSection(&clipboard->lock);
950 clipboard->wfc = wfc;
951 channels = wfc->common.context.channels;
952 clipboard->log = WLog_Get(TAG);
953 clipboard->channels = channels;
954 clipboard->system = ClipboardCreate();
955 if (!clipboard->system)
956 goto fail;
957
958 clipboard->file = cliprdr_file_context_new(clipboard);
959 if (!clipboard->file)
960 goto fail;
961
962 if (!cliprdr_file_context_set_locally_available(clipboard->file, TRUE))
963 goto fail;
964
965 clipboard->request_queue = Queue_New(TRUE, -1, -1);
966 if (!clipboard->request_queue)
967 goto fail;
968
969 {
970 wObject* obj = Queue_Object(clipboard->request_queue);
971 WINPR_ASSERT(obj);
972 obj->fnObjectFree = wlf_request_free;
973 obj->fnObjectNew = wlf_request_clone;
974 }
975
976 return clipboard;
977
978fail:
979 wlf_clipboard_free(clipboard);
980 return NULL;
981}
982
983void wlf_clipboard_free(wfClipboard* clipboard)
984{
985 if (!clipboard)
986 return;
987
988 cliprdr_file_context_free(clipboard->file);
989
990 wlf_cliprdr_free_server_formats(clipboard);
991 wlf_cliprdr_free_client_formats(clipboard);
992 ClipboardDestroy(clipboard->system);
993
994 EnterCriticalSection(&clipboard->lock);
995
996 Queue_Free(clipboard->request_queue);
997 LeaveCriticalSection(&clipboard->lock);
998 DeleteCriticalSection(&clipboard->lock);
999 free(clipboard);
1000}
1001
1002BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
1003{
1004 WINPR_ASSERT(clipboard);
1005 WINPR_ASSERT(cliprdr);
1006
1007 clipboard->context = cliprdr;
1008 cliprdr->MonitorReady = wlf_cliprdr_monitor_ready;
1009 cliprdr->ServerCapabilities = wlf_cliprdr_server_capabilities;
1010 cliprdr->ServerFormatList = wlf_cliprdr_server_format_list;
1011 cliprdr->ServerFormatListResponse = wlf_cliprdr_server_format_list_response;
1012 cliprdr->ServerFormatDataRequest = wlf_cliprdr_server_format_data_request;
1013 cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response;
1014
1015 return cliprdr_file_context_init(clipboard->file, cliprdr);
1016}
1017
1018BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
1019{
1020 WINPR_ASSERT(clipboard);
1021 if (!cliprdr_file_context_uninit(clipboard->file, cliprdr))
1022 return FALSE;
1023
1024 if (cliprdr)
1025 cliprdr->custom = NULL;
1026
1027 return TRUE;
1028}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57