/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { BOOL rawTransfer; xfCliprdrFormat* format = NULL; UINT32 formatId = formatDataRequest->requestedFormatId; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; rawTransfer = xf_cliprdr_is_raw_transfer_available(clipboard); if (rawTransfer) { format = xf_cliprdr_get_client_format_by_id(clipboard, CF_RAW); XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1); } else format = xf_cliprdr_get_client_format_by_id(clipboard, formatId); if (!format) return xf_cliprdr_send_data_response(clipboard, NULL, 0); clipboard->requestedFormatId = rawTransfer ? CF_RAW : formatId; XConvertSelection(xfc->display, clipboard->clipboard_atom, format->atom, clipboard->property_atom, xfc->drawable, CurrentTime); XFlush(xfc->display); /* After this point, we expect a SelectionNotify event from the clipboard owner. */ return CHANNEL_RC_OK; }
static void xf_cliprdr_process_requested_data(xfInfo* xfi, boolean has_data, uint8* data, int size) { uint8* outbuf; clipboardContext* cb = (clipboardContext*) xfi->clipboard_context; if (cb->incr_starts && has_data) return; if (!has_data || data == NULL) { xf_cliprdr_send_null_data_response(xfi); return; } switch (cb->format_mappings[cb->request_index].format_id) { case CB_FORMAT_RAW: case CB_FORMAT_PNG: case CB_FORMAT_JPEG: case CB_FORMAT_GIF: outbuf = xf_cliprdr_process_requested_raw(data, &size); break; case CB_FORMAT_UNICODETEXT: outbuf = xf_cliprdr_process_requested_unicodetext(data, &size); break; case CB_FORMAT_TEXT: outbuf = xf_cliprdr_process_requested_text(data, &size); break; case CB_FORMAT_DIB: outbuf = xf_cliprdr_process_requested_dib(data, &size); break; case CB_FORMAT_HTML: outbuf = xf_cliprdr_process_requested_html(data, &size); break; default: outbuf = NULL; break; } if (outbuf) { xf_cliprdr_send_data_response(xfi, outbuf, size); } else { xf_cliprdr_send_null_data_response(xfi); } /* Resend the format list, otherwise the server won't request again for the next paste */ xf_cliprdr_send_format_list(xfi); }
static int xf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { xfCliprdrFormat* format = NULL; UINT32 formatId = formatDataRequest->requestedFormatId; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; if (xf_cliprdr_is_self_owned(clipboard)) { format = xf_cliprdr_get_format_by_id(clipboard, 0); XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1); } else { format = xf_cliprdr_get_format_by_id(clipboard, formatId); } if (!format) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return 1; } clipboard->requestedFormatId = formatId; XConvertSelection(xfc->display, clipboard->clipboard_atom, format->atom, clipboard->property_atom, xfc->drawable, CurrentTime); XFlush(xfc->display); /* After this point, we expect a SelectionNotify event from the clipboard owner. */ return 1; }
static void xf_cliprdr_send_null_data_response(xfInfo* xfi) { xf_cliprdr_send_data_response(xfi, NULL, 0); }
static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) { Atom type; BYTE* data = NULL; BOOL has_data = FALSE; int format_property; unsigned long dummy; unsigned long length; unsigned long bytes_left; xfCliprdrFormat* format; xfContext* xfc = clipboard->xfc; format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); if (!format || (format->atom != target)) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return FALSE; } XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, 0, 0, target, &type, &format_property, &length, &bytes_left, &data); if (data) { XFree(data); data = NULL; } if (bytes_left <= 0 && !clipboard->incr_starts) { } else if (type == clipboard->incr_atom) { clipboard->incr_starts = TRUE; if (clipboard->incr_data) { free(clipboard->incr_data); clipboard->incr_data = NULL; } clipboard->incr_data_length = 0; has_data = TRUE; /* data will be followed in PropertyNotify event */ } else { if (bytes_left <= 0) { /* INCR finish */ data = clipboard->incr_data; clipboard->incr_data = NULL; bytes_left = clipboard->incr_data_length; clipboard->incr_data_length = 0; clipboard->incr_starts = 0; has_data = TRUE; } else if (XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, bytes_left, 0, target, &type, &format_property, &length, &dummy, &data) == Success) { if (clipboard->incr_starts) { BYTE *new_data; bytes_left = length * format_property / 8; new_data = (BYTE*) realloc(clipboard->incr_data, clipboard->incr_data_length + bytes_left); if (!new_data) return FALSE; clipboard->incr_data = new_data; CopyMemory(clipboard->incr_data + clipboard->incr_data_length, data, bytes_left); clipboard->incr_data_length += bytes_left; XFree(data); data = NULL; } has_data = TRUE; } else { } } XDeleteProperty(xfc->display, xfc->drawable, clipboard->property_atom); xf_cliprdr_process_requested_data(clipboard, has_data, data, (int) bytes_left); if (data) XFree(data); return TRUE; }
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) { BOOL bSuccess; UINT32 SrcSize; UINT32 DstSize; UINT32 formatId; UINT32 altFormatId; BYTE* pSrcData = NULL; BYTE* pDstData = NULL; xfCliprdrFormat* format; if (clipboard->incr_starts && hasData) return; format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } formatId = 0; altFormatId = 0; switch (format->formatId) { case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: size = strlen((char*) data) + 1; formatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; case CF_DIB: formatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: size = strlen((char*) data) + 1; formatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; } SrcSize = (UINT32) size; pSrcData = (BYTE*) malloc(SrcSize); if (!pSrcData) return; CopyMemory(pSrcData, data, SrcSize); bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); if (!bSuccess) free(pSrcData); altFormatId = clipboard->requestedFormatId; if (bSuccess && altFormatId) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); } if (!pDstData) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); free(pDstData); }
static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) { BOOL bSuccess; UINT32 SrcSize; UINT32 DstSize; UINT32 srcFormatId; UINT32 dstFormatId; BYTE* pDstData = NULL; xfCliprdrFormat* format; if (clipboard->incr_starts && hasData) return; format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } srcFormatId = 0; switch (format->formatId) { case CF_RAW: srcFormatId = CF_RAW; break; case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: size = strlen((char*) data) + 1; srcFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; case CF_DIB: srcFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; case CB_FORMAT_TEXTURILIST: srcFormatId = ClipboardGetFormatId(clipboard->system, "text/uri-list"); break; } SrcSize = (UINT32) size; bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); if (format->formatName) dstFormatId = ClipboardGetFormatId(clipboard->system, format->formatName); else dstFormatId = format->formatId; if (bSuccess) { DstSize = 0; pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); } if (!pDstData) { xf_cliprdr_send_data_response(clipboard, NULL, 0); return; } /* * File lists require a bit of postprocessing to convert them from WinPR's FILDESCRIPTOR * format to CLIPRDR_FILELIST expected by the server. * * We check for "FileGroupDescriptorW" format being registered (i.e., nonzero) in order * to not process CF_RAW as a file list in case WinPR does not support file transfers. */ if (dstFormatId && (dstFormatId == ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW"))) { UINT error = NO_ERROR; FILEDESCRIPTOR* file_array = (FILEDESCRIPTOR*) pDstData; UINT32 file_count = DstSize / sizeof(FILEDESCRIPTOR); pDstData = NULL; DstSize = 0; error = cliprdr_serialize_file_list(file_array, file_count, &pDstData, &DstSize); if (error) WLog_ERR(TAG, "failed to serialize CLIPRDR_FILELIST: 0x%08X", error); free(file_array); } xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); free(pDstData); }