FreeRDP
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 
36 UINT 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);
86 fail:
87  free(pFormatIds);
88  free(formats);
89  return rc;
90 }
91 
92 static 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);
113 fail:
114  return rc;
115 }
116 
117 static 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 
139 static 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 
168 static 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 
204 static 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 
282 static UINT
283 android_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 
297 static UINT
298 android_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 
312 static 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 
326 static UINT
327 android_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 
368 static UINT
369 android_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 = NULL;
376  androidContext* afc;
377  freerdp* instance;
378 
379  if (!cliprdr || !formatDataResponse)
380  return ERROR_INVALID_PARAMETER;
381 
382  afc = (androidContext*)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  if (format->formatName)
405  formatId = ClipboardRegisterFormat(afc->clipboard, format->formatName);
406  else
407  formatId = format->formatId;
408 
409  size = formatDataResponse->common.dataLen;
410 
411  if (!ClipboardSetData(afc->clipboard, formatId, formatDataResponse->requestedFormatData, size))
412  return ERROR_INTERNAL_ERROR;
413 
414  (void)SetEvent(afc->clipboardRequestEvent);
415 
416  if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT))
417  {
418  JNIEnv* env;
419  jstring jdata;
420  jboolean attached;
421  formatId = ClipboardRegisterFormat(afc->clipboard, "text/plain");
422  data = (void*)ClipboardGetData(afc->clipboard, formatId, &size);
423  attached = jni_attach_thread(&env);
424  size = strnlen(data, size);
425  jdata = jniNewStringUTF(env, data, size);
426  freerdp_callback("OnRemoteClipboardChanged", "(JLjava/lang/String;)V", (jlong)instance,
427  jdata);
428  (*env)->DeleteLocalRef(env, jdata);
429 
430  if (attached == JNI_TRUE)
431  jni_detach_thread();
432  }
433 
434  return CHANNEL_RC_OK;
435 }
436 
442 static UINT android_cliprdr_server_file_contents_request(
443  CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
444 {
445  if (!cliprdr || !fileContentsRequest)
446  return ERROR_INVALID_PARAMETER;
447 
448  return CHANNEL_RC_OK;
449 }
450 
456 static UINT android_cliprdr_server_file_contents_response(
457  CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
458 {
459  if (!cliprdr || !fileContentsResponse)
460  return ERROR_INVALID_PARAMETER;
461 
462  return CHANNEL_RC_OK;
463 }
464 
465 BOOL android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr)
466 {
467  wClipboard* clipboard;
468  HANDLE hevent;
469 
470  if (!afc || !cliprdr)
471  return FALSE;
472 
473  if (!(hevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
474  return FALSE;
475 
476  if (!(clipboard = ClipboardCreate()))
477  {
478  (void)CloseHandle(hevent);
479  return FALSE;
480  }
481 
482  afc->cliprdr = cliprdr;
483  afc->clipboard = clipboard;
484  afc->clipboardRequestEvent = hevent;
485  cliprdr->custom = (void*)afc;
486  cliprdr->MonitorReady = android_cliprdr_monitor_ready;
487  cliprdr->ServerCapabilities = android_cliprdr_server_capabilities;
488  cliprdr->ServerFormatList = android_cliprdr_server_format_list;
489  cliprdr->ServerFormatListResponse = android_cliprdr_server_format_list_response;
490  cliprdr->ServerLockClipboardData = android_cliprdr_server_lock_clipboard_data;
491  cliprdr->ServerUnlockClipboardData = android_cliprdr_server_unlock_clipboard_data;
492  cliprdr->ServerFormatDataRequest = android_cliprdr_server_format_data_request;
493  cliprdr->ServerFormatDataResponse = android_cliprdr_server_format_data_response;
494  cliprdr->ServerFileContentsRequest = android_cliprdr_server_file_contents_request;
495  cliprdr->ServerFileContentsResponse = android_cliprdr_server_file_contents_response;
496  return TRUE;
497 }
498 
499 BOOL android_cliprdr_uninit(androidContext* afc, CliprdrClientContext* cliprdr)
500 {
501  if (!afc || !cliprdr)
502  return FALSE;
503 
504  cliprdr->custom = NULL;
505  afc->cliprdr = NULL;
506  ClipboardDestroy(afc->clipboard);
507  (void)CloseHandle(afc->clipboardRequestEvent);
508  return TRUE;
509 }