From 3b9a19e9931e80536aeca4d76a56df1628829df3 Mon Sep 17 00:00:00 2001 From: Martin Fleisz Date: Wed, 14 Jun 2023 14:44:13 +0200 Subject: [PATCH] cliprdr: Fix an issue with file format filtering on Windows This PR fixes an issue caused by clipboard format filtering which discarded all formats but `FileGroupDescriptorW` to enable clipboard file transfer. However at least on windows we also need `FileContents` to be placed in the clipboard to make file transfer work correctly. The PR also unifies list filtering into a single functions instead of having two different functions. --- channels/cliprdr/client/cliprdr_format.c | 93 +++++++++++++----------- channels/cliprdr/client/cliprdr_format.h | 2 + channels/cliprdr/client/cliprdr_main.c | 66 +---------------- channels/cliprdr/client/cliprdr_main.h | 1 + 4 files changed, 56 insertions(+), 106 deletions(-) diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 4654e0f01..d5ec1a11d 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -35,68 +35,71 @@ #include "cliprdr_format.h" #include "../cliprdr_common.h" -static BOOL cliprdr_filter_server_format_list(CLIPRDR_FORMAT_LIST* list, const UINT32 mask) +CLIPRDR_FORMAT_LIST cliprdr_filter_format_list(const CLIPRDR_FORMAT_LIST* list, const UINT32 mask, + const UINT32 checkMask) { - const UINT32 all = CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES; + const UINT32 maskData = + checkMask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL); + const UINT32 maskFiles = + checkMask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES); WINPR_ASSERT(list); - if ((mask & all) == all) - return TRUE; + CLIPRDR_FORMAT_LIST filtered = { 0 }; + filtered.common.msgType = CB_FORMAT_LIST; + filtered.numFormats = list->numFormats; + filtered.formats = calloc(filtered.numFormats, sizeof(CLIPRDR_FORMAT_LIST)); - if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES) != 0) + size_t wpos = 0; + if ((mask & checkMask) == checkMask) { - const CLIPRDR_FORMAT* files = NULL; for (size_t x = 0; x < list->numFormats; x++) { - CLIPRDR_FORMAT* format = &list->formats[x]; + const CLIPRDR_FORMAT* format = &list->formats[x]; + CLIPRDR_FORMAT* cur = &filtered.formats[x]; + cur->formatId = format->formatId; + if (format->formatName) + cur->formatName = _strdup(format->formatName); + wpos++; + } + } + else if ((mask & maskFiles) != 0) + { + for (size_t x = 0; x < list->numFormats; x++) + { + const CLIPRDR_FORMAT* format = &list->formats[x]; + CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; if (!format->formatName) continue; - if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0) - files = format; - else + if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0 || + strcmp(format->formatName, type_FileContents) == 0) { - free(format->formatName); - format->formatName = NULL; + cur->formatId = format->formatId; + cur->formatName = _strdup(format->formatName); + wpos++; } } - - if (!files) - list->numFormats = 0; - else - { - list->numFormats = 1; - list->formats[0] = *files; - } - return TRUE; } - - if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL) != 0) + else if ((mask & maskData) != 0) { - BOOL move = FALSE; for (size_t x = 0; x < list->numFormats; x++) { - CLIPRDR_FORMAT* format = &list->formats[x]; + const CLIPRDR_FORMAT* format = &list->formats[x]; + CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; - if (move) + if (!format->formatName || + (strcmp(format->formatName, type_FileGroupDescriptorW) != 0 && + strcmp(format->formatName, type_FileContents) != 0)) { - CLIPRDR_FORMAT* last = &list->formats[x - 1]; - *last = *format; - } - else if (!format->formatName) - continue; - else if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0) - { - move = TRUE; - free(format->formatName); - format->formatName = NULL; + cur->formatId = format->formatId; + if (format->formatName) + cur->formatName = _strdup(format->formatName); + wpos++; } } - if (move) - list->numFormats -= 1; - return TRUE; } - return FALSE; + filtered.numFormats = wpos; + return filtered; } /** @@ -108,6 +111,7 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data UINT16 msgFlags) { CLIPRDR_FORMAT_LIST formatList = { 0 }; + CLIPRDR_FORMAT_LIST filteredFormatList = { 0 }; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); UINT error = CHANNEL_RC_OK; @@ -120,19 +124,22 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data const UINT32 mask = freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); - if (!cliprdr_filter_server_format_list(&formatList, mask)) + filteredFormatList = cliprdr_filter_format_list( + &formatList, mask, CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES); + if (filteredFormatList.numFormats == 0) goto error_out; WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %" PRIu32 "", - formatList.numFormats); + filteredFormatList.numFormats); if (context->ServerFormatList) { - if ((error = context->ServerFormatList(context, &formatList))) + if ((error = context->ServerFormatList(context, &filteredFormatList))) WLog_ERR(TAG, "ServerFormatList failed with error %" PRIu32 "", error); } error_out: + cliprdr_free_format_list(&filteredFormatList); cliprdr_free_format_list(&formatList); return error; } diff --git a/channels/cliprdr/client/cliprdr_format.h b/channels/cliprdr/client/cliprdr_format.h index a068d6ff4..a3ba1ed1b 100644 --- a/channels/cliprdr/client/cliprdr_format.h +++ b/channels/cliprdr/client/cliprdr_format.h @@ -31,5 +31,7 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN UINT16 msgFlags); UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags); +CLIPRDR_FORMAT_LIST cliprdr_filter_format_list(const CLIPRDR_FORMAT_LIST* list, const UINT32 mask, + const UINT32 checkMask); #endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H */ diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 1eb30ba22..508ee418c 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -39,6 +39,7 @@ #include "../cliprdr_common.h" const char* type_FileGroupDescriptorW = "FileGroupDescriptorW"; +const char* type_FileContents = "FileContents"; static const char* CB_MSG_TYPE_STRINGS(UINT32 type) { @@ -660,68 +661,6 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context, return cliprdr_packet_send(cliprdr, s); } -static CLIPRDR_FORMAT_LIST cliprdr_filter_local_format_list(const CLIPRDR_FORMAT_LIST* list, - const UINT32 mask) -{ - const UINT32 all = CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES; - WINPR_ASSERT(list); - - CLIPRDR_FORMAT_LIST filtered = { 0 }; - filtered.common.msgType = CB_FORMAT_LIST; - filtered.numFormats = list->numFormats; - filtered.formats = calloc(filtered.numFormats, sizeof(CLIPRDR_FORMAT_LIST)); - - size_t wpos = 0; - if ((mask & all) == all) - { - for (size_t x = 0; x < list->numFormats; x++) - { - const CLIPRDR_FORMAT* format = &list->formats[x]; - CLIPRDR_FORMAT* cur = &filtered.formats[x]; - cur->formatId = format->formatId; - if (format->formatName) - cur->formatName = _strdup(format->formatName); - wpos++; - } - } - else if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES) != 0) - { - for (size_t x = 0; x < list->numFormats; x++) - { - const CLIPRDR_FORMAT* format = &list->formats[x]; - CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; - - if (!format->formatName) - continue; - if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0) - { - cur->formatId = format->formatId; - cur->formatName = _strdup(format->formatName); - wpos++; - break; - } - } - } - else if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE) != 0) - { - for (size_t x = 0; x < list->numFormats; x++) - { - const CLIPRDR_FORMAT* format = &list->formats[x]; - CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; - - if (!format->formatName || (strcmp(format->formatName, type_FileGroupDescriptorW) != 0)) - { - cur->formatId = format->formatId; - if (format->formatName) - cur->formatName = _strdup(format->formatName); - wpos++; - } - } - } - filtered.numFormats = wpos; - return filtered; -} - /** * Function description * @@ -741,7 +680,8 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context, const UINT32 mask = freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); - CLIPRDR_FORMAT_LIST filterList = cliprdr_filter_local_format_list(formatList, mask); + CLIPRDR_FORMAT_LIST filterList = cliprdr_filter_format_list( + formatList, mask, CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES); /* Allow initial format list from monitor ready, but ignore later attempts */ if ((filterList.numFormats == 0) && cliprdr->initialFormatListSent) diff --git a/channels/cliprdr/client/cliprdr_main.h b/channels/cliprdr/client/cliprdr_main.h index 6923b3115..9e899f597 100644 --- a/channels/cliprdr/client/cliprdr_main.h +++ b/channels/cliprdr/client/cliprdr_main.h @@ -56,5 +56,6 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr); UINT cliprdr_send_error_response(cliprdrPlugin* cliprdr, UINT16 type); extern const char* type_FileGroupDescriptorW; +extern const char* type_FileContents; #endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_MAIN_H */