Blame client/Wayland/wlf_cliprdr.c

Packit Service 5a9772
/**
Packit Service 5a9772
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service 5a9772
 * Wayland Clipboard Redirection
Packit Service 5a9772
 *
Packit Service 5a9772
 * Copyright 2018 Armin Novak <armin.novak@thincast.com>
Packit Service 5a9772
 * Copyright 2018 Thincast Technologies GmbH
Packit Service 5a9772
 *
Packit Service 5a9772
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service 5a9772
 * you may not use this file except in compliance with the License.
Packit Service 5a9772
 * You may obtain a copy of the License at
Packit Service 5a9772
 *
Packit Service 5a9772
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 5a9772
 *
Packit Service 5a9772
 * Unless required by applicable law or agreed to in writing, software
Packit Service 5a9772
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service 5a9772
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service 5a9772
 * See the License for the specific language governing permissions and
Packit Service 5a9772
 * limitations under the License.
Packit Service 5a9772
 */
Packit Service 5a9772
Packit Service 5a9772
#ifdef HAVE_CONFIG_H
Packit Service 5a9772
#include "config.h"
Packit Service 5a9772
#endif
Packit Service 5a9772
Packit Service 5a9772
#include <stdlib.h>
Packit Service 5a9772
Packit Service 5a9772
#include <winpr/crt.h>
Packit Service 5a9772
#include <winpr/image.h>
Packit Service 5a9772
#include <winpr/stream.h>
Packit Service 5a9772
#include <winpr/clipboard.h>
Packit Service 5a9772
Packit Service 5a9772
#include <freerdp/log.h>
Packit Service 5a9772
#include <freerdp/client/cliprdr.h>
Packit Service 5a9772
#include <freerdp/channels/channels.h>
Packit Service 5a9772
#include <freerdp/channels/cliprdr.h>
Packit Service 5a9772
Packit Service 5a9772
#include "wlf_cliprdr.h"
Packit Service 5a9772
Packit Service 5a9772
#define TAG CLIENT_TAG("wayland.cliprdr")
Packit Service 5a9772
Packit Service 5a9772
#define MAX_CLIPBOARD_FORMATS 255
Packit Service 5a9772
Packit Service 5a9772
static const char* mime_text[] = { "text/plain",  "text/plain;charset=utf-8",
Packit Service 5a9772
	                               "UTF8_STRING", "COMPOUND_TEXT",
Packit Service 5a9772
	                               "TEXT",        "STRING" };
Packit Service 5a9772
Packit Service 5a9772
static const char* mime_image[] = {
Packit Service 5a9772
	"image/png",       "image/bmp",   "image/x-bmp",        "image/x-MS-bmp",
Packit Service 5a9772
	"image/x-icon",    "image/x-ico", "image/x-win-bitmap", "image/vmd.microsoft.icon",
Packit Service 5a9772
	"application/ico", "image/ico",   "image/icon",         "image/jpeg",
Packit Service 5a9772
	"image/tiff"
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static const char* mime_html[] = { "text/html" };
Packit Service 5a9772
Packit Service 5a9772
struct wlf_clipboard
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wfc;
Packit Service 5a9772
	rdpChannels* channels;
Packit Service 5a9772
	CliprdrClientContext* context;
Packit Service 5a9772
	wLog* log;
Packit Service 5a9772
Packit Service 5a9772
	UwacSeat* seat;
Packit Service 5a9772
	wClipboard* system;
Packit Service 5a9772
	wClipboardDelegate* delegate;
Packit Service 5a9772
Packit Service 5a9772
	size_t numClientFormats;
Packit Service 5a9772
	CLIPRDR_FORMAT* clientFormats;
Packit Service 5a9772
Packit Service 5a9772
	size_t numServerFormats;
Packit Service 5a9772
	CLIPRDR_FORMAT* serverFormats;
Packit Service 5a9772
Packit Service 5a9772
	BOOL sync;
Packit Service 5a9772
Packit Service 5a9772
	/* File clipping */
Packit Service 5a9772
	BOOL streams_supported;
Packit Service 5a9772
	BOOL file_formats_registered;
Packit Service 5a9772
Packit Service 5a9772
	/* Server response stuff */
Packit Service 5a9772
	FILE* responseFile;
Packit Service 5a9772
	UINT32 responseFormat;
Packit Service 5a9772
	const char* responseMime;
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_mime_is_text(const char* mime)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t x;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_text); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (strcmp(mime, mime_text[x]) == 0)
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_mime_is_image(const char* mime)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t x;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_image); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (strcmp(mime, mime_image[x]) == 0)
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_mime_is_html(const char* mime)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t x;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_html); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (strcmp(mime, mime_html[x]) == 0)
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_cliprdr_free_server_formats(wfClipboard* clipboard)
Packit Service 5a9772
{
Packit Service 5a9772
	if (clipboard && clipboard->serverFormats)
Packit Service 5a9772
	{
Packit Service 5a9772
		size_t j;
Packit Service 5a9772
Packit Service 5a9772
		for (j = 0; j < clipboard->numServerFormats; j++)
Packit Service 5a9772
		{
Packit Service 5a9772
			CLIPRDR_FORMAT* format = &clipboard->serverFormats[j];
Packit Service 5a9772
			free(format->formatName);
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		free(clipboard->serverFormats);
Packit Service 5a9772
		clipboard->serverFormats = NULL;
Packit Service 5a9772
		clipboard->numServerFormats = 0;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (clipboard)
Packit Service 5a9772
		UwacClipboardOfferDestroy(clipboard->seat);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_cliprdr_free_client_formats(wfClipboard* clipboard)
Packit Service 5a9772
{
Packit Service 5a9772
	if (clipboard && clipboard->numClientFormats)
Packit Service 5a9772
	{
Packit Service 5a9772
		size_t j;
Packit Service 5a9772
Packit Service 5a9772
		for (j = 0; j < clipboard->numClientFormats; j++)
Packit Service 5a9772
		{
Packit Service 5a9772
			CLIPRDR_FORMAT* format = &clipboard->clientFormats[j];
Packit Service 5a9772
			free(format->formatName);
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		free(clipboard->clientFormats);
Packit Service 5a9772
		clipboard->clientFormats = NULL;
Packit Service 5a9772
		clipboard->numClientFormats = 0;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (clipboard)
Packit Service 5a9772
		UwacClipboardOfferDestroy(clipboard->seat);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_send_client_format_list(wfClipboard* clipboard)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FORMAT_LIST formatList = { 0 };
Packit Service 5a9772
	formatList.msgFlags = CB_RESPONSE_OK;
Packit Service 5a9772
	formatList.numFormats = (UINT32)clipboard->numClientFormats;
Packit Service 5a9772
	formatList.formats = clipboard->clientFormats;
Packit Service 5a9772
	formatList.msgType = CB_FORMAT_LIST;
Packit Service 5a9772
	return clipboard->context->ClientFormatList(clipboard->context, &formatList);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wfl_cliprdr_add_client_format_id(wfClipboard* clipboard, UINT32 formatId)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t x;
Packit Service 5a9772
	CLIPRDR_FORMAT* format;
Packit Service 5a9772
	const char* name = ClipboardGetFormatName(clipboard->system, formatId);
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < clipboard->numClientFormats; x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		format = &clipboard->clientFormats[x];
Packit Service 5a9772
Packit Service 5a9772
		if (format->formatId == formatId)
Packit Service 5a9772
			return;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	format = realloc(clipboard->clientFormats,
Packit Service 5a9772
	                 (clipboard->numClientFormats + 1) * sizeof(CLIPRDR_FORMAT));
Packit Service 5a9772
Packit Service 5a9772
	if (!format)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	clipboard->clientFormats = format;
Packit Service 5a9772
	format = &clipboard->clientFormats[clipboard->numClientFormats++];
Packit Service 5a9772
	format->formatId = formatId;
Packit Service 5a9772
	format->formatName = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (name && (formatId >= CF_MAX))
Packit Service 5a9772
		format->formatName = _strdup(name);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_cliprdr_add_client_format(wfClipboard* clipboard, const char* mime)
Packit Service 5a9772
{
Packit Service 5a9772
	if (wlf_mime_is_html(mime))
Packit Service 5a9772
	{
Packit Service 5a9772
		UINT32 formatId = ClipboardGetFormatId(clipboard->system, "HTML Format");
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, formatId);
Packit Service 5a9772
	}
Packit Service 5a9772
	else if (wlf_mime_is_text(mime))
Packit Service 5a9772
	{
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, CF_TEXT);
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, CF_OEMTEXT);
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, CF_UNICODETEXT);
Packit Service 5a9772
	}
Packit Service 5a9772
	else if (wlf_mime_is_image(mime))
Packit Service 5a9772
	{
Packit Service 5a9772
		UINT32 formatId = ClipboardGetFormatId(clipboard->system, "image/bmp");
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, formatId);
Packit Service 5a9772
		wfl_cliprdr_add_client_format_id(clipboard, CF_DIB);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	wlf_cliprdr_send_client_format_list(clipboard);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_send_data_request(wfClipboard* clipboard, UINT32 formatId)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FORMAT_DATA_REQUEST request = { 0 };
Packit Service 5a9772
	request.requestedFormatId = formatId;
Packit Service 5a9772
	return clipboard->context->ClientFormatDataRequest(clipboard->context, &request);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_send_data_response(wfClipboard* clipboard, const BYTE* data, size_t size)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
Packit Service 5a9772
Packit Service 5a9772
	if (size > UINT32_MAX)
Packit Service 5a9772
		return ERROR_INVALID_PARAMETER;
Packit Service 5a9772
Packit Service 5a9772
	response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
Packit Service 5a9772
	response.dataLen = (UINT32)size;
Packit Service 5a9772
	response.requestedFormatData = data;
Packit Service 5a9772
	return clipboard->context->ClientFormatDataResponse(clipboard->context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!clipboard || !event)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!clipboard->context)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	switch (event->type)
Packit Service 5a9772
	{
Packit Service 5a9772
		case UWAC_EVENT_CLIPBOARD_AVAILABLE:
Packit Service 5a9772
			clipboard->seat = event->seat;
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
Packit Service 5a9772
		case UWAC_EVENT_CLIPBOARD_OFFER:
Packit Service 5a9772
			WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime);
Packit Service 5a9772
			wlf_cliprdr_add_client_format(clipboard, event->mime);
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
Packit Service 5a9772
		case UWAC_EVENT_CLIPBOARD_SELECT:
Packit Service 5a9772
			WLog_Print(clipboard->log, WLOG_DEBUG, "client announces new data");
Packit Service 5a9772
			wlf_cliprdr_free_client_formats(clipboard);
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
Packit Service 5a9772
		default:
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_send_client_capabilities(wfClipboard* clipboard)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_CAPABILITIES capabilities;
Packit Service 5a9772
	CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
Packit Service 5a9772
	capabilities.cCapabilitiesSets = 1;
Packit Service 5a9772
	capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet);
Packit Service 5a9772
	generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
Packit Service 5a9772
	generalCapabilitySet.capabilitySetLength = 12;
Packit Service 5a9772
	generalCapabilitySet.version = CB_CAPS_VERSION_2;
Packit Service 5a9772
	generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
Packit Service 5a9772
Packit Service 5a9772
	if (clipboard->streams_supported && clipboard->file_formats_registered)
Packit Service 5a9772
		generalCapabilitySet.generalFlags |= CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS;
Packit Service 5a9772
Packit Service 5a9772
	return clipboard->context->ClientCapabilities(clipboard->context, &capabilities);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_send_client_format_list_response(wfClipboard* clipboard, BOOL status)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
Packit Service 5a9772
	formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
Packit Service 5a9772
	formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
Packit Service 5a9772
	formatListResponse.dataLen = 0;
Packit Service 5a9772
	return clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_monitor_ready(CliprdrClientContext* context,
Packit Service 5a9772
                                      const CLIPRDR_MONITOR_READY* monitorReady)
Packit Service 5a9772
{
Packit Service 5a9772
	wfClipboard* clipboard = (wfClipboard*)context->custom;
Packit Service 5a9772
	UINT ret;
Packit Service 5a9772
	WINPR_UNUSED(monitorReady);
Packit Service 5a9772
Packit Service 5a9772
	if ((ret = wlf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK)
Packit Service 5a9772
		return ret;
Packit Service 5a9772
Packit Service 5a9772
	if ((ret = wlf_cliprdr_send_client_format_list(clipboard)) != CHANNEL_RC_OK)
Packit Service 5a9772
		return ret;
Packit Service 5a9772
Packit Service 5a9772
	clipboard->sync = TRUE;
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_server_capabilities(CliprdrClientContext* context,
Packit Service 5a9772
                                            const CLIPRDR_CAPABILITIES* capabilities)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT32 i;
Packit Service 5a9772
	const BYTE* capsPtr = (const BYTE*)capabilities->capabilitySets;
Packit Service 5a9772
	wfClipboard* clipboard = (wfClipboard*)context->custom;
Packit Service 5a9772
	clipboard->streams_supported = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	for (i = 0; i < capabilities->cCapabilitiesSets; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const CLIPRDR_CAPABILITY_SET* caps = (const CLIPRDR_CAPABILITY_SET*)capsPtr;
Packit Service 5a9772
Packit Service 5a9772
		if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
Packit Service 5a9772
		{
Packit Service 5a9772
			const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps =
Packit Service 5a9772
			    (const CLIPRDR_GENERAL_CAPABILITY_SET*)caps;
Packit Service 5a9772
Packit Service 5a9772
			if (generalCaps->generalFlags & CB_STREAM_FILECLIP_ENABLED)
Packit Service 5a9772
			{
Packit Service 5a9772
				clipboard->streams_supported = TRUE;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		capsPtr += caps->capabilitySetLength;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* mime, int fd)
Packit Service 5a9772
{
Packit Service 5a9772
	wfClipboard* clipboard = (wfClipboard*)context;
Packit Service 5a9772
	size_t x;
Packit Service 5a9772
	WINPR_UNUSED(seat);
Packit Service 5a9772
	clipboard->responseMime = NULL;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_html); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const char* mime_cur = mime_html[x];
Packit Service 5a9772
Packit Service 5a9772
		if (strcmp(mime_cur, mime) == 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			clipboard->responseMime = mime_cur;
Packit Service 5a9772
			clipboard->responseFormat = ClipboardGetFormatId(clipboard->system, "HTML Format");
Packit Service 5a9772
			break;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_text); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const char* mime_cur = mime_text[x];
Packit Service 5a9772
Packit Service 5a9772
		if (strcmp(mime_cur, mime) == 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			clipboard->responseMime = mime_cur;
Packit Service 5a9772
			clipboard->responseFormat = CF_UNICODETEXT;
Packit Service 5a9772
			break;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < ARRAYSIZE(mime_image); x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const char* mime_cur = mime_image[x];
Packit Service 5a9772
Packit Service 5a9772
		if (strcmp(mime_cur, mime) == 0)
Packit Service 5a9772
		{
Packit Service 5a9772
			clipboard->responseMime = mime_cur;
Packit Service 5a9772
			clipboard->responseFormat = CF_DIB;
Packit Service 5a9772
			break;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (clipboard->responseMime != NULL)
Packit Service 5a9772
	{
Packit Service 5a9772
		clipboard->responseFile = fdopen(fd, "w");
Packit Service 5a9772
Packit Service 5a9772
		if (clipboard->responseFile)
Packit Service 5a9772
			wlf_cliprdr_send_data_request(clipboard, clipboard->responseFormat);
Packit Service 5a9772
		else
Packit Service 5a9772
			WLog_Print(clipboard->log, WLOG_ERROR,
Packit Service 5a9772
			           "failed to open clipboard file descriptor for MIME %s",
Packit Service 5a9772
			           clipboard->responseMime);
Packit Service 5a9772
	}
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context)
Packit Service 5a9772
{
Packit Service 5a9772
	WINPR_UNUSED(seat);
Packit Service 5a9772
	WINPR_UNUSED(context);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Called when the clipboard changes server side.
Packit Service 5a9772
 *
Packit Service 5a9772
 * Clear the local clipboard offer and replace it with a new one
Packit Service 5a9772
 * that announces the formats we get listed here.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT wlf_cliprdr_server_format_list(CliprdrClientContext* context,
Packit Service 5a9772
                                           const CLIPRDR_FORMAT_LIST* formatList)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT32 i;
Packit Service 5a9772
	wfClipboard* clipboard;
Packit Service 5a9772
	BOOL html = FALSE;
Packit Service 5a9772
	BOOL text = FALSE;
Packit Service 5a9772
	BOOL image = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!context || !context->custom)
Packit Service 5a9772
		return ERROR_INVALID_PARAMETER;
Packit Service 5a9772
Packit Service 5a9772
	clipboard = (wfClipboard*)context->custom;
Packit Service 5a9772
	wlf_cliprdr_free_server_formats(clipboard);
Packit Service 5a9772
Packit Service 5a9772
	if (!(clipboard->serverFormats =
Packit Service 5a9772
	          (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT))))
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_Print(clipboard->log, WLOG_ERROR,
Packit Service 5a9772
		           "failed to allocate %" PRIuz " CLIPRDR_FORMAT structs",
Packit Service 5a9772
		           clipboard->numServerFormats);
Packit Service 5a9772
		return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	clipboard->numServerFormats = formatList->numFormats;
Packit Service 5a9772
Packit Service 5a9772
	if (!clipboard->seat)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_Print(clipboard->log, WLOG_ERROR,
Packit Service 5a9772
		           "clipboard->seat=NULL, check your client implementation");
Packit Service 5a9772
		return ERROR_INTERNAL_ERROR;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	for (i = 0; i < formatList->numFormats; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const CLIPRDR_FORMAT* format = &formatList->formats[i];
Packit Service 5a9772
		CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i];
Packit Service 5a9772
		srvFormat->formatId = format->formatId;
Packit Service 5a9772
Packit Service 5a9772
		if (format->formatName)
Packit Service 5a9772
		{
Packit Service 5a9772
			srvFormat->formatName = _strdup(format->formatName);
Packit Service 5a9772
Packit Service 5a9772
			if (!srvFormat->formatName)
Packit Service 5a9772
			{
Packit Service 5a9772
				wlf_cliprdr_free_server_formats(clipboard);
Packit Service 5a9772
				return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		if (format->formatName)
Packit Service 5a9772
		{
Packit Service 5a9772
			if (strcmp(format->formatName, "HTML Format") == 0)
Packit Service 5a9772
			{
Packit Service 5a9772
				text = TRUE;
Packit Service 5a9772
				html = TRUE;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
		else
Packit Service 5a9772
		{
Packit Service 5a9772
			switch (format->formatId)
Packit Service 5a9772
			{
Packit Service 5a9772
				case CF_TEXT:
Packit Service 5a9772
				case CF_OEMTEXT:
Packit Service 5a9772
				case CF_UNICODETEXT:
Packit Service 5a9772
					text = TRUE;
Packit Service 5a9772
					break;
Packit Service 5a9772
Packit Service 5a9772
				case CF_DIB:
Packit Service 5a9772
					image = TRUE;
Packit Service 5a9772
					break;
Packit Service 5a9772
Packit Service 5a9772
				default:
Packit Service 5a9772
					break;
Packit Service 5a9772
			}
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (html)
Packit Service 5a9772
	{
Packit Service 5a9772
		size_t x;
Packit Service 5a9772
Packit Service 5a9772
		for (x = 0; x < ARRAYSIZE(mime_html); x++)
Packit Service 5a9772
			UwacClipboardOfferCreate(clipboard->seat, mime_html[x]);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (text)
Packit Service 5a9772
	{
Packit Service 5a9772
		size_t x;
Packit Service 5a9772
Packit Service 5a9772
		for (x = 0; x < ARRAYSIZE(mime_text); x++)
Packit Service 5a9772
			UwacClipboardOfferCreate(clipboard->seat, mime_text[x]);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (image)
Packit Service 5a9772
	{
Packit Service 5a9772
		size_t x;
Packit Service 5a9772
Packit Service 5a9772
		for (x = 0; x < ARRAYSIZE(mime_image); x++)
Packit Service 5a9772
			UwacClipboardOfferCreate(clipboard->seat, mime_image[x]);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	UwacClipboardOfferAnnounce(clipboard->seat, clipboard, wlf_cliprdr_transfer_data,
Packit Service 5a9772
	                           wlf_cliprdr_cancel_data);
Packit Service 5a9772
	return wlf_cliprdr_send_client_format_list_response(clipboard, TRUE);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_format_list_response(CliprdrClientContext* context,
Packit Service 5a9772
                                        const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
Packit Service 5a9772
{
Packit Service 5a9772
	// wfClipboard* clipboard = (wfClipboard*) context->custom;
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_format_data_request(CliprdrClientContext* context,
Packit Service 5a9772
                                       const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
Packit Service 5a9772
{
Packit Service 5a9772
	int cnv;
Packit Service 5a9772
	UINT rc = CHANNEL_RC_OK;
Packit Service 5a9772
	BYTE* data;
Packit Service 5a9772
	LPWSTR cdata;
Packit Service 5a9772
	size_t size;
Packit Service 5a9772
	const char* mime;
Packit Service 5a9772
	UINT32 formatId = formatDataRequest->requestedFormatId;
Packit Service 5a9772
	wfClipboard* clipboard = (wfClipboard*)context->custom;
Packit Service 5a9772
Packit Service 5a9772
	switch (formatId)
Packit Service 5a9772
	{
Packit Service 5a9772
		case CF_TEXT:
Packit Service 5a9772
		case CF_OEMTEXT:
Packit Service 5a9772
		case CF_UNICODETEXT:
Packit Service 5a9772
			mime = "text/plain;charset=utf-8";
Packit Service 5a9772
			break;
Packit Service 5a9772
Packit Service 5a9772
		case CF_DIB:
Packit Service 5a9772
		case CF_DIBV5:
Packit Service 5a9772
			mime = "image/bmp";
Packit Service 5a9772
			break;
Packit Service 5a9772
Packit Service 5a9772
		default:
Packit Service 5a9772
			if (formatId == ClipboardGetFormatId(clipboard->system, "HTML Format"))
Packit Service 5a9772
				mime = "text/html";
Packit Service 5a9772
			else if (formatId == ClipboardGetFormatId(clipboard->system, "image/bmp"))
Packit Service 5a9772
				mime = "image/bmp";
Packit Service 5a9772
			else
Packit Service 5a9772
				mime = ClipboardGetFormatName(clipboard->system, formatId);
Packit Service 5a9772
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	data = UwacClipboardDataGet(clipboard->seat, mime, &size);
Packit Service 5a9772
Packit Service 5a9772
	if (!data)
Packit Service 5a9772
		return ERROR_INTERNAL_ERROR;
Packit Service 5a9772
Packit Service 5a9772
	switch (formatId)
Packit Service 5a9772
	{
Packit Service 5a9772
		case CF_UNICODETEXT:
Packit Service 5a9772
			if (size > INT_MAX)
Packit Service 5a9772
				rc = ERROR_INTERNAL_ERROR;
Packit Service 5a9772
			else
Packit Service 5a9772
			{
Packit Service 5a9772
				cdata = NULL;
Packit Service 5a9772
				cnv = ConvertToUnicode(CP_UTF8, 0, (LPCSTR)data, (int)size, &cdata, 0);
Packit Service 5a9772
				free(data);
Packit Service 5a9772
				data = NULL;
Packit Service 5a9772
Packit Service 5a9772
				if (cnv < 0)
Packit Service 5a9772
					rc = ERROR_INTERNAL_ERROR;
Packit Service 5a9772
				else
Packit Service 5a9772
				{
Packit Service 5a9772
					size = (size_t)cnv;
Packit Service 5a9772
					data = (BYTE*)cdata;
Packit Service 5a9772
					size *= sizeof(WCHAR);
Packit Service 5a9772
				}
Packit Service 5a9772
			}
Packit Service 5a9772
Packit Service 5a9772
			break;
Packit Service 5a9772
Packit Service 5a9772
		default:
Packit Service 5a9772
			// TODO: Image conversions
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (rc != CHANNEL_RC_OK)
Packit Service 5a9772
		return rc;
Packit Service 5a9772
Packit Service 5a9772
	rc = wlf_cliprdr_send_data_response(clipboard, data, size);
Packit Service 5a9772
	free(data);
Packit Service 5a9772
	return rc;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_format_data_response(CliprdrClientContext* context,
Packit Service 5a9772
                                        const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
Packit Service 5a9772
{
Packit Service 5a9772
	int cnv;
Packit Service 5a9772
	UINT rc = ERROR_INTERNAL_ERROR;
Packit Service 5a9772
	UINT32 size = formatDataResponse->dataLen;
Packit Service 5a9772
	LPSTR cdata = NULL;
Packit Service 5a9772
	LPCSTR data = (LPCSTR)formatDataResponse->requestedFormatData;
Packit Service 5a9772
	const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData;
Packit Service 5a9772
	wfClipboard* clipboard = (wfClipboard*)context->custom;
Packit Service 5a9772
Packit Service 5a9772
	if (size > INT_MAX * sizeof(WCHAR))
Packit Service 5a9772
		return ERROR_INTERNAL_ERROR;
Packit Service 5a9772
Packit Service 5a9772
	switch (clipboard->responseFormat)
Packit Service 5a9772
	{
Packit Service 5a9772
		case CF_UNICODETEXT:
Packit Service 5a9772
			cnv = ConvertFromUnicode(CP_UTF8, 0, wdata, (int)(size / sizeof(WCHAR)), &cdata, 0,
Packit Service 5a9772
			                         NULL, NULL);
Packit Service 5a9772
Packit Service 5a9772
			if (cnv < 0)
Packit Service 5a9772
				return ERROR_INTERNAL_ERROR;
Packit Service 5a9772
Packit Service 5a9772
			size = (size_t)cnv;
Packit Service 5a9772
			data = cdata;
Packit Service 5a9772
			break;
Packit Service 5a9772
Packit Service 5a9772
		default:
Packit Service 5a9772
			// TODO: Image conversions
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	fwrite(data, 1, size, clipboard->responseFile);
Packit Service 5a9772
	fclose(clipboard->responseFile);
Packit Service 5a9772
	rc = CHANNEL_RC_OK;
Packit Service 5a9772
	free(cdata);
Packit Service 5a9772
	return rc;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_file_size_request(wfClipboard* clipboard,
Packit Service 5a9772
                                     const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
Packit Service 5a9772
{
Packit Service 5a9772
	wClipboardFileSizeRequest request = { 0 };
Packit Service 5a9772
	request.streamId = fileContentsRequest->streamId;
Packit Service 5a9772
	request.listIndex = fileContentsRequest->listIndex;
Packit Service 5a9772
Packit Service 5a9772
	if (fileContentsRequest->cbRequested != sizeof(UINT64))
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_Print(clipboard->log, WLOG_WARN,
Packit Service 5a9772
		           "unexpected FILECONTENTS_SIZE request: %" PRIu32 " bytes",
Packit Service 5a9772
		           fileContentsRequest->cbRequested);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_file_range_request(wfClipboard* clipboard,
Packit Service 5a9772
                                      const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
Packit Service 5a9772
{
Packit Service 5a9772
	wClipboardFileRangeRequest request = { 0 };
Packit Service 5a9772
	request.streamId = fileContentsRequest->streamId;
Packit Service 5a9772
	request.listIndex = fileContentsRequest->listIndex;
Packit Service 5a9772
	request.nPositionLow = fileContentsRequest->nPositionLow;
Packit Service 5a9772
	request.nPositionHigh = fileContentsRequest->nPositionHigh;
Packit Service 5a9772
	request.cbRequested = fileContentsRequest->cbRequested;
Packit Service 5a9772
	return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_send_file_contents_failure(CliprdrClientContext* context,
Packit Service 5a9772
                                       const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
Packit Service 5a9772
	response.msgFlags = CB_RESPONSE_FAIL;
Packit Service 5a9772
	response.streamId = fileContentsRequest->streamId;
Packit Service 5a9772
	return context->ClientFileContentsResponse(context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT
Packit Service 5a9772
wlf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
Packit Service 5a9772
                                         const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT error = NO_ERROR;
Packit Service 5a9772
	wfClipboard* clipboard = context->custom;
Packit Service 5a9772
Packit Service 5a9772
	/*
Packit Service 5a9772
	 * MS-RDPECLIP 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST):
Packit Service 5a9772
	 * The FILECONTENTS_SIZE and FILECONTENTS_RANGE flags MUST NOT be set at the same time.
Packit Service 5a9772
	 */
Packit Service 5a9772
	if ((fileContentsRequest->dwFlags & (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) ==
Packit Service 5a9772
	    (FILECONTENTS_SIZE | FILECONTENTS_RANGE))
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_Print(clipboard->log, WLOG_ERROR, "invalid CLIPRDR_FILECONTENTS_REQUEST.dwFlags");
Packit Service 5a9772
		return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (fileContentsRequest->dwFlags & FILECONTENTS_SIZE)
Packit Service 5a9772
		error = wlf_cliprdr_server_file_size_request(clipboard, fileContentsRequest);
Packit Service 5a9772
Packit Service 5a9772
	if (fileContentsRequest->dwFlags & FILECONTENTS_RANGE)
Packit Service 5a9772
		error = wlf_cliprdr_server_file_range_request(clipboard, fileContentsRequest);
Packit Service 5a9772
Packit Service 5a9772
	if (error)
Packit Service 5a9772
	{
Packit Service 5a9772
		WLog_Print(clipboard->log, WLOG_ERROR,
Packit Service 5a9772
		           "failed to handle CLIPRDR_FILECONTENTS_REQUEST: 0x%08X", error);
Packit Service 5a9772
		return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate,
Packit Service 5a9772
                                                    const wClipboardFileSizeRequest* request,
Packit Service 5a9772
                                                    UINT64 fileSize)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
Packit Service 5a9772
	wfClipboard* clipboard = delegate->custom;
Packit Service 5a9772
	response.msgFlags = CB_RESPONSE_OK;
Packit Service 5a9772
	response.streamId = request->streamId;
Packit Service 5a9772
	response.cbRequested = sizeof(UINT64);
Packit Service 5a9772
	response.requestedData = (BYTE*)&fileSize;
Packit Service 5a9772
	return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate,
Packit Service 5a9772
                                                    const wClipboardFileSizeRequest* request,
Packit Service 5a9772
                                                    UINT errorCode)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
Packit Service 5a9772
	wfClipboard* clipboard = delegate->custom;
Packit Service 5a9772
	WINPR_UNUSED(errorCode);
Packit Service 5a9772
	response.msgFlags = CB_RESPONSE_FAIL;
Packit Service 5a9772
	response.streamId = request->streamId;
Packit Service 5a9772
	return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate,
Packit Service 5a9772
                                                     const wClipboardFileRangeRequest* request,
Packit Service 5a9772
                                                     const BYTE* data, UINT32 size)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
Packit Service 5a9772
	wfClipboard* clipboard = delegate->custom;
Packit Service 5a9772
	response.msgFlags = CB_RESPONSE_OK;
Packit Service 5a9772
	response.streamId = request->streamId;
Packit Service 5a9772
	response.cbRequested = size;
Packit Service 5a9772
	response.requestedData = (const BYTE*)data;
Packit Service 5a9772
	return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate,
Packit Service 5a9772
                                                     const wClipboardFileRangeRequest* request,
Packit Service 5a9772
                                                     UINT errorCode)
Packit Service 5a9772
{
Packit Service 5a9772
	CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
Packit Service 5a9772
	wfClipboard* clipboard = delegate->custom;
Packit Service 5a9772
	WINPR_UNUSED(errorCode);
Packit Service 5a9772
	response.msgFlags = CB_RESPONSE_FAIL;
Packit Service 5a9772
	response.streamId = request->streamId;
Packit Service 5a9772
	return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
wfClipboard* wlf_clipboard_new(wlfContext* wfc)
Packit Service 5a9772
{
Packit Service 5a9772
	rdpChannels* channels;
Packit Service 5a9772
	wfClipboard* clipboard;
Packit Service 5a9772
Packit Service 5a9772
	if (!(clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard))))
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	clipboard->wfc = wfc;
Packit Service 5a9772
	channels = wfc->context.channels;
Packit Service 5a9772
	clipboard->log = WLog_Get(TAG);
Packit Service 5a9772
	clipboard->channels = channels;
Packit Service 5a9772
	clipboard->system = ClipboardCreate();
Packit Service 5a9772
	clipboard->delegate = ClipboardGetDelegate(clipboard->system);
Packit Service 5a9772
	clipboard->delegate->custom = clipboard;
Packit Service 5a9772
	/* TODO: set up a filesystem base path for local URI */
Packit Service 5a9772
	/* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */
Packit Service 5a9772
	clipboard->delegate->ClipboardFileSizeSuccess = wlf_cliprdr_clipboard_file_size_success;
Packit Service 5a9772
	clipboard->delegate->ClipboardFileSizeFailure = wlf_cliprdr_clipboard_file_size_failure;
Packit Service 5a9772
	clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success;
Packit Service 5a9772
	clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure;
Packit Service 5a9772
	return clipboard;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
void wlf_clipboard_free(wfClipboard* clipboard)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!clipboard)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	wlf_cliprdr_free_server_formats(clipboard);
Packit Service 5a9772
	wlf_cliprdr_free_client_formats(clipboard);
Packit Service 5a9772
	ClipboardDestroy(clipboard->system);
Packit Service 5a9772
	free(clipboard);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!cliprdr || !clipboard)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	clipboard->context = cliprdr;
Packit Service 5a9772
	cliprdr->custom = (void*)clipboard;
Packit Service 5a9772
	cliprdr->MonitorReady = wlf_cliprdr_monitor_ready;
Packit Service 5a9772
	cliprdr->ServerCapabilities = wlf_cliprdr_server_capabilities;
Packit Service 5a9772
	cliprdr->ServerFormatList = wlf_cliprdr_server_format_list;
Packit Service 5a9772
	cliprdr->ServerFormatListResponse = wlf_cliprdr_server_format_list_response;
Packit Service 5a9772
	cliprdr->ServerFormatDataRequest = wlf_cliprdr_server_format_data_request;
Packit Service 5a9772
	cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response;
Packit Service 5a9772
	cliprdr->ServerFileContentsRequest = wlf_cliprdr_server_file_contents_request;
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
Packit Service 5a9772
{
Packit Service 5a9772
	if (cliprdr)
Packit Service 5a9772
		cliprdr->custom = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (clipboard)
Packit Service 5a9772
		clipboard->context = NULL;
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}