FreeRDP
Loading...
Searching...
No Matches
ios_cliprdr.m
1
23#include <freerdp/config.h>
24
25#include <winpr/crt.h>
26#include <winpr/stream.h>
27#include <winpr/clipboard.h>
28
29#include <freerdp/client/channels.h>
30#include <freerdp/client/cliprdr.h>
31
32#include "ios_cliprdr.h"
33#include "ios_freerdp_ui.h"
34
35static void ios_cliprdr_free_formats(CLIPRDR_FORMAT *formats, UINT32 numFormats)
36{
37 if (!formats)
38 return;
39
40 for (UINT32 index = 0; index < numFormats; index++)
41 free(formats[index].formatName);
42
43 free(formats);
44}
45
46UINT ios_cliprdr_send_client_format_list(CliprdrClientContext *cliprdr)
47{
48 CLIPRDR_FORMAT format = WINPR_C_ARRAY_INIT;
49 CLIPRDR_FORMAT_LIST formatList = WINPR_C_ARRAY_INIT;
50
51 if (!cliprdr || !cliprdr->ClientFormatList)
52 return ERROR_INVALID_PARAMETER;
53
54 mfContext *afc = (mfContext *)cliprdr->custom;
55
56 if (!afc)
57 return ERROR_INVALID_PARAMETER;
58
59 // Only announce the text; it is read from the pasteboard when the server requests it, since
60 // reading another app's pasteboard can show the paste permission alert.
61 format.formatId = CF_UNICODETEXT;
62 formatList.common.msgFlags = 0;
63 formatList.numFormats = afc->clipboardHasText ? 1 : 0;
64 formatList.formats = &format;
65 formatList.common.msgType = CB_FORMAT_LIST;
66 return cliprdr->ClientFormatList(cliprdr, &formatList);
67}
68
69static UINT ios_cliprdr_send_client_format_data_request(CliprdrClientContext *cliprdr,
70 UINT32 formatId)
71{
72 UINT rc = ERROR_INVALID_PARAMETER;
73 CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = WINPR_C_ARRAY_INIT;
74 mfContext *afc;
75
76 if (!cliprdr)
77 goto fail;
78
79 afc = (mfContext *)cliprdr->custom;
80
81 if (!afc || !afc->clipboardRequestEvent || !cliprdr->ClientFormatDataRequest)
82 goto fail;
83
84 formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
85 formatDataRequest.common.msgFlags = 0;
86 formatDataRequest.requestedFormatId = formatId;
87 afc->requestedFormatId = formatId;
88 (void)ResetEvent(afc->clipboardRequestEvent);
89 rc = cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest);
90fail:
91 return rc;
92}
93
94static UINT ios_cliprdr_send_client_capabilities(CliprdrClientContext *cliprdr)
95{
96 CLIPRDR_CAPABILITIES capabilities;
97 CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
98
99 if (!cliprdr || !cliprdr->ClientCapabilities)
100 return ERROR_INVALID_PARAMETER;
101
102 capabilities.cCapabilitiesSets = 1;
103 capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet);
104 generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
105 generalCapabilitySet.capabilitySetLength = 12;
106 generalCapabilitySet.version = CB_CAPS_VERSION_2;
107 generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
108 return cliprdr->ClientCapabilities(cliprdr, &capabilities);
109}
110
116static UINT ios_cliprdr_monitor_ready(CliprdrClientContext *cliprdr,
117 const CLIPRDR_MONITOR_READY *monitorReady)
118{
119 UINT rc;
120 mfContext *afc;
121
122 if (!cliprdr || !monitorReady)
123 return ERROR_INVALID_PARAMETER;
124
125 afc = (mfContext *)cliprdr->custom;
126
127 if (!afc)
128 return ERROR_INVALID_PARAMETER;
129
130 if ((rc = ios_cliprdr_send_client_capabilities(cliprdr)) != CHANNEL_RC_OK)
131 return rc;
132
133 if ((rc = ios_cliprdr_send_client_format_list(cliprdr)) != CHANNEL_RC_OK)
134 return rc;
135
136 afc->clipboardSync = TRUE;
137 return CHANNEL_RC_OK;
138}
139
145static UINT ios_cliprdr_server_capabilities(CliprdrClientContext *cliprdr,
146 const CLIPRDR_CAPABILITIES *capabilities)
147{
148 CLIPRDR_CAPABILITY_SET *capabilitySet;
149 mfContext *afc;
150
151 if (!cliprdr || !capabilities)
152 return ERROR_INVALID_PARAMETER;
153
154 afc = (mfContext *)cliprdr->custom;
155
156 if (!afc)
157 return ERROR_INVALID_PARAMETER;
158
159 for (UINT32 index = 0; index < capabilities->cCapabilitiesSets; index++)
160 {
161 capabilitySet = &(capabilities->capabilitySets[index]);
162
163 if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) &&
164 (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN))
165 {
166 CLIPRDR_GENERAL_CAPABILITY_SET *generalCapabilitySet =
167 (CLIPRDR_GENERAL_CAPABILITY_SET *)capabilitySet;
168 afc->clipboardCapabilities = generalCapabilitySet->generalFlags;
169 break;
170 }
171 }
172
173 return CHANNEL_RC_OK;
174}
175
176static UINT ios_cliprdr_send_client_format_list_response(CliprdrClientContext *cliprdr, BOOL status)
177{
178 CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = WINPR_C_ARRAY_INIT;
179
180 formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
181 formatListResponse.common.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
182 formatListResponse.common.dataLen = 0;
183
184 if (!cliprdr || !cliprdr->ClientFormatListResponse)
185 return ERROR_INVALID_PARAMETER;
186
187 return cliprdr->ClientFormatListResponse(cliprdr, &formatListResponse);
188}
189
195static UINT ios_cliprdr_server_format_list(CliprdrClientContext *cliprdr,
196 const CLIPRDR_FORMAT_LIST *formatList)
197{
198 UINT rc;
199 CLIPRDR_FORMAT *format;
200 mfContext *afc;
201
202 if (!cliprdr || !formatList)
203 return ERROR_INVALID_PARAMETER;
204
205 afc = (mfContext *)cliprdr->custom;
206
207 if (!afc)
208 return ERROR_INVALID_PARAMETER;
209
210 ios_cliprdr_free_formats(afc->serverFormats, afc->numServerFormats);
211 afc->serverFormats = nullptr;
212 afc->numServerFormats = 0;
213
214 if (formatList->numFormats < 1)
215 return ios_cliprdr_send_client_format_list_response(cliprdr, TRUE);
216
217 afc->numServerFormats = formatList->numFormats;
218 afc->serverFormats = (CLIPRDR_FORMAT *)calloc(afc->numServerFormats, sizeof(CLIPRDR_FORMAT));
219
220 if (!afc->serverFormats)
221 return CHANNEL_RC_NO_MEMORY;
222
223 for (UINT32 index = 0; index < afc->numServerFormats; index++)
224 {
225 afc->serverFormats[index].formatId = formatList->formats[index].formatId;
226 afc->serverFormats[index].formatName = nullptr;
227
228 if (formatList->formats[index].formatName)
229 {
230 afc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName);
231
232 if (!afc->serverFormats[index].formatName)
233 return CHANNEL_RC_NO_MEMORY;
234 }
235 }
236
237 if ((rc = ios_cliprdr_send_client_format_list_response(cliprdr, TRUE)) != CHANNEL_RC_OK)
238 return rc;
239
240 BOOL unicode = FALSE;
241 BOOL text = FALSE;
242 for (UINT32 index = 0; index < afc->numServerFormats; index++)
243 {
244 format = &(afc->serverFormats[index]);
245
246 if (format->formatId == CF_UNICODETEXT)
247 unicode = TRUE;
248
249 else if (format->formatId == CF_TEXT)
250 text = TRUE;
251 }
252
253 if (unicode)
254 return ios_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT);
255 if (text)
256 return ios_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT);
257 return CHANNEL_RC_OK;
258}
259
265static UINT
266ios_cliprdr_server_format_list_response(CliprdrClientContext *cliprdr,
267 const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse)
268{
269 if (!cliprdr || !formatListResponse)
270 return ERROR_INVALID_PARAMETER;
271
272 return CHANNEL_RC_OK;
273}
274
280static UINT
281ios_cliprdr_server_lock_clipboard_data(CliprdrClientContext *cliprdr,
282 const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData)
283{
284 if (!cliprdr || !lockClipboardData)
285 return ERROR_INVALID_PARAMETER;
286
287 return CHANNEL_RC_OK;
288}
289
295static UINT
296ios_cliprdr_server_unlock_clipboard_data(CliprdrClientContext *cliprdr,
297 const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData)
298{
299 if (!cliprdr || !unlockClipboardData)
300 return ERROR_INVALID_PARAMETER;
301
302 return CHANNEL_RC_OK;
303}
304
310static UINT
311ios_cliprdr_server_format_data_request(CliprdrClientContext *cliprdr,
312 const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
313{
314 UINT rc;
315 BYTE *data = nullptr;
316 UINT32 size = 0;
317 UINT32 formatId;
318 CLIPRDR_FORMAT_DATA_RESPONSE response = WINPR_C_ARRAY_INIT;
319 mfContext *afc;
320
321 if (!cliprdr || !formatDataRequest || !cliprdr->ClientFormatDataResponse)
322 return ERROR_INVALID_PARAMETER;
323
324 afc = (mfContext *)cliprdr->custom;
325
326 if (!afc)
327 return ERROR_INVALID_PARAMETER;
328
329 formatId = formatDataRequest->requestedFormatId;
330
331 if ((formatId == CF_UNICODETEXT) || (formatId == CF_TEXT) || (formatId == CF_OEMTEXT))
332 {
333 char *text = ios_ui_get_clipboard_text((rdpContext *)afc);
334
335 if (text)
336 {
337 ClipboardLock(afc->clipboard);
338 if (ClipboardSetData(afc->clipboard,
339 ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"), text,
340 (UINT32)strlen(text)))
341 data = (BYTE *)ClipboardGetData(afc->clipboard, formatId, &size);
342 ClipboardUnlock(afc->clipboard);
343 free(text);
344 }
345 }
346
347 response.common.msgFlags = CB_RESPONSE_OK;
348 response.common.dataLen = size;
349 response.requestedFormatData = data;
350
351 if (!data)
352 {
353 response.common.msgFlags = CB_RESPONSE_FAIL;
354 response.common.dataLen = 0;
355 response.requestedFormatData = nullptr;
356 }
357
358 rc = cliprdr->ClientFormatDataResponse(cliprdr, &response);
359 free(data);
360 return rc;
361}
362
368static UINT
369ios_cliprdr_server_format_data_response(CliprdrClientContext *cliprdr,
370 const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse)
371{
372 BYTE *data;
373 UINT32 size;
374 UINT32 formatId;
375 CLIPRDR_FORMAT *format = nullptr;
376 mfContext *afc;
377 freerdp *instance;
378
379 if (!cliprdr || !formatDataResponse)
380 return ERROR_INVALID_PARAMETER;
381
382 afc = (mfContext *)cliprdr->custom;
383
384 if (!afc)
385 return ERROR_INVALID_PARAMETER;
386
387 instance = ((rdpContext *)afc)->instance;
388
389 if (!instance)
390 return ERROR_INVALID_PARAMETER;
391
392 for (UINT32 index = 0; index < afc->numServerFormats; index++)
393 {
394 if (afc->requestedFormatId == afc->serverFormats[index].formatId)
395 format = &(afc->serverFormats[index]);
396 }
397
398 if (!format)
399 {
400 (void)SetEvent(afc->clipboardRequestEvent);
401 return ERROR_INTERNAL_ERROR;
402 }
403
404 // Returning an error ends the channel thread and with it the session.
405 if (formatDataResponse->common.msgFlags & CB_RESPONSE_FAIL)
406 {
407 (void)SetEvent(afc->clipboardRequestEvent);
408 return CHANNEL_RC_OK;
409 }
410
411 if (format->formatName)
412 formatId = ClipboardRegisterFormat(afc->clipboard, format->formatName);
413 else
414 formatId = format->formatId;
415
416 size = formatDataResponse->common.dataLen;
417
418 ClipboardLock(afc->clipboard);
419 if (!ClipboardSetData(afc->clipboard, formatId, formatDataResponse->requestedFormatData, size))
420 {
421 ClipboardUnlock(afc->clipboard);
422 return ERROR_INTERNAL_ERROR;
423 }
424
425 (void)SetEvent(afc->clipboardRequestEvent);
426
427 if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT))
428 {
429 formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING");
430 data = (BYTE *)ClipboardGetData(afc->clipboard, formatId, &size);
431 if (data)
432 {
433 size = (UINT32)strnlen((const char *)data, size);
434 ios_ui_set_clipboard_text((rdpContext *)afc, (const char *)data, size);
435 }
436 free(data);
437 }
438 ClipboardUnlock(afc->clipboard);
439
440 return CHANNEL_RC_OK;
441}
442
448static UINT
449ios_cliprdr_server_file_contents_request(CliprdrClientContext *cliprdr,
450 const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest)
451{
452 if (!cliprdr || !fileContentsRequest)
453 return ERROR_INVALID_PARAMETER;
454
455 return CHANNEL_RC_OK;
456}
457
463static UINT ios_cliprdr_server_file_contents_response(
464 CliprdrClientContext *cliprdr, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse)
465{
466 if (!cliprdr || !fileContentsResponse)
467 return ERROR_INVALID_PARAMETER;
468
469 return CHANNEL_RC_OK;
470}
471
472BOOL ios_cliprdr_init(mfContext *afc, CliprdrClientContext *cliprdr)
473{
474 wClipboard *clipboard;
475 HANDLE hevent;
476
477 if (!afc || !cliprdr)
478 return FALSE;
479
480 if (!(hevent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
481 return FALSE;
482
483 if (!(clipboard = ClipboardCreate()))
484 {
485 (void)CloseHandle(hevent);
486 return FALSE;
487 }
488
489 afc->cliprdr = cliprdr;
490 afc->clipboard = clipboard;
491 afc->clipboardRequestEvent = hevent;
492 cliprdr->custom = (void *)afc;
493 cliprdr->MonitorReady = ios_cliprdr_monitor_ready;
494 cliprdr->ServerCapabilities = ios_cliprdr_server_capabilities;
495 cliprdr->ServerFormatList = ios_cliprdr_server_format_list;
496 cliprdr->ServerFormatListResponse = ios_cliprdr_server_format_list_response;
497 cliprdr->ServerLockClipboardData = ios_cliprdr_server_lock_clipboard_data;
498 cliprdr->ServerUnlockClipboardData = ios_cliprdr_server_unlock_clipboard_data;
499 cliprdr->ServerFormatDataRequest = ios_cliprdr_server_format_data_request;
500 cliprdr->ServerFormatDataResponse = ios_cliprdr_server_format_data_response;
501 cliprdr->ServerFileContentsRequest = ios_cliprdr_server_file_contents_request;
502 cliprdr->ServerFileContentsResponse = ios_cliprdr_server_file_contents_response;
503 return TRUE;
504}
505
506BOOL ios_cliprdr_uninit(mfContext *afc, CliprdrClientContext *cliprdr)
507{
508 if (!afc || !cliprdr)
509 return FALSE;
510
511 cliprdr->custom = nullptr;
512 afc->cliprdr = nullptr;
513 afc->clipboardSync = FALSE;
514 ios_cliprdr_free_formats(afc->serverFormats, afc->numServerFormats);
515 afc->serverFormats = nullptr;
516 afc->numServerFormats = 0;
517 ClipboardDestroy(afc->clipboard);
518 (void)CloseHandle(afc->clipboardRequestEvent);
519 return TRUE;
520}