diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c index 282eb9ad6..68362ae3c 100644 --- a/client/Wayland/wlf_cliprdr.c +++ b/client/Wayland/wlf_cliprdr.c @@ -851,6 +851,8 @@ wfClipboard* wlf_clipboard_new(wlfContext* wfc) clipboard->system = ClipboardCreate(); clipboard->delegate = ClipboardGetDelegate(clipboard->system); clipboard->delegate->custom = clipboard; + /* TODO: set up a filesystem base path for local URI */ + /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ clipboard->delegate->ClipboardFileSizeSuccess = wlf_cliprdr_clipboard_file_size_success; clipboard->delegate->ClipboardFileSizeFailure = wlf_cliprdr_clipboard_file_size_failure; clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success; diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 004d1312f..0f2881375 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -1380,6 +1380,13 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* dstFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); nullTerminated = TRUE; } + + if (strcmp(clipboard->data_format_name, "FileGroupDescriptorW") == 0) + { + srcFormatId = ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW"); + dstFormatId = ClipboardGetFormatId(clipboard->system, "text/uri-list"); + nullTerminated = FALSE; + } } else { @@ -1429,10 +1436,10 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* if (!pDstData) { - WLog_ERR(TAG, "failed to get clipboard data in format %s [source format %s]", - ClipboardGetFormatName(clipboard->system, dstFormatId), - ClipboardGetFormatName(clipboard->system, srcFormatId)); - return ERROR_INTERNAL_ERROR; + WLog_WARN(TAG, "failed to get clipboard data in format %s [source format %s]", + ClipboardGetFormatName(clipboard->system, dstFormatId), + ClipboardGetFormatName(clipboard->system, srcFormatId)); + return CHANNEL_RC_OK; } if (nullTerminated) @@ -1704,6 +1711,8 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); clipboard->delegate = ClipboardGetDelegate(clipboard->system); clipboard->delegate->custom = clipboard; + /* TODO: set up a filesystem base path for local URI */ + /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ clipboard->delegate->ClipboardFileSizeSuccess = xf_cliprdr_clipboard_file_size_success; clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure; clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success; diff --git a/winpr/include/winpr/clipboard.h b/winpr/include/winpr/clipboard.h index c1c84d71b..b1e7a40f4 100644 --- a/winpr/include/winpr/clipboard.h +++ b/winpr/include/winpr/clipboard.h @@ -25,7 +25,8 @@ typedef struct _wClipboard wClipboard; -typedef void* (*CLIPBOARD_SYNTHESIZE_FN)(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32* pSize); +typedef void* (*CLIPBOARD_SYNTHESIZE_FN)(wClipboard* clipboard, UINT32 formatId, const void* data, + UINT32* pSize); struct _wClipboardFileSizeRequest { @@ -50,18 +51,19 @@ struct _wClipboardDelegate { wClipboard* clipboard; void* custom; + char* basePath; - UINT (*ClientRequestFileSize)(wClipboardDelegate*, const wClipboardFileSizeRequest*); - UINT (*ClipboardFileSizeSuccess)(wClipboardDelegate*, const wClipboardFileSizeRequest*, - UINT64 fileSize); - UINT (*ClipboardFileSizeFailure)(wClipboardDelegate*, const wClipboardFileSizeRequest*, - UINT errorCode); + UINT(*ClientRequestFileSize)(wClipboardDelegate*, const wClipboardFileSizeRequest*); + UINT(*ClipboardFileSizeSuccess)(wClipboardDelegate*, const wClipboardFileSizeRequest*, + UINT64 fileSize); + UINT(*ClipboardFileSizeFailure)(wClipboardDelegate*, const wClipboardFileSizeRequest*, + UINT errorCode); - UINT (*ClientRequestFileRange)(wClipboardDelegate*, const wClipboardFileRangeRequest*); - UINT (*ClipboardFileRangeSuccess)(wClipboardDelegate*, const wClipboardFileRangeRequest*, - const BYTE* data, UINT32 size); - UINT (*ClipboardFileRangeFailure)(wClipboardDelegate*, const wClipboardFileRangeRequest*, - UINT errorCode); + UINT(*ClientRequestFileRange)(wClipboardDelegate*, const wClipboardFileRangeRequest*); + UINT(*ClipboardFileRangeSuccess)(wClipboardDelegate*, const wClipboardFileRangeRequest*, + const BYTE* data, UINT32 size); + UINT(*ClipboardFileRangeFailure)(wClipboardDelegate*, const wClipboardFileRangeRequest*, + UINT errorCode); }; #ifdef __cplusplus @@ -80,19 +82,20 @@ WINPR_API UINT32 ClipboardGetRegisteredFormatIds(wClipboard* clipboard, UINT32** WINPR_API UINT32 ClipboardRegisterFormat(wClipboard* clipboard, const char* name); WINPR_API BOOL ClipboardRegisterSynthesizer(wClipboard* clipboard, UINT32 formatId, - UINT32 syntheticId, CLIPBOARD_SYNTHESIZE_FN pfnSynthesize); + UINT32 syntheticId, CLIPBOARD_SYNTHESIZE_FN pfnSynthesize); WINPR_API UINT32 ClipboardGetFormatId(wClipboard* clipboard, const char* name); WINPR_API const char* ClipboardGetFormatName(wClipboard* clipboard, UINT32 formatId); WINPR_API void* ClipboardGetData(wClipboard* clipboard, UINT32 formatId, UINT32* pSize); -WINPR_API BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, UINT32 size); +WINPR_API BOOL ClipboardSetData(wClipboard* clipboard, UINT32 formatId, const void* data, + UINT32 size); WINPR_API UINT64 ClipboardGetOwner(wClipboard* clipboard); WINPR_API void ClipboardSetOwner(wClipboard* clipboard, UINT64 ownerId); WINPR_API wClipboardDelegate* ClipboardGetDelegate(wClipboard* clipboard); -WINPR_API wClipboard* ClipboardCreate(); +WINPR_API wClipboard* ClipboardCreate(void); WINPR_API void ClipboardDestroy(wClipboard* clipboard); #ifdef __cplusplus diff --git a/winpr/libwinpr/clipboard/clipboard.c b/winpr/libwinpr/clipboard/clipboard.c index 3d945bcd5..044ef70b2 100644 --- a/winpr/libwinpr/clipboard/clipboard.c +++ b/winpr/libwinpr/clipboard/clipboard.c @@ -373,6 +373,7 @@ BOOL ClipboardInitFormats(wClipboard* clipboard) ZeroMemory(format, sizeof(wClipboardFormat)); format->formatId = formatId; format->formatName = _strdup(CF_STANDARD_STRINGS[formatId]); + if (!format->formatName) goto error; } @@ -381,13 +382,14 @@ BOOL ClipboardInitFormats(wClipboard* clipboard) goto error; return TRUE; - error: + for (formatId = 0; formatId < clipboard->numFormats; formatId++) { free(clipboard->formats[formatId].formatName); free(clipboard->formats[formatId].synthesizers); } + return FALSE; } @@ -522,13 +524,12 @@ wClipboardDelegate* ClipboardGetDelegate(wClipboard* clipboard) return &clipboard->delegate; } -void ClipboardInitLocalFileSubsystem(wClipboard* clipboard) +static void ClipboardInitLocalFileSubsystem(wClipboard* clipboard) { /* * There can be only one local file subsystem active. * Return as soon as initialization succeeds. */ - #ifdef WITH_WCLIPBOARD_POSIX if (ClipboardInitPosixFileSubsystem(clipboard)) { @@ -539,16 +540,16 @@ void ClipboardInitLocalFileSubsystem(wClipboard* clipboard) { WLog_WARN(TAG, "failed to initialize POSIX local file subsystem"); } -#endif +#endif WLog_INFO(TAG, "failed to initialize local file subsystem, file transfer not available"); } -wClipboard* ClipboardCreate() +wClipboard* ClipboardCreate(void) { wClipboard* clipboard; - clipboard = (wClipboard*) calloc(1, sizeof(wClipboard)); + if (!clipboard) return NULL; @@ -560,9 +561,9 @@ wClipboard* ClipboardCreate() clipboard->numFormats = 0; clipboard->maxFormats = 64; - clipboard->formats = (wClipboardFormat*) - calloc(clipboard->maxFormats, sizeof(wClipboardFormat)); + calloc(clipboard->maxFormats, sizeof(wClipboardFormat)); + if (!clipboard->formats) goto error_free_lock; @@ -570,11 +571,8 @@ wClipboard* ClipboardCreate() goto error_free_formats; clipboard->delegate.clipboard = clipboard; - ClipboardInitLocalFileSubsystem(clipboard); - return clipboard; - error_free_formats: free(clipboard->formats); error_free_lock: diff --git a/winpr/libwinpr/clipboard/posix.c b/winpr/libwinpr/clipboard/posix.c index 627af2ec3..d52d4096b 100644 --- a/winpr/libwinpr/clipboard/posix.c +++ b/winpr/libwinpr/clipboard/posix.c @@ -573,6 +573,71 @@ static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 f return descriptors; } +static void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId, + const void* data, UINT32* pSize) +{ + const FILEDESCRIPTOR* descriptors; + UINT32 nrDescriptors; + size_t count, x, alloc, pos, baseLength = 0; + const char* src = (const char*) data; + char* dst; + + if (!clipboard || !data || !pSize) + return NULL; + + if (*pSize < sizeof(UINT32)) + return NULL; + + if (clipboard->delegate.basePath) + baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH); + + if (baseLength < 1) + return NULL; + + if (clipboard->delegate.ClientRequestFileSize) + nrDescriptors = (UINT32)(src[3] << 24) | (UINT32)(src[2] << 16) | (UINT32)(src[1] << 8) | + (src[0] & 0xFF); + + count = (*pSize - 4) / sizeof(FILEDESCRIPTOR); + + if ((count < 1) || (count != nrDescriptors)) + return NULL; + + descriptors = (const FILEDESCRIPTOR*)&src[4]; + + if (formatId != ClipboardGetFormatId(clipboard, "FileGroupDescriptorW")) + return NULL; + + alloc = 0; + + /* Get total size of file names */ + for (x = 0; x < count; x++) + alloc += _wcsnlen(descriptors[x].cFileName, ARRAYSIZE(descriptors[x].cFileName)); + + /* Append a prefix file:// and postfix \r\n for each file */ + alloc += (sizeof("/\r\n") + baseLength) * count; + dst = calloc(alloc, sizeof(char)); + + if (!dst) + return NULL; + + pos = 0; + + for (x = 0; x < count; x++) + { + const FILEDESCRIPTOR* cur = &descriptors[x]; + size_t curLen = _wcsnlen(cur->cFileName, ARRAYSIZE(cur->cFileName)); + char* curName = NULL; + ConvertFromUnicode(CP_UTF8, 0, cur->cFileName, curLen, &curName, 0, NULL, NULL); + pos += _snprintf(&dst[pos], alloc - pos, "%s/%s\r\n", clipboard->delegate.basePath, curName); + free(curName); + } + + *pSize = alloc; + clipboard->fileListSequenceNumber = clipboard->sequenceNumber; + return dst; +} + static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard) { UINT32 file_group_format_id; @@ -595,6 +660,11 @@ static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard) convert_uri_list_to_filedescriptors)) goto error_free_local_files; + if (!ClipboardRegisterSynthesizer(clipboard, + file_group_format_id, local_file_format_id, + convert_filedescriptors_to_uri_list)) + goto error_free_local_files; + return TRUE; error_free_local_files: ArrayList_Free(clipboard->localFiles);