From 2aa7252d1b126108be4302d57f397adb089dabe7 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 7 Apr 2014 19:22:53 -0700 Subject: [PATCH] GUAC-608: Implement outbound clipboard streaming. Stub out inbound. --- src/protocols/rdp/guac_handlers.c | 17 ++++++++++--- src/protocols/rdp/guac_handlers.h | 4 ++- src/protocols/rdp/rdp_cliprdr.c | 41 +++++++++++++++++++++++++++++-- src/protocols/rdp/rdp_stream.c | 25 +++++++++++++++++++ src/protocols/rdp/rdp_stream.h | 24 +++++++++++++++++- 5 files changed, 104 insertions(+), 7 deletions(-) diff --git a/src/protocols/rdp/guac_handlers.c b/src/protocols/rdp/guac_handlers.c index 0c55e7f0..5052a8d5 100644 --- a/src/protocols/rdp/guac_handlers.c +++ b/src/protocols/rdp/guac_handlers.c @@ -459,8 +459,12 @@ int rdp_guac_client_key_handler(guac_client* client, int keysym, int pressed) { } -int rdp_guac_client_clipboard_handler(guac_client* client, char* data) { +int rdp_guac_client_clipboard_handler(guac_client* client, guac_stream* stream, + char* mimetype) { + return guac_rdp_clipboard_handler(client, stream, mimetype); + +#if 0 rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; rdpChannels* channels = client_data->rdp_inst->context->channels; @@ -479,8 +483,7 @@ int rdp_guac_client_clipboard_handler(guac_client* client, char* data) { format_list->num_formats = 1; freerdp_channels_send_event(channels, (wMessage*) format_list); - - return 0; +#endif } @@ -516,6 +519,10 @@ int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream, case GUAC_RDP_INBOUND_SVC_STREAM: return guac_rdp_svc_blob_handler(client, stream, data, length); + /* Clipboard stream */ + case GUAC_RDP_INBOUND_CLIPBOARD_STREAM: + return guac_rdp_clipboard_blob_handler(client, stream, data, length); + /* Other streams do not accept blobs */ default: guac_protocol_send_ack(client->socket, stream, @@ -540,6 +547,10 @@ int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream) { case GUAC_RDP_UPLOAD_STREAM: return guac_rdp_upload_end_handler(client, stream); + /* Clipboard stream */ + case GUAC_RDP_INBOUND_CLIPBOARD_STREAM: + return guac_rdp_clipboard_end_handler(client, stream); + /* Other streams do not accept explicit closure */ default: guac_protocol_send_ack(client->socket, stream, diff --git a/src/protocols/rdp/guac_handlers.h b/src/protocols/rdp/guac_handlers.h index e9d20137..b0775daf 100644 --- a/src/protocols/rdp/guac_handlers.h +++ b/src/protocols/rdp/guac_handlers.h @@ -33,7 +33,9 @@ int rdp_guac_client_free_handler(guac_client* client); int rdp_guac_client_handle_messages(guac_client* client); int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask); int rdp_guac_client_key_handler(guac_client* client, int keysym, int pressed); -int rdp_guac_client_clipboard_handler(guac_client* client, char* data); + +int rdp_guac_client_clipboard_handler(guac_client* client, guac_stream*, + char* mimetype); int rdp_guac_client_file_handler(guac_client* client, guac_stream* stream, char* mimetype, char* filename); diff --git a/src/protocols/rdp/rdp_cliprdr.c b/src/protocols/rdp/rdp_cliprdr.c index 1e939a6b..7489267c 100644 --- a/src/protocols/rdp/rdp_cliprdr.c +++ b/src/protocols/rdp/rdp_cliprdr.c @@ -247,8 +247,45 @@ void guac_rdp_process_cb_data_response(guac_client* client, /* Convert send clipboard data */ if (guac_iconv(reader, &input, event->size, - GUAC_WRITE_UTF8, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH)) - guac_protocol_send_clipboard(client->socket, client_data->clipboard); + GUAC_WRITE_UTF8, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH)) { + + char* current = client_data->clipboard; + int remaining = GUAC_RDP_CLIPBOARD_MAX_LENGTH; + + /* Begin stream */ + guac_stream* stream = guac_client_alloc_stream(client); + guac_protocol_send_clipboard(client->socket, stream, "text/plain"); + + /* Split clipboard into chunks */ + while (remaining > 0) { + + /* Calculate size of next block */ + int block_size = 4096; + if (remaining < block_size) + block_size = remaining; + + /* If at end of string, send final blob */ + int length = strnlen(current, block_size); + if (length < block_size) { + guac_protocol_send_blob(client->socket, stream, current, length+1); + break; + } + + /* Otherwise, send current blob and continue */ + else + guac_protocol_send_blob(client->socket, stream, current, length); + + /* Next block */ + remaining -= length; + current += length; + + } + + /* End stream */ + guac_protocol_send_end(client->socket, stream); + guac_client_free_stream(client, stream); + + } } diff --git a/src/protocols/rdp/rdp_stream.c b/src/protocols/rdp/rdp_stream.c index ad15e943..1e1252f5 100644 --- a/src/protocols/rdp/rdp_stream.c +++ b/src/protocols/rdp/rdp_stream.c @@ -143,6 +143,20 @@ int guac_rdp_svc_pipe_handler(guac_client* client, guac_stream* stream, } +int guac_rdp_clipboard_handler(guac_client* client, guac_stream* stream, + char* mimetype) { + + guac_rdp_stream* rdp_stream; + + /* Init stream data */ + stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream)); + rdp_stream->type = GUAC_RDP_INBOUND_CLIPBOARD_STREAM; + + guac_client_log_info(client, "Creating clipboard stream %s", mimetype); + return 0; + +} + int guac_rdp_upload_blob_handler(guac_client* client, guac_stream* stream, void* data, int length) { @@ -205,6 +219,12 @@ int guac_rdp_svc_blob_handler(guac_client* client, guac_stream* stream, } +int guac_rdp_clipboard_blob_handler(guac_client* client, guac_stream* stream, + void* data, int length) { + guac_client_log_info(client, "Received %i bytes of clipboard data", length); + return 0; +} + int guac_rdp_upload_end_handler(guac_client* client, guac_stream* stream) { guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data; @@ -231,6 +251,11 @@ int guac_rdp_upload_end_handler(guac_client* client, guac_stream* stream) { } +int guac_rdp_clipboard_end_handler(guac_client* client, guac_stream* stream) { + guac_client_log_info(client, "Received end of clipboard data"); + return 0; +} + int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream, char* message, guac_protocol_status status) { diff --git a/src/protocols/rdp/rdp_stream.h b/src/protocols/rdp/rdp_stream.h index e7cf6958..978f8ae1 100644 --- a/src/protocols/rdp/rdp_stream.h +++ b/src/protocols/rdp/rdp_stream.h @@ -82,7 +82,12 @@ typedef enum guac_rdp_stream_type { /** * The inbound half of a static virtual channel. */ - GUAC_RDP_INBOUND_SVC_STREAM + GUAC_RDP_INBOUND_SVC_STREAM, + + /** + * An inbound stream of clipboard data. + */ + GUAC_RDP_INBOUND_CLIPBOARD_STREAM } guac_rdp_stream_type; @@ -125,6 +130,12 @@ int guac_rdp_upload_file_handler(guac_client* client, guac_stream* stream, int guac_rdp_svc_pipe_handler(guac_client* client, guac_stream* stream, char* mimetype, char* name); +/** + * Handler for inbound clipboard data. + */ +int guac_rdp_clipboard_handler(guac_client* client, guac_stream* stream, + char* mimetype); + /** * Handler for stream data related to file uploads. */ @@ -137,11 +148,22 @@ int guac_rdp_upload_blob_handler(guac_client* client, guac_stream* stream, int guac_rdp_svc_blob_handler(guac_client* client, guac_stream* stream, void* data, int length); +/** + * Handler for stream data related to clipboard. + */ +int guac_rdp_clipboard_blob_handler(guac_client* client, guac_stream* stream, + void* data, int length); + /** * Handler for end-of-stream related to file uploads. */ int guac_rdp_upload_end_handler(guac_client* client, guac_stream* stream); +/** + * Handler for end-of-stream related to clipboard. + */ +int guac_rdp_clipboard_end_handler(guac_client* client, guac_stream* stream); + /** * Handler for acknowledgements of receipt of data related to file downloads. */