From 769eb382171dec800ed8930134d5863bbd72f3e7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 12 Nov 2014 12:25:12 -0500 Subject: [PATCH] afreerdp: migrate to cliprdr callback interface --- client/Android/FreeRDPCore/jni/android_cliprdr.c | 564 +++++++++-------------- client/Android/FreeRDPCore/jni/android_cliprdr.h | 8 +- client/Android/FreeRDPCore/jni/android_event.c | 41 +- client/Android/FreeRDPCore/jni/android_freerdp.c | 119 +++-- client/Android/FreeRDPCore/jni/android_freerdp.h | 14 +- 5 files changed, 344 insertions(+), 402 deletions(-) diff --git a/client/Android/FreeRDPCore/jni/android_cliprdr.c b/client/Android/FreeRDPCore/jni/android_cliprdr.c index 4bb0df0..f3278b3 100644 --- a/client/Android/FreeRDPCore/jni/android_cliprdr.c +++ b/client/Android/FreeRDPCore/jni/android_cliprdr.c @@ -22,12 +22,10 @@ #endif #include -#include #include #include -#include #include #include @@ -36,437 +34,325 @@ #include "android_jni_utils.h" #include "android_jni_callback.h" -struct clipboard_context +int android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) { - freerdp* instance; - rdpChannels* channels; - - /* server->client data */ - UINT32* formats; - int num_formats; - BYTE* data; - UINT32 data_format; - int data_length; - - /* client->server data */ - UINT32* android_formats; - int android_num_formats; - BYTE* android_data; - int android_data_length; -}; -typedef struct clipboard_context clipboardContext; - -static BYTE* lf2crlf(BYTE* data, int* size) -{ - BYTE c; - BYTE* outbuf; - BYTE* out; - BYTE* in_end; - BYTE* in; - int out_size; - - out_size = (*size) * 2 + 1; - outbuf = (BYTE*) malloc(out_size); - ZeroMemory(outbuf, out_size); - - out = outbuf; - in = data; - in_end = data + (*size); - - while (in < in_end) - { - c = *in++; - if (c == '\n') - { - *out++ = '\r'; - *out++ = '\n'; - } - else - { - *out++ = c; - } - } + UINT32 index; + UINT32 formatId; + UINT32 numFormats; + UINT32* pFormatIds; + const char* formatName; + CLIPRDR_FORMAT* formats; + CLIPRDR_FORMAT_LIST formatList; + androidContext* afc = (androidContext*) cliprdr->custom; - *out++ = 0; - *size = out - outbuf; + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); - return outbuf; -} + pFormatIds = NULL; + numFormats = ClipboardGetFormatIds(afc->clipboard, &pFormatIds); -static void crlf2lf(BYTE* data, int* size) -{ - BYTE c; - BYTE* out; - BYTE* in; - BYTE* in_end; + formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); - out = data; - in = data; - in_end = data + (*size); + if (!formats) + return -1; - while (in < in_end) + for (index = 0; index < numFormats; index++) { - c = *in++; + formatId = pFormatIds[index]; + formatName = ClipboardGetFormatName(afc->clipboard, formatId); - if (c != '\r') - *out++ = c; - } + formats[index].formatId = formatId; + formats[index].formatName = NULL; - *size = out - data; -} - -void android_cliprdr_init(freerdp* inst) -{ - clipboardContext* cb; - androidContext* ctx = (androidContext*) inst->context; - - cb = (clipboardContext*) calloc(1, sizeof(clipboardContext)); - - cb->instance = inst; - cb->channels = inst->context->channels; - - cb->android_num_formats = 2; - cb->android_formats = (UINT32*) calloc(cb->android_num_formats, sizeof(UINT32)); - cb->android_formats[0] = CF_TEXT; - cb->android_formats[1] = CF_UNICODETEXT; - - ctx->clipboard_context = cb; -} - -void android_cliprdr_uninit(freerdp* inst) -{ - androidContext* ctx = (androidContext*)inst->context; - clipboardContext* cb = (clipboardContext*)ctx->clipboard_context; - - if (cb) - { - if (cb->formats) - free(cb->formats); - if (cb->data) - free(cb->data); - if (cb->android_formats) - free(cb->android_formats); - if (cb->android_data) - free(cb->android_data); - free(cb); - ctx->clipboard_context = NULL; + if ((formatId > CF_MAX) && formatName) + formats[index].formatName = _strdup(formatName); } -} -static void android_cliprdr_send_null_format_list(clipboardContext* cb) -{ - RDP_CB_FORMAT_LIST_EVENT* event; + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = numFormats; + formatList.formats = formats; - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); + afc->cliprdr->ClientFormatList(afc->cliprdr, &formatList); - event->num_formats = 0; + free(pFormatIds); + free(formats); - freerdp_channels_send_event(cb->channels, (wMessage*) event); + return 1; } -static void android_cliprdr_send_supported_format_list(clipboardContext* cb) +int android_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId) { - int i; - RDP_CB_FORMAT_LIST_EVENT* event; + CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; + androidContext* afc = (androidContext*) cliprdr->custom; - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FormatList, NULL, NULL); + ZeroMemory(&formatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); - event->formats = (UINT32*) calloc(cb->android_num_formats, sizeof(UINT32)); - event->num_formats = cb->android_num_formats; + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; + formatDataRequest.msgFlags = 0; - for (i = 0; i < cb->android_num_formats; i++) - { - event->formats[i] = cb->android_formats[i]; - } + formatDataRequest.requestedFormatId = formatId; + afc->requestedFormatId = formatId; + ResetEvent(afc->clipboardRequestEvent); - freerdp_channels_send_event(cb->channels, (wMessage*) event); -} + cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest); -static void android_cliprdr_send_format_list(clipboardContext* cb) -{ - if (cb->android_data) - { - android_cliprdr_send_supported_format_list(cb); - } - else - { - android_cliprdr_send_null_format_list(cb); - } + return 1; } -static void android_cliprdr_send_data_request(clipboardContext* cb, UINT32 format) +int android_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) { - RDP_CB_DATA_REQUEST_EVENT* event; + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_DataRequest, NULL, NULL); + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); - event->format = format; + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; - freerdp_channels_send_event(cb->channels, (wMessage*) event); -} - -static void android_cliprdr_send_data_response(clipboardContext* cb, BYTE* data, int size) -{ - RDP_CB_DATA_RESPONSE_EVENT* event; - - event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_DataResponse, NULL, NULL); + generalCapabilitySet.version = CB_CAPS_VERSION_2; + generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES; - event->data = data; - event->size = size; + cliprdr->ClientCapabilities(cliprdr, &capabilities); - freerdp_channels_send_event(cb->channels, (wMessage*) event); + return 1; } -static void android_cliprdr_send_null_data_response(clipboardContext* cb) +int android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_READY* monitorReady) { - android_cliprdr_send_data_response(cb, NULL, 0); -} + androidContext* afc = (androidContext*) cliprdr->custom; -static void android_cliprdr_process_cb_monitor_ready_event(clipboardContext* cb) -{ - android_cliprdr_send_format_list(cb); + afc->clipboardSync = TRUE; + android_cliprdr_send_client_capabilities(cliprdr); + android_cliprdr_send_client_format_list(cliprdr); + + return 1; } -static BYTE* android_cliprdr_process_requested_unicodetext(BYTE* data, int* size) +int android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPABILITIES* capabilities) { - char* inbuf; - WCHAR* outbuf = NULL; - int out_size; + UINT32 index; + CLIPRDR_CAPABILITY_SET* capabilitySet; + androidContext* afc = (androidContext*) cliprdr->custom; - inbuf = (char*) lf2crlf(data, size); - out_size = ConvertToUnicode(CP_UTF8, 0, inbuf, -1, &outbuf, 0); - free(inbuf); + for (index = 0; index < capabilities->cCapabilitiesSets; index++) + { + capabilitySet = &(capabilities->capabilitySets[index]); - *size = (int) ((out_size + 1) * 2); + if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && + (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) + { + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet + = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; - return (BYTE*) outbuf; + afc->clipboardCapabilities = generalCapabilitySet->generalFlags; + break; + } + } + + return 1; } -static BYTE* android_cliprdr_process_requested_text(BYTE* data, int* size) +int android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST* formatList) { - BYTE* outbuf; + UINT32 index; + CLIPRDR_FORMAT* format; + androidContext* afc = (androidContext*) cliprdr->custom; - outbuf = lf2crlf(data, size); + if (afc->serverFormats) + { + for (index = 0; index < afc->numServerFormats; index++) + { + free(afc->serverFormats[index].formatName); + } - return outbuf; -} + free(afc->serverFormats); + afc->serverFormats = NULL; + afc->numServerFormats = 0; + } -static void android_cliprdr_process_cb_data_request_event(clipboardContext* cb, RDP_CB_DATA_REQUEST_EVENT* event) -{ - int i; + if (formatList->numFormats < 1) + return 1; - DEBUG_ANDROID("format %d", event->format); + afc->numServerFormats = formatList->numFormats; + afc->serverFormats = (CLIPRDR_FORMAT*) calloc(afc->numServerFormats, sizeof(CLIPRDR_FORMAT)); - for (i = 0; i < cb->android_num_formats; i++) - { - if (event->format == cb->android_formats[i]) - break; - } + if (!afc->serverFormats) + return -1; - if (i >= cb->android_num_formats) + for (index = 0; index < afc->numServerFormats; index++) { - DEBUG_ANDROID("unsupported format requested"); - android_cliprdr_send_null_data_response(cb); - } - else if (!cb->android_data) - { - DEBUG_ANDROID("no android clipdata"); - android_cliprdr_send_null_data_response(cb); + afc->serverFormats[index].formatId = formatList->formats[index].formatId; + afc->serverFormats[index].formatName = NULL; + + if (formatList->formats[index].formatName) + afc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); } - else + + for (index = 0; index < afc->numServerFormats; index++) { - BYTE* outbuf = NULL; - int size = cb->android_data_length; + format = &(afc->serverFormats[index]); - switch (event->format) + if (format->formatId == CF_UNICODETEXT) { - case CF_UNICODETEXT: - outbuf = android_cliprdr_process_requested_unicodetext(cb->android_data, &size); - break; - - case CF_TEXT: - outbuf = android_cliprdr_process_requested_text(cb->android_data, &size); - break; + android_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT); + break; + } + else if (format->formatId == CF_TEXT) + { + android_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT); + break; } - - if (outbuf) - android_cliprdr_send_data_response(cb, outbuf, size); - else - android_cliprdr_send_null_data_response(cb); } - - /* Resend the format list, otherwise the server won't request again for the next paste */ - android_cliprdr_send_format_list(cb); + + return 1; } -static BOOL android_cliprdr_has_format(UINT32* formats, int num_formats, UINT32 format) +int android_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { - int i; + return 1; +} - for (i = 0; i < num_formats; i++) - { - if (formats[i] == format) - return TRUE; - } +int android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + return 1; +} - return FALSE; +int android_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + return 1; } -static void android_cliprdr_process_cb_format_list_event(clipboardContext* cb, RDP_CB_FORMAT_LIST_EVENT* event) +int android_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { - if (cb->data) - { - free(cb->data); - cb->data = NULL; - cb->data_length = 0; - } + BYTE* data; + UINT32 size; + UINT32 formatId; + CLIPRDR_FORMAT_DATA_RESPONSE response; + androidContext* afc = (androidContext*) cliprdr->custom; - if (cb->formats) - free(cb->formats); + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); - cb->data_format = 0; - cb->formats = event->formats; - cb->num_formats = event->num_formats; - event->formats = NULL; - event->num_formats = 0; + formatId = formatDataRequest->requestedFormatId; + data = (BYTE*) ClipboardGetData(afc->clipboard, formatId, &size); - if (android_cliprdr_has_format(cb->formats, cb->num_formats, CF_TEXT)) - { - cb->data_format = CF_TEXT; - android_cliprdr_send_data_request(cb, CF_TEXT); - } - else if (android_cliprdr_has_format(cb->formats, cb->num_formats, CF_UNICODETEXT)) - { - cb->data_format = CF_UNICODETEXT; - android_cliprdr_send_data_request(cb, CF_UNICODETEXT); - } - else if (android_cliprdr_has_format(cb->formats, cb->num_formats, CB_FORMAT_HTML)) + response.msgFlags = CB_RESPONSE_OK; + response.dataLen = size; + response.requestedFormatData = data; + + if (!data) { - cb->data_format = CB_FORMAT_HTML; - android_cliprdr_send_data_request(cb, CB_FORMAT_HTML); + response.msgFlags = CB_RESPONSE_FAIL; + response.dataLen = 0; + response.requestedFormatData = NULL; } + + cliprdr->ClientFormatDataResponse(cliprdr, &response); + + free(data); + + return 1; } -static void android_cliprdr_process_text(clipboardContext* cb, BYTE* data, int size) +int android_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { - if (size > 0 && data) + BYTE* data; + UINT32 size; + UINT32 index; + UINT32 formatId; + CLIPRDR_FORMAT* format = NULL; + androidContext* afc = (androidContext*) cliprdr->custom; + freerdp* instance = ((rdpContext*) afc)->instance; + + for (index = 0; index < afc->numServerFormats; index++) { - cb->data = (BYTE*) malloc(size + 1); - memcpy(cb->data, data, size); - cb->data[size] = 0; - cb->data_length = size; + if (afc->requestedFormatId == afc->serverFormats[index].formatId) + format = &(afc->serverFormats[index]); } -} -static void android_cliprdr_process_unicodetext(clipboardContext* cb, BYTE* data, int size) -{ - cb->data_length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) data, size / 2, (CHAR**) &(cb->data), 0, NULL, NULL); - crlf2lf(cb->data, &cb->data_length); -} + if (!format) + { + SetEvent(afc->clipboardRequestEvent); + return -1; + } -static void android_cliprdr_process_cb_data_response_event(clipboardContext* cb, RDP_CB_DATA_RESPONSE_EVENT* event) -{ - DEBUG_ANDROID("size=%d", event->size); + if (format->formatName) + formatId = ClipboardRegisterFormat(afc->clipboard, format->formatName); + else + formatId = format->formatId; - if (event->size > 0) + size = formatDataResponse->dataLen; + data = (BYTE*) malloc(size); + CopyMemory(data, formatDataResponse->requestedFormatData, size); + + ClipboardSetData(afc->clipboard, formatId, data, size); + + SetEvent(afc->clipboardRequestEvent); + + if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT)) { - if (cb->data) - { - free(cb->data); - cb->data = NULL; - cb->data_length = 0; - } + JNIEnv* env; + jstring jdata; + jboolean attached; - switch (cb->data_format) - { - case CF_TEXT: - android_cliprdr_process_text(cb, event->data, event->size - 1); - break; + formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"); - case CF_UNICODETEXT: - android_cliprdr_process_unicodetext(cb, event->data, event->size - 2); - break; - } + data = (void*) ClipboardGetData(afc->clipboard, formatId, &size); - DEBUG_ANDROID("computer_clipboard_data %s ", (char*)cb->data); + attached = jni_attach_thread(&env); + jdata = jniNewStringUTF(env, data, size); - if (cb->data) - { - JNIEnv* env; - jboolean attached = jni_attach_thread(&env); - jstring jdata = jniNewStringUTF(env, cb->data, cb->data_length); + freerdp_callback("OnRemoteClipboardChanged", "(ILjava/lang/String;)V", instance, jdata); - freerdp_callback("OnRemoteClipboardChanged", "(ILjava/lang/String;)V", cb->instance, jdata); + (*env)->DeleteLocalRef(env, jdata); - (*env)->DeleteLocalRef(env, jdata); - if(attached == JNI_TRUE) - { - jni_detach_thread(); - } + if (attached == JNI_TRUE) + { + jni_detach_thread(); } } + + return 1; } -void android_process_cliprdr_event(freerdp* inst, wMessage* event) +int android_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { - androidContext* ctx = (androidContext*)inst->context; - clipboardContext* cb = (clipboardContext*) ctx->clipboard_context; - - if (!cb) - return; - - switch (GetMessageType(event->id)) - { - case CliprdrChannel_MonitorReady: - android_cliprdr_process_cb_monitor_ready_event(cb); - break; - - case CliprdrChannel_FormatList: - android_cliprdr_process_cb_format_list_event(cb, (RDP_CB_FORMAT_LIST_EVENT*) event); - break; - - case CliprdrChannel_DataRequest: - android_cliprdr_process_cb_data_request_event(cb, (RDP_CB_DATA_REQUEST_EVENT*) event); - break; + return 1; +} - case CliprdrChannel_DataResponse: - android_cliprdr_process_cb_data_response_event(cb, (RDP_CB_DATA_RESPONSE_EVENT*) event); - break; +int android_cliprdr_server_file_contents_response(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +{ + return 1; +} - default: - DEBUG_ANDROID("unknown event type %d", GetMessageType(event->id)); - break; - } +int android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr) +{ + cliprdr->custom = (void*) afc; + afc->cliprdr = cliprdr; + + afc->clipboard = ClipboardCreate(); + afc->clipboardRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + cliprdr->MonitorReady = android_cliprdr_monitor_ready; + cliprdr->ServerCapabilities = android_cliprdr_server_capabilities; + cliprdr->ServerFormatList = android_cliprdr_server_format_list; + cliprdr->ServerFormatListResponse = android_cliprdr_server_format_list_response; + cliprdr->ServerLockClipboardData = android_cliprdr_server_lock_clipboard_data; + cliprdr->ServerUnlockClipboardData = android_cliprdr_server_unlock_clipboard_data; + cliprdr->ServerFormatDataRequest = android_cliprdr_server_format_data_request; + cliprdr->ServerFormatDataResponse = android_cliprdr_server_format_data_response; + cliprdr->ServerFileContentsRequest = android_cliprdr_server_file_contents_request; + cliprdr->ServerFileContentsResponse = android_cliprdr_server_file_contents_response; + + return 1; } -void android_process_cliprdr_send_clipboard_data(freerdp* inst, void* data, int len) +int android_cliprdr_uninit(androidContext* afc, CliprdrClientContext* cliprdr) { - androidContext* ctx = (androidContext*)inst->context; - clipboardContext* cb = (clipboardContext*) ctx->clipboard_context; + cliprdr->custom = NULL; + afc->cliprdr = NULL; - DEBUG_ANDROID("android_clipboard_data %s ", (char*)data); - - if (cb && (data == NULL || cb->android_data == NULL || - len != cb->android_data_length || memcmp(data, cb->android_data, len))) - { - if (cb->android_data) - { - free(cb->android_data); - cb->android_data = NULL; - cb->android_data_length = 0; - } - if (data) - { - cb->android_data = (BYTE*) malloc(len + 1); - memcpy(cb->android_data, data, len); - cb->android_data[len] = 0; - cb->android_data_length = len; - } + ClipboardDestroy(afc->clipboard); + CloseHandle(afc->clipboardRequestEvent); - android_cliprdr_send_format_list(cb); - } + return 1; } diff --git a/client/Android/FreeRDPCore/jni/android_cliprdr.h b/client/Android/FreeRDPCore/jni/android_cliprdr.h index 233bff3..b431815 100644 --- a/client/Android/FreeRDPCore/jni/android_cliprdr.h +++ b/client/Android/FreeRDPCore/jni/android_cliprdr.h @@ -22,9 +22,9 @@ #include "android_freerdp.h" -void android_cliprdr_init(freerdp* inst); -void android_cliprdr_uninit(freerdp* inst); -void android_process_cliprdr_send_clipboard_data(freerdp* inst, void* data, int len); -void android_process_cliprdr_event(freerdp* inst, wMessage* event); +int android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr); + +int android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr); +int android_cliprdr_uninit(androidContext* afc, CliprdrClientContext* cliprdr); #endif /* __ANDROID_CLIPRDR_H__ */ diff --git a/client/Android/FreeRDPCore/jni/android_event.c b/client/Android/FreeRDPCore/jni/android_event.c index 15452fa..e63511c 100644 --- a/client/Android/FreeRDPCore/jni/android_event.c +++ b/client/Android/FreeRDPCore/jni/android_event.c @@ -14,11 +14,11 @@ #include "config.h" #endif -#include -#include -#include +#include + #include #include + #include #include @@ -115,11 +115,13 @@ ANDROID_EVENT* android_pop_event(ANDROID_EVENT_QUEUE * queue) return event; } -int android_process_event(ANDROID_EVENT_QUEUE * queue, freerdp * inst) +int android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst) { ANDROID_EVENT* event; + rdpContext* context = inst->context; + androidContext* afc = (androidContext*) context; - while (android_peek_event(queue) != NULL) + while (android_peek_event(queue)) { event = android_pop_event(queue); @@ -143,8 +145,33 @@ int android_process_event(ANDROID_EVENT_QUEUE * queue, freerdp * inst) } else if (event->type == EVENT_TYPE_CLIPBOARD) { - ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*)event; - android_process_cliprdr_send_clipboard_data(inst, clipboard_event->data, clipboard_event->data_length); + BYTE* data; + UINT32 size; + UINT32 formatId; + ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*) event; + + formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"); + + size = clipboard_event->data_length; + + if (size) + { + data = (BYTE*) malloc(size); + + if (!data) + return -1; + + CopyMemory(data, clipboard_event->data, size); + + ClipboardSetData(afc->clipboard, formatId, (void*) data, size); + } + else + { + ClipboardEmpty(afc->clipboard); + } + + android_cliprdr_send_client_format_list(afc->cliprdr); + android_event_clipboard_free(clipboard_event); } else if (event->type == EVENT_TYPE_DISCONNECT) diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.c b/client/Android/FreeRDPCore/jni/android_freerdp.c index 4d75b52..c1e9594 100644 --- a/client/Android/FreeRDPCore/jni/android_freerdp.c +++ b/client/Android/FreeRDPCore/jni/android_freerdp.c @@ -20,12 +20,17 @@ #include #include #include + +#include #include +#include +#include +#include +#include +#include #include #include #include -#include -#include #include #include #include @@ -39,7 +44,6 @@ #include "android_debug.h" #include "android_cliprdr.h" - #if defined(WITH_GPROF) #include "jni/prof.h" #endif @@ -57,6 +61,45 @@ void android_context_free(freerdp* instance, rdpContext* context) android_event_queue_uninit(instance); } +void android_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) +{ + rdpSettings* settings = context->settings; + androidContext* afc = (androidContext*) context; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + android_cliprdr_init(afc, (CliprdrClientContext*) e->pInterface); + } +} + +void android_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) +{ + rdpSettings* settings = context->settings; + androidContext* afc = (androidContext*) context; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + + } + else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) + { + if (settings->SoftwareGdi) + gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); + } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + android_cliprdr_uninit(afc, (CliprdrClientContext*) e->pInterface); + } +} void android_begin_paint(rdpContext* context) { @@ -65,7 +108,6 @@ void android_begin_paint(rdpContext* context) gdi->primary->hdc->hwnd->ninvalid = 0; } - void android_end_paint(rdpContext* context) { androidContext *ctx = (androidContext*)context; @@ -97,7 +139,6 @@ void android_desktop_resize(rdpContext* context) context->settings->DesktopHeight, context->settings->ColorDepth); } - BOOL android_pre_connect(freerdp* instance) { DEBUG_ANDROID("android_pre_connect"); @@ -131,6 +172,12 @@ BOOL android_pre_connect(freerdp* instance) settings->FrameAcknowledge = 10; + PubSub_SubscribeChannelConnected(instance->context->pubSub, + (pChannelConnectedEventHandler) android_OnChannelConnectedEventHandler); + + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + (pChannelDisconnectedEventHandler) android_OnChannelDisconnectedEventHandler); + freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); freerdp_client_load_addins(instance->context->channels, instance->settings); @@ -166,11 +213,8 @@ static BOOL android_post_connect(freerdp* instance) instance->update->EndPaint = android_end_paint; instance->update->DesktopResize = android_desktop_resize; - android_cliprdr_init(instance); - freerdp_channels_post_connect(instance->context->channels, instance); - // send notifications freerdp_callback("OnConnectionSuccess", "(I)V", instance); return TRUE; @@ -180,7 +224,6 @@ static void android_post_disconnect(freerdp* instance) { gdi_free(instance); cache_free(instance->context->cache); - android_cliprdr_uninit(instance); } BOOL android_authenticate(freerdp* instance, char** username, char** password, char** domain) @@ -196,26 +239,27 @@ BOOL android_authenticate(freerdp* instance, char** username, char** password, c jobject jstr3 = create_string_builder(env, *password); jboolean res = freerdp_callback_bool_result("OnAuthenticate", "(ILjava/lang/StringBuilder;Ljava/lang/StringBuilder;Ljava/lang/StringBuilder;)Z", instance, jstr1, jstr2, jstr3); - if(res == JNI_TRUE) + + if (res == JNI_TRUE) { // read back string values - if(*username != NULL) + if (*username != NULL) free(*username); *username = get_string_from_string_builder(env, jstr1); - if(*domain != NULL) + if (*domain != NULL) free(*domain); *domain = get_string_from_string_builder(env, jstr2); - if(*password == NULL) + if (*password == NULL) free(*password); *password = get_string_from_string_builder(env, jstr3); } - if(attached == JNI_TRUE) + if (attached == JNI_TRUE) jni_detach_thread(); return ((res == JNI_TRUE) ? TRUE : FALSE); @@ -239,7 +283,7 @@ BOOL android_verify_certificate(freerdp* instance, char* subject, char* issuer, jboolean res = freerdp_callback_bool_result("OnVerifyCertificate", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z", instance, jstr1, jstr2, jstr3); - if(attached == JNI_TRUE) + if (attached == JNI_TRUE) jni_detach_thread(); return ((res == JNI_TRUE) ? TRUE : FALSE); @@ -250,30 +294,6 @@ BOOL android_verify_changed_certificate(freerdp* instance, char* subject, char* return android_verify_certificate(instance, subject, issuer, new_fingerprint); } -static void android_process_channel_event(rdpChannels* channels, freerdp* instance) -{ - wMessage* event; - - event = freerdp_channels_pop_event(channels); - - if (event) - { - int ev = GetMessageClass(event->id); - switch(ev) - { - case CliprdrChannel_Class: - android_process_cliprdr_event(instance, event); - break; - - default: - DEBUG_ANDROID("Unsupported channel event %08X", ev); - break; - } - - freerdp_event_free(event); - } -} - static void* jni_input_thread(void* arg) { HANDLE event[3]; @@ -330,14 +350,13 @@ static void* jni_channels_thread(void* arg) channels = instance->context->channels; event = freerdp_channels_get_event_handle(instance); - + while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) { status = freerdp_channels_process_pending_messages(instance); + if (!status) - break; - - android_process_channel_event(channels, instance); + break; } DEBUG_ANDROID("Quit."); @@ -513,14 +532,12 @@ static int android_freerdp_run(freerdp* instance) DEBUG_ANDROID("Failed to check channel manager file descriptor\n"); break; } - - android_process_channel_event(instance->context->channels, instance); } } DEBUG_ANDROID("Prepare shutdown..."); - // issue another OnDisconnecting here in case the disconnect was initiated by the sever and not our client + // issue another OnDisconnecting here in case the disconnect was initiated by the server and not our client freerdp_callback("OnDisconnecting", "(I)V", instance); DEBUG_ANDROID("Close channels..."); @@ -701,10 +718,10 @@ JNIEXPORT void JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls, settings->ServerHostname = strdup(hostname); - if(username && strlen(username) > 0) + if (username && strlen(username) > 0) settings->Username = strdup(username); - if(password && strlen(password) > 0) + if (password && strlen(password) > 0) { settings->Password = strdup(password); settings->AutoLogonEnabled = TRUE; @@ -712,7 +729,7 @@ JNIEXPORT void JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls, settings->Domain = strdup(domain); - if(certname && strlen(certname) > 0) + if (certname && strlen(certname) > 0) settings->CertificateName = strdup(certname); settings->ConsoleSession = (console == JNI_TRUE) ? TRUE : FALSE; @@ -823,10 +840,10 @@ JNIEXPORT void JNICALL jni_freerdp_set_advanced_settings(JNIEnv *env, jclass cls settings->AsyncTransport = async_transport; settings->AsyncInput = async_input; - if(remote_program && strlen(remote_program) > 0) + if (remote_program && strlen(remote_program) > 0) settings->AlternateShell = strdup(remote_program); - if(work_dir && strlen(work_dir) > 0) + if (work_dir && strlen(work_dir) > 0) settings->ShellWorkingDirectory = strdup(work_dir); (*env)->ReleaseStringUTFChars(env, jRemoteProgram, remote_program); diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.h b/client/Android/FreeRDPCore/jni/android_freerdp.h index 91d9c93..dd36a65 100644 --- a/client/Android/FreeRDPCore/jni/android_freerdp.h +++ b/client/Android/FreeRDPCore/jni/android_freerdp.h @@ -11,7 +11,12 @@ #define __ANDROID_FREERDP_H #include + +#include +#include + #include +#include #include "android_event.h" @@ -24,7 +29,14 @@ struct android_context BOOL is_connected; - void* clipboard_context; + BOOL clipboardSync; + wClipboard* clipboard; + UINT32 numServerFormats; + UINT32 requestedFormatId; + HANDLE clipboardRequestEvent; + CLIPRDR_FORMAT* serverFormats; + CliprdrClientContext* cliprdr; + UINT32 clipboardCapabilities; }; typedef struct android_context androidContext; -- 2.7.4