3b9a19e993
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.
244 lines
7.7 KiB
C
244 lines
7.7 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
* Clipboard Virtual Channel
|
|
*
|
|
* Copyright 2009-2011 Jay Sorg
|
|
* Copyright 2010-2011 Vic Lee
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <freerdp/config.h>
|
|
|
|
#include <winpr/crt.h>
|
|
#include <winpr/print.h>
|
|
|
|
#include <freerdp/types.h>
|
|
#include <freerdp/freerdp.h>
|
|
#include <freerdp/settings.h>
|
|
#include <freerdp/constants.h>
|
|
#include <freerdp/client/cliprdr.h>
|
|
|
|
#include "cliprdr_main.h"
|
|
#include "cliprdr_format.h"
|
|
#include "../cliprdr_common.h"
|
|
|
|
CLIPRDR_FORMAT_LIST cliprdr_filter_format_list(const CLIPRDR_FORMAT_LIST* list, const UINT32 mask,
|
|
const UINT32 checkMask)
|
|
{
|
|
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);
|
|
|
|
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 & checkMask) == checkMask)
|
|
{
|
|
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 & 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 ||
|
|
strcmp(format->formatName, type_FileContents) == 0)
|
|
{
|
|
cur->formatId = format->formatId;
|
|
cur->formatName = _strdup(format->formatName);
|
|
wpos++;
|
|
}
|
|
}
|
|
}
|
|
else if ((mask & maskData) != 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 &&
|
|
strcmp(format->formatName, type_FileContents) != 0))
|
|
{
|
|
cur->formatId = format->formatId;
|
|
if (format->formatName)
|
|
cur->formatName = _strdup(format->formatName);
|
|
wpos++;
|
|
}
|
|
}
|
|
}
|
|
filtered.numFormats = wpos;
|
|
return filtered;
|
|
}
|
|
|
|
/**
|
|
* Function description
|
|
*
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
*/
|
|
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
|
|
UINT16 msgFlags)
|
|
{
|
|
CLIPRDR_FORMAT_LIST formatList = { 0 };
|
|
CLIPRDR_FORMAT_LIST filteredFormatList = { 0 };
|
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
formatList.common.msgType = CB_FORMAT_LIST;
|
|
formatList.common.msgFlags = msgFlags;
|
|
formatList.common.dataLen = dataLen;
|
|
|
|
if ((error = cliprdr_read_format_list(s, &formatList, cliprdr->useLongFormatNames)))
|
|
goto error_out;
|
|
|
|
const UINT32 mask =
|
|
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
|
|
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 "",
|
|
filteredFormatList.numFormats);
|
|
|
|
if (context->ServerFormatList)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Function description
|
|
*
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
*/
|
|
UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
|
|
UINT16 msgFlags)
|
|
{
|
|
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 };
|
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse");
|
|
|
|
formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE;
|
|
formatListResponse.common.msgFlags = msgFlags;
|
|
formatListResponse.common.dataLen = dataLen;
|
|
|
|
IFCALLRET(context->ServerFormatListResponse, error, context, &formatListResponse);
|
|
if (error)
|
|
WLog_ERR(TAG, "ServerFormatListResponse failed with error %" PRIu32 "!", error);
|
|
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Function description
|
|
*
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
*/
|
|
UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
|
|
UINT16 msgFlags)
|
|
{
|
|
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = { 0 };
|
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest");
|
|
|
|
formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST;
|
|
formatDataRequest.common.msgFlags = msgFlags;
|
|
formatDataRequest.common.dataLen = dataLen;
|
|
|
|
if ((error = cliprdr_read_format_data_request(s, &formatDataRequest)))
|
|
return error;
|
|
|
|
const UINT32 mask =
|
|
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
|
|
if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0)
|
|
{
|
|
return cliprdr_send_error_response(cliprdr, CB_FORMAT_DATA_RESPONSE);
|
|
}
|
|
|
|
context->lastRequestedFormatId = formatDataRequest.requestedFormatId;
|
|
IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest);
|
|
if (error)
|
|
WLog_ERR(TAG, "ServerFormatDataRequest failed with error %" PRIu32 "!", error);
|
|
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Function description
|
|
*
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
*/
|
|
UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
|
|
UINT16 msgFlags)
|
|
{
|
|
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse = { 0 };
|
|
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
|
UINT error = CHANNEL_RC_OK;
|
|
|
|
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataResponse");
|
|
|
|
formatDataResponse.common.msgType = CB_FORMAT_DATA_RESPONSE;
|
|
formatDataResponse.common.msgFlags = msgFlags;
|
|
formatDataResponse.common.dataLen = dataLen;
|
|
|
|
if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
|
|
return error;
|
|
|
|
const UINT32 mask =
|
|
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
|
|
if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0)
|
|
{
|
|
WLog_WARN(TAG,
|
|
"Received ServerFormatDataResponse but remote -> local clipboard is disabled");
|
|
return CHANNEL_RC_OK;
|
|
}
|
|
|
|
IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse);
|
|
if (error)
|
|
WLog_ERR(TAG, "ServerFormatDataResponse failed with error %" PRIu32 "!", error);
|
|
|
|
return error;
|
|
}
|