summaryrefslogtreecommitdiffstats
path: root/channels/cliprdr/client/cliprdr_format.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/cliprdr/client/cliprdr_format.c')
-rw-r--r--channels/cliprdr/client/cliprdr_format.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c
new file mode 100644
index 0000000..8b13af4
--- /dev/null
+++ b/channels/cliprdr/client/cliprdr_format.c
@@ -0,0 +1,243 @@
+/**
+ * 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));
+
+ 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;
+}