FreeRDP
Loading...
Searching...
No Matches
android_cliprdr.c
1
22#include <freerdp/config.h>
23
24#include <jni.h>
25
26#include <winpr/crt.h>
27#include <winpr/stream.h>
28
29#include <freerdp/client/channels.h>
30#include <freerdp/client/cliprdr.h>
31
32#include "android_cliprdr.h"
33#include "android_jni_utils.h"
34#include "android_jni_callback.h"
35
36UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr)
37{
38 UINT rc = ERROR_INTERNAL_ERROR;
39 UINT32 formatId;
40 UINT32 numFormats;
41 UINT32* pFormatIds;
42 const char* formatName;
43 CLIPRDR_FORMAT* formats;
44 CLIPRDR_FORMAT_LIST formatList = { 0 };
45
46 if (!cliprdr)
47 return ERROR_INVALID_PARAMETER;
48
49 androidContext* afc = (androidContext*)cliprdr->custom;
50
51 if (!afc || !afc->cliprdr)
52 return ERROR_INVALID_PARAMETER;
53
54 pFormatIds = NULL;
55 numFormats = ClipboardGetFormatIds(afc->clipboard, &pFormatIds);
56 formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT));
57
58 if (!formats)
59 goto fail;
60
61 for (UINT32 index = 0; index < numFormats; index++)
62 {
63 formatId = pFormatIds[index];
64 formatName = ClipboardGetFormatName(afc->clipboard, formatId);
65 formats[index].formatId = formatId;
66 formats[index].formatName = NULL;
67
68 if ((formatId > CF_MAX) && formatName)
69 {
70 formats[index].formatName = _strdup(formatName);
71
72 if (!formats[index].formatName)
73 goto fail;
74 }
75 }
76
77 formatList.common.msgFlags = 0;
78 formatList.numFormats = numFormats;
79 formatList.formats = formats;
80 formatList.common.msgType = CB_FORMAT_LIST;
81
82 if (!afc->cliprdr->ClientFormatList)
83 goto fail;
84
85 rc = afc->cliprdr->ClientFormatList(afc->cliprdr, &formatList);
86fail:
87 free(pFormatIds);
88 free(formats);
89 return rc;
90}
91
92static UINT android_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr,
93 UINT32 formatId)
94{
95 UINT rc = ERROR_INVALID_PARAMETER;
96 CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = { 0 };
97 androidContext* afc;
98
99 if (!cliprdr)
100 goto fail;
101
102 afc = (androidContext*)cliprdr->custom;
103
104 if (!afc || !afc->clipboardRequestEvent || !cliprdr->ClientFormatDataRequest)
105 goto fail;
106
107 formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
108 formatDataRequest.common.msgFlags = 0;
109 formatDataRequest.requestedFormatId = formatId;
110 afc->requestedFormatId = formatId;
111 (void)ResetEvent(afc->clipboardRequestEvent);
112 rc = cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest);
113fail:
114 return rc;
115}
116
117static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr)
118{
119 CLIPRDR_CAPABILITIES capabilities;
120 CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
121
122 if (!cliprdr || !cliprdr->ClientCapabilities)
123 return ERROR_INVALID_PARAMETER;
124
125 capabilities.cCapabilitiesSets = 1;
126 capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet);
127 generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
128 generalCapabilitySet.capabilitySetLength = 12;
129 generalCapabilitySet.version = CB_CAPS_VERSION_2;
130 generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
131 return cliprdr->ClientCapabilities(cliprdr, &capabilities);
132}
133
139static UINT android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr,
140 const CLIPRDR_MONITOR_READY* monitorReady)
141{
142 UINT rc;
143 androidContext* afc;
144
145 if (!cliprdr || !monitorReady)
146 return ERROR_INVALID_PARAMETER;
147
148 afc = (androidContext*)cliprdr->custom;
149
150 if (!afc)
151 return ERROR_INVALID_PARAMETER;
152
153 if ((rc = android_cliprdr_send_client_capabilities(cliprdr)) != CHANNEL_RC_OK)
154 return rc;
155
156 if ((rc = android_cliprdr_send_client_format_list(cliprdr)) != CHANNEL_RC_OK)
157 return rc;
158
159 afc->clipboardSync = TRUE;
160 return CHANNEL_RC_OK;
161}
162
168static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr,
169 const CLIPRDR_CAPABILITIES* capabilities)
170{
171 CLIPRDR_CAPABILITY_SET* capabilitySet;
172 androidContext* afc;
173
174 if (!cliprdr || !capabilities)
175 return ERROR_INVALID_PARAMETER;
176
177 afc = (androidContext*)cliprdr->custom;
178
179 if (!afc)
180 return ERROR_INVALID_PARAMETER;
181
182 for (UINT32 index = 0; index < capabilities->cCapabilitiesSets; index++)
183 {
184 capabilitySet = &(capabilities->capabilitySets[index]);
185
186 if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) &&
187 (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN))
188 {
189 CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet =
190 (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilitySet;
191 afc->clipboardCapabilities = generalCapabilitySet->generalFlags;
192 break;
193 }
194 }
195
196 return CHANNEL_RC_OK;
197}
198
204static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr,
205 const CLIPRDR_FORMAT_LIST* formatList)
206{
207 UINT rc;
208 CLIPRDR_FORMAT* format;
209 androidContext* afc;
210
211 if (!cliprdr || !formatList)
212 return ERROR_INVALID_PARAMETER;
213
214 afc = (androidContext*)cliprdr->custom;
215
216 if (!afc)
217 return ERROR_INVALID_PARAMETER;
218
219 if (afc->serverFormats)
220 {
221 for (UINT32 index = 0; index < afc->numServerFormats; index++)
222 free(afc->serverFormats[index].formatName);
223
224 free(afc->serverFormats);
225 afc->serverFormats = NULL;
226 afc->numServerFormats = 0;
227 }
228
229 if (formatList->numFormats < 1)
230 return CHANNEL_RC_OK;
231
232 afc->numServerFormats = formatList->numFormats;
233 afc->serverFormats = (CLIPRDR_FORMAT*)calloc(afc->numServerFormats, sizeof(CLIPRDR_FORMAT));
234
235 if (!afc->serverFormats)
236 return CHANNEL_RC_NO_MEMORY;
237
238 for (UINT32 index = 0; index < afc->numServerFormats; index++)
239 {
240 afc->serverFormats[index].formatId = formatList->formats[index].formatId;
241 afc->serverFormats[index].formatName = NULL;
242
243 if (formatList->formats[index].formatName)
244 {
245 afc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName);
246
247 if (!afc->serverFormats[index].formatName)
248 return CHANNEL_RC_NO_MEMORY;
249 }
250 }
251
252 for (UINT32 index = 0; index < afc->numServerFormats; index++)
253 {
254 format = &(afc->serverFormats[index]);
255
256 if (format->formatId == CF_UNICODETEXT)
257 {
258 if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT)) !=
259 CHANNEL_RC_OK)
260 return rc;
261
262 break;
263 }
264 else if (format->formatId == CF_TEXT)
265 {
266 if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT)) !=
267 CHANNEL_RC_OK)
268 return rc;
269
270 break;
271 }
272 }
273
274 return CHANNEL_RC_OK;
275}
276
282static UINT
283android_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr,
284 const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
285{
286 if (!cliprdr || !formatListResponse)
287 return ERROR_INVALID_PARAMETER;
288
289 return CHANNEL_RC_OK;
290}
291
297static UINT
298android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr,
299 const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
300{
301 if (!cliprdr || !lockClipboardData)
302 return ERROR_INVALID_PARAMETER;
303
304 return CHANNEL_RC_OK;
305}
306
312static UINT android_cliprdr_server_unlock_clipboard_data(
313 CliprdrClientContext* cliprdr, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
314{
315 if (!cliprdr || !unlockClipboardData)
316 return ERROR_INVALID_PARAMETER;
317
318 return CHANNEL_RC_OK;
319}
320
326static UINT
327android_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr,
328 const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
329{
330 UINT rc;
331 BYTE* data;
332 UINT32 size;
333 UINT32 formatId;
334 CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
335 androidContext* afc;
336
337 if (!cliprdr || !formatDataRequest || !cliprdr->ClientFormatDataResponse)
338 return ERROR_INVALID_PARAMETER;
339
340 afc = (androidContext*)cliprdr->custom;
341
342 if (!afc)
343 return ERROR_INVALID_PARAMETER;
344
345 formatId = formatDataRequest->requestedFormatId;
346 data = (BYTE*)ClipboardGetData(afc->clipboard, formatId, &size);
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 = NULL;
356 }
357
358 rc = cliprdr->ClientFormatDataResponse(cliprdr, &response);
359 free(data);
360 return rc;
361}
362
368static UINT
369android_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr,
370 const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
371{
372 CLIPRDR_FORMAT* format = NULL;
373
374 if (!cliprdr || !formatDataResponse)
375 return ERROR_INVALID_PARAMETER;
376
377 androidContext* afc = (androidContext*)cliprdr->custom;
378
379 if (!afc)
380 return ERROR_INVALID_PARAMETER;
381
382 freerdp* instance = ((rdpContext*)afc)->instance;
383
384 if (!instance)
385 return ERROR_INVALID_PARAMETER;
386
387 for (UINT32 index = 0; index < afc->numServerFormats; index++)
388 {
389 if (afc->requestedFormatId == afc->serverFormats[index].formatId)
390 format = &(afc->serverFormats[index]);
391 }
392
393 if (!format)
394 {
395 (void)SetEvent(afc->clipboardRequestEvent);
396 return ERROR_INTERNAL_ERROR;
397 }
398
399 UINT32 formatId = format->formatId;
400 if (format->formatName)
401 formatId = ClipboardRegisterFormat(afc->clipboard, format->formatName);
402
403 uint32_t size = formatDataResponse->common.dataLen;
404
405 if (!ClipboardSetData(afc->clipboard, formatId, formatDataResponse->requestedFormatData, size))
406 return ERROR_INTERNAL_ERROR;
407
408 (void)SetEvent(afc->clipboardRequestEvent);
409
410 if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT))
411 {
412 JNIEnv* env = NULL;
413 formatId = ClipboardRegisterFormat(afc->clipboard, "text/plain");
414 char* data = (char*)ClipboardGetData(afc->clipboard, formatId, &size);
415 jboolean attached = jni_attach_thread(&env);
416 size = strnlen(data, size);
417 jstring jdata = jniNewStringUTF(env, data, size);
418 freerdp_callback("OnRemoteClipboardChanged", "(JLjava/lang/String;)V", (jlong)instance,
419 jdata);
420 (*env)->DeleteLocalRef(env, jdata);
421
422 if (attached == JNI_TRUE)
423 jni_detach_thread();
424 }
425
426 return CHANNEL_RC_OK;
427}
428
434static UINT android_cliprdr_server_file_contents_request(
435 CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
436{
437 if (!cliprdr || !fileContentsRequest)
438 return ERROR_INVALID_PARAMETER;
439
440 return CHANNEL_RC_OK;
441}
442
448static UINT android_cliprdr_server_file_contents_response(
449 CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
450{
451 if (!cliprdr || !fileContentsResponse)
452 return ERROR_INVALID_PARAMETER;
453
454 return CHANNEL_RC_OK;
455}
456
457BOOL android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr)
458{
459 wClipboard* clipboard;
460 HANDLE hevent;
461
462 if (!afc || !cliprdr)
463 return FALSE;
464
465 if (!(hevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
466 return FALSE;
467
468 if (!(clipboard = ClipboardCreate()))
469 {
470 (void)CloseHandle(hevent);
471 return FALSE;
472 }
473
474 afc->cliprdr = cliprdr;
475 afc->clipboard = clipboard;
476 afc->clipboardRequestEvent = hevent;
477 cliprdr->custom = (void*)afc;
478 cliprdr->MonitorReady = android_cliprdr_monitor_ready;
479 cliprdr->ServerCapabilities = android_cliprdr_server_capabilities;
480 cliprdr->ServerFormatList = android_cliprdr_server_format_list;
481 cliprdr->ServerFormatListResponse = android_cliprdr_server_format_list_response;
482 cliprdr->ServerLockClipboardData = android_cliprdr_server_lock_clipboard_data;
483 cliprdr->ServerUnlockClipboardData = android_cliprdr_server_unlock_clipboard_data;
484 cliprdr->ServerFormatDataRequest = android_cliprdr_server_format_data_request;
485 cliprdr->ServerFormatDataResponse = android_cliprdr_server_format_data_response;
486 cliprdr->ServerFileContentsRequest = android_cliprdr_server_file_contents_request;
487 cliprdr->ServerFileContentsResponse = android_cliprdr_server_file_contents_response;
488 return TRUE;
489}
490
491BOOL android_cliprdr_uninit(androidContext* afc, CliprdrClientContext* cliprdr)
492{
493 if (!afc || !cliprdr)
494 return FALSE;
495
496 cliprdr->custom = NULL;
497 afc->cliprdr = NULL;
498 ClipboardDestroy(afc->clipboard);
499 (void)CloseHandle(afc->clipboardRequestEvent);
500 return TRUE;
501}