diff --git a/src/protocols/rdp/channels/cliprdr.c b/src/protocols/rdp/channels/cliprdr.c index 261f0c98..8f9d92a5 100644 --- a/src/protocols/rdp/channels/cliprdr.c +++ b/src/protocols/rdp/channels/cliprdr.c @@ -352,10 +352,11 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, guac_client* client = clipboard->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; + guac_rdp_settings* settings = rdp_client->settings; guac_client_log(client, GUAC_LOG_TRACE, "CLIPRDR: Received format data request."); - guac_iconv_write* writer; + guac_iconv_write* remote_writer; const char* input = clipboard->clipboard->buffer; char* output = malloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH); @@ -363,11 +364,11 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, switch (format_data_request->requestedFormatId) { case CF_TEXT: - writer = GUAC_WRITE_CP1252; + remote_writer = settings->clipboard_crlf ? GUAC_WRITE_CP1252_CRLF : GUAC_WRITE_CP1252; break; case CF_UNICODETEXT: - writer = GUAC_WRITE_UTF16; + remote_writer = settings->clipboard_crlf ? GUAC_WRITE_UTF16_CRLF : GUAC_WRITE_UTF16; break; /* Warn if clipboard data cannot be sent as intended due to a violation @@ -386,8 +387,9 @@ static UINT guac_rdp_cliprdr_format_data_request(CliprdrClientContext* cliprdr, /* Send received clipboard data to the RDP server in the format * requested */ BYTE* start = (BYTE*) output; - guac_iconv(GUAC_READ_UTF8, &input, clipboard->clipboard->length, - writer, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH); + guac_iconv_read* local_reader = settings->normalize_clipboard ? GUAC_READ_UTF8_NORMALIZED : GUAC_READ_UTF8; + guac_iconv(local_reader, &input, clipboard->clipboard->length, + remote_writer, &output, GUAC_RDP_CLIPBOARD_MAX_LENGTH); CLIPRDR_FORMAT_DATA_RESPONSE data_response = { .requestedFormatData = (BYTE*) start, @@ -449,7 +451,7 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, char received_data[GUAC_RDP_CLIPBOARD_MAX_LENGTH]; - guac_iconv_read* reader; + guac_iconv_read* remote_reader; const char* input = (char*) format_data_response->requestedFormatData; char* output = received_data; @@ -458,12 +460,12 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, /* Non-Unicode (Windows CP-1252) */ case CF_TEXT: - reader = GUAC_READ_CP1252; + remote_reader = settings->normalize_clipboard ? GUAC_READ_CP1252_NORMALIZED : GUAC_READ_CP1252; break; /* Unicode (UTF-16) */ case CF_UNICODETEXT: - reader = GUAC_READ_UTF16; + remote_reader = settings->normalize_clipboard ? GUAC_READ_UTF16_NORMALIZED : GUAC_READ_UTF16; break; /* If the format ID stored within the guac_rdp_clipboard structure is actually @@ -481,7 +483,7 @@ static UINT guac_rdp_cliprdr_format_data_response(CliprdrClientContext* cliprdr, /* Convert, store, and forward the clipboard data received from RDP * server */ - if (guac_iconv(reader, &input, format_data_response->dataLen, + if (guac_iconv(remote_reader, &input, format_data_response->dataLen, GUAC_WRITE_UTF8, &output, sizeof(received_data))) { int length = strnlen(received_data, sizeof(received_data)); guac_common_clipboard_reset(clipboard->clipboard, "text/plain"); diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 5a1d48e9..81dfedf9 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -130,6 +130,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "wol-wait-time", "force-lossless", + "normalize-clipboard", NULL }; @@ -647,6 +648,16 @@ enum RDP_ARGS_IDX { */ IDX_FORCE_LOSSLESS, + /** + * Controls whether the text content of the clipboard should be + * automatically normalized to use a particular line ending format. Valid + * values are "preserve", to preserve line endings verbatim, "windows" to + * transform all line endings to Windows-style CRLF sequences, or "unix" to + * transform all line endings to Unix-style newline characters ('\n'). By + * default, line endings within the clipboard are preserved. + */ + IDX_NORMALIZE_CLIPBOARD, + RDP_ARGS_COUNT }; @@ -1167,7 +1178,36 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, 0); - + + /* Normalize clipboard line endings to Unix format */ + if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "unix") == 0) { + guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Unix (LF)"); + settings->normalize_clipboard = 1; + settings->clipboard_crlf = 0; + } + + /* Normalize clipboard line endings to Windows format */ + else if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "windows") == 0) { + guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Windows (CRLF)"); + settings->normalize_clipboard = 1; + settings->clipboard_crlf = 1; + } + + /* Preserve clipboard line ending format */ + else if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "preserve") == 0) { + guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Preserve (none)"); + settings->normalize_clipboard = 0; + settings->clipboard_crlf = 0; + } + + /* If nothing given, default to preserving line endings */ + else { + guac_user_log(user, GUAC_LOG_INFO, "No clipboard line-ending normalization specified. Defaulting to preserving the format of all line endings."); + settings->normalize_clipboard = 0; + settings->clipboard_crlf = 0; + } + + /* Parse Wake-on-LAN (WoL) settings */ settings->wol_send_packet = guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index f80cde48..daaf3e9c 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -323,6 +323,19 @@ typedef struct guac_rdp_settings { */ int disable_paste; + /** + * Whether line endings within the clipboard should be automatically + * normalized to Unix-style newline characters. + */ + int normalize_clipboard; + + /** + * Whether Unix-style newline characters within the clipboard should be + * automatically translated to CRLF sequences before transmission to the + * RDP server. + */ + int clipboard_crlf; + /** * Whether the desktop wallpaper should be visible. If unset, the desktop * wallpaper will be hidden, reducing the amount of bandwidth required.