diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 2ec90b602..3d6b18da7 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -111,7 +111,7 @@ void cliprdr_print_general_capability_flags(UINT32 flags) WLog_INFO(TAG, "}"); } -static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s) +static int cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s) { UINT32 version; UINT32 generalFlags; @@ -159,9 +159,11 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* caps_event->capabilities = generalFlags; svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) caps_event); } + + return 1; } -static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) +static int cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) { int i; UINT16 lengthCapability; @@ -187,6 +189,8 @@ static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 break; } } + + return 1; } static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr) @@ -210,7 +214,7 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr) cliprdr_packet_send(cliprdr, s); } -static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) +static int cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) { CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -236,74 +240,178 @@ static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UI event = (RDP_CB_MONITOR_READY_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) event); } + + return 1; } -static void cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) +static int cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { - RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event; + CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest"); - cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FilecontentsRequest, NULL, NULL); + if (context->custom) + { + CLIPRDR_FILE_CONTENTS_REQUEST request; - Stream_Read_UINT32(s, cb_event->streamId); - Stream_Read_UINT32(s, cb_event->lindex); - Stream_Read_UINT32(s, cb_event->dwFlags); - Stream_Read_UINT32(s, cb_event->nPositionLow); - Stream_Read_UINT32(s, cb_event->nPositionHigh); - Stream_Read_UINT32(s, cb_event->cbRequested); - //Stream_Read_UINT32(s, cb_event->clipDataId); - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + if (Stream_GetRemainingLength(s) < 28) + return -1; + + request.msgType = CB_FILECONTENTS_REQUEST; + request.msgFlags = flags; + request.dataLen = length; + + Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ + Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ + Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ + Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ + Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ + + if (context->ServerFileContentsRequest) + context->ServerFileContentsRequest(context, &request); + } + else + { + RDP_CB_FILECONTENTS_REQUEST_EVENT* cb_event; + + cb_event = (RDP_CB_FILECONTENTS_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_FilecontentsRequest, NULL, NULL); + + Stream_Read_UINT32(s, cb_event->streamId); + Stream_Read_UINT32(s, cb_event->lindex); + Stream_Read_UINT32(s, cb_event->dwFlags); + Stream_Read_UINT32(s, cb_event->nPositionLow); + Stream_Read_UINT32(s, cb_event->nPositionHigh); + Stream_Read_UINT32(s, cb_event->cbRequested); + //Stream_Read_UINT32(s, cb_event->clipDataId); + + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + } + + return 1; } -static void cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) +static int cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { - RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event; + CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse"); - cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_FilecontentsResponse, NULL, NULL); - - Stream_Read_UINT32(s, cb_event->streamId); - - if (length > 0) + if (context->custom) { - cb_event->size = length - 4; - cb_event->data = (BYTE*) malloc(cb_event->size); - CopyMemory(cb_event->data, Stream_Pointer(s), cb_event->size); + CLIPRDR_FILE_CONTENTS_RESPONSE response; + + if (Stream_GetRemainingLength(s) < 4) + return -1; + + response.msgType = CB_FILECONTENTS_RESPONSE; + response.msgFlags = flags; + response.dataLen = length; + + Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ + + response.cbRequested = length - 4; + response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + + if (context->ServerFileContentsResponse) + context->ServerFileContentsResponse(context, &response); + } + else + { + RDP_CB_FILECONTENTS_RESPONSE_EVENT* cb_event; + + cb_event = (RDP_CB_FILECONTENTS_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_FilecontentsResponse, NULL, NULL); + + Stream_Read_UINT32(s, cb_event->streamId); + + if (length > 0) + { + cb_event->size = length - 4; + cb_event->data = (BYTE*) malloc(cb_event->size); + CopyMemory(cb_event->data, Stream_Pointer(s), cb_event->size); + } + + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); } - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + return 1; } -static void cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) +static int cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { - RDP_CB_LOCK_CLIPDATA_EVENT* cb_event; + CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData"); - cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_LockClipdata, NULL, NULL); + if (context->custom) + { + CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData; - Stream_Read_UINT32(s, cb_event->clipDataId); + if (Stream_GetRemainingLength(s) < 4) + return -1; - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + lockClipboardData.msgType = CB_LOCK_CLIPDATA; + lockClipboardData.msgFlags = flags; + lockClipboardData.dataLen = length; + + Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */ + + if (context->ServerLockClipboardData) + context->ServerLockClipboardData(context, &lockClipboardData); + } + else + { + RDP_CB_LOCK_CLIPDATA_EVENT* cb_event; + + cb_event = (RDP_CB_LOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_LockClipdata, NULL, NULL); + + Stream_Read_UINT32(s, cb_event->clipDataId); + + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + } + + return 1; } -static void cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) +static int cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, UINT16 flags) { - RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event; + CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData"); - cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, - CliprdrChannel_UnLockClipdata, NULL, NULL); + if (context->custom) + { + CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; - Stream_Read_UINT32(s, cb_event->clipDataId); + if (Stream_GetRemainingLength(s) < 4) + return -1; - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; + unlockClipboardData.msgFlags = flags; + unlockClipboardData.dataLen = length; + + Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ + + if (context->ServerUnlockClipboardData) + context->ServerUnlockClipboardData(context, &unlockClipboardData); + } + else + { + RDP_CB_UNLOCK_CLIPDATA_EVENT* cb_event; + + cb_event = (RDP_CB_UNLOCK_CLIPDATA_EVENT*) freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_UnLockClipdata, NULL, NULL); + + Stream_Read_UINT32(s, cb_event->clipDataId); + + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage*) cb_event); + } + + return 1; } static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) @@ -490,6 +598,36 @@ int cliprdr_client_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILIT return 0; } +int cliprdr_temp_directory(CliprdrClientContext* context, CLIPRDR_TEMP_DIRECTORY* tempDirectory) +{ + int length; + wStream* s; + WCHAR* wszTempDir = NULL; + cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + + s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 520 * 2); + + length = ConvertToUnicode(CP_UTF8, 0, tempDirectory->szTempDir, -1, &wszTempDir, 0); + + if (length < 0) + return -1; + + if (length > 520) + length = 520; + + Stream_Write(s, tempDirectory->szTempDir, length * 2); + Stream_Zero(s, (520 - length) * 2); + + free(wszTempDir); + + WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s", + tempDirectory->szTempDir); + + cliprdr_packet_send(cliprdr, s); + + return 1; +} + int cliprdr_client_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList) { wStream* s; @@ -557,6 +695,40 @@ int cliprdr_client_format_list_response(CliprdrClientContext* context, CLIPRDR_F return 0; } +int cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + wStream* s; + cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + + s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); + + Stream_Write_UINT32(s, lockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientLockClipboardData: clipDataId: 0x%04X", + lockClipboardData->clipDataId); + + cliprdr_packet_send(cliprdr, s); + + return 1; +} + +int cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + wStream* s; + cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + + s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); + + Stream_Write_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientUnlockClipboardData: clipDataId: 0x%04X", + unlockClipboardData->clipDataId); + + cliprdr_packet_send(cliprdr, s); + + return 1; +} + int cliprdr_client_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { wStream* s; @@ -592,6 +764,58 @@ int cliprdr_client_format_data_response(CliprdrClientContext* context, CLIPRDR_F return 0; } +int cliprdr_client_file_contents_request(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + wStream* s; + cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + + s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 28); + + Stream_Write_UINT32(s, fileContentsRequest->streamId); /* streamId (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->listIndex); /* listIndex (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->dwFlags); /* dwFlags (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->cbRequested); /* cbRequested (4 bytes) */ + Stream_Write_UINT32(s, fileContentsRequest->clipDataId); /* clipDataId (4 bytes) */ + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsRequest: streamId: 0x%04X", + fileContentsRequest->streamId); + + cliprdr_packet_send(cliprdr, s); + + return 1; +} + +int cliprdr_client_file_contents_response(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +{ + wStream* s; + cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + + if (fileContentsResponse->dwFlags & FILECONTENTS_SIZE) + fileContentsResponse->cbRequested = sizeof(UINT64); + + s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, + 4 + fileContentsResponse->cbRequested); + + Stream_Write_UINT32(s, fileContentsResponse->streamId); /* streamId (4 bytes) */ + + /** + * requestedFileContentsData: + * FILECONTENTS_SIZE: file size as UINT64 + * FILECONTENTS_RANGE: file data from requested range + */ + + Stream_Write(s, fileContentsResponse->requestedData, fileContentsResponse->cbRequested); + + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsResponse: streamId: 0x%04X", + fileContentsResponse->streamId); + + cliprdr_packet_send(cliprdr, s); + + return 1; +} + /* cliprdr is always built-in */ #define VirtualChannelEntry cliprdr_VirtualChannelEntry @@ -626,10 +850,15 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) context = (CliprdrClientContext*) calloc(1, sizeof(CliprdrClientContext)); context->handle = (void*) cliprdr; context->ClientCapabilities = cliprdr_client_capabilities; + context->TempDirectory = cliprdr_temp_directory; context->ClientFormatList = cliprdr_client_format_list; context->ClientFormatListResponse = cliprdr_client_format_list_response; + context->ClientLockClipboardData = cliprdr_client_lock_clipboard_data; + context->ClientUnlockClipboardData = cliprdr_client_unlock_clipboard_data; context->ClientFormatDataRequest = cliprdr_client_format_data_request; context->ClientFormatDataResponse = cliprdr_client_format_data_response; + context->ClientFileContentsRequest = cliprdr_client_file_contents_request; + context->ClientFileContentsResponse = cliprdr_client_file_contents_response; *(pEntryPointsEx->ppInterface) = (void*) context; } diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c index 555481869..aa16bf5a1 100644 --- a/client/Windows/wf_cliprdr.c +++ b/client/Windows/wf_cliprdr.c @@ -107,9 +107,6 @@ ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream* This) } } -#define FILECONTENTS_SIZE 0x00000001 -#define FILECONTENTS_RANGE 0x00000002 - HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void *pv, ULONG cb, ULONG *pcbRead) { int ret; @@ -1215,7 +1212,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM case WM_CLIPBOARDUPDATE: DEBUG_CLIPRDR("info: %s - WM_CLIPBOARDUPDATE", __FUNCTION__); - if (clipboard->channel_initialized) + if (clipboard->sync) { if ((GetClipboardOwner() != clipboard->hwnd) && (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj))) @@ -1407,14 +1404,7 @@ static void wf_cliprdr_process_cb_clip_caps_event(wfClipboard* clipboard, RDP_CB static void wf_cliprdr_process_cb_monitor_ready_event(wfClipboard* clipboard, RDP_CB_MONITOR_READY_EVENT* ready_event) { -#if 0 - /*Disabled since the current function only sends the temp directory which is not - guaranteed to be accessible to the server - */ - cliprdr_send_tempdir(clipboard); -#endif - clipboard->channel_initialized = TRUE; - + clipboard->sync = TRUE; cliprdr_send_format_list(clipboard); } @@ -2143,18 +2133,88 @@ void wf_process_cliprdr_event(wfContext* wfc, wMessage* event) static int wf_cliprdr_monitor_ready(CliprdrClientContext* context, CLIPRDR_MONITOR_READY* monitorReady) { wfClipboard* clipboard = (wfClipboard*) context->custom; + + clipboard->sync = TRUE; + cliprdr_send_format_list(clipboard); + return 1; } static int wf_cliprdr_server_capabilities(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities) { + UINT32 index; + CLIPRDR_CAPABILITY_SET* capabilitySet; wfClipboard* clipboard = (wfClipboard*) context->custom; + + for (index = 0; index < capabilities->cCapabilitiesSets; index++) + { + capabilitySet = &(capabilities->capabilitySets[index]); + + if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && + (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) + { + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet + = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; + + clipboard->capabilities = generalCapabilitySet->generalFlags; + break; + } + } + return 1; } static int wf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList) { + UINT32 i, j; + formatMapping* mapping; + CLIPRDR_FORMAT* format; wfClipboard* clipboard = (wfClipboard*) context->custom; + + clear_format_map(clipboard); + + for (i = j = 0; i < formatList->numFormats; i++) + { + format = &(formatList->formats[i]); + mapping = &(clipboard->format_mappings[j++]); + + mapping->remote_format_id = format->formatId; + + if (format->formatName) + { + mapping->name = _strdup(format->formatName); + mapping->local_format_id = RegisterClipboardFormatA((LPCSTR) mapping->name); + } + else + { + mapping->name = NULL; + mapping->local_format_id = mapping->remote_format_id; + } + + clipboard->map_size++; + map_ensure_capacity(clipboard); + } + + if (file_transferring(clipboard)) + { + PostMessage(clipboard->hwnd, WM_CLIPRDR_MESSAGE, OLE_SETCLIPBOARD, 0); + } + else + { + if (!OpenClipboard(clipboard->hwnd)) + return -1; + + if (EmptyClipboard()) + { + for (i = 0; i < (UINT32) clipboard->map_size; i++) + { + SetClipboardData(clipboard->format_mappings[i].local_format_id, NULL); + } + } + + CloseClipboard(); + } + return 1; } @@ -2164,13 +2224,238 @@ static int wf_cliprdr_server_format_list_response(CliprdrClientContext* context, return 1; } -static int wf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +int wf_cliprdr_server_lock_clipboard_data(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { wfClipboard* clipboard = (wfClipboard*) context->custom; return 1; } +int wf_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + wfClipboard* clipboard = (wfClipboard*) context->custom; + return 1; +} + +static int wf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +{ + int size = 0; + char* buff = NULL; + char* globlemem = NULL; + HANDLE hClipdata = NULL; + UINT32 requestedFormatId; + CLIPRDR_FORMAT_DATA_RESPONSE response; + wfClipboard* clipboard = (wfClipboard*) context->custom; + + requestedFormatId = formatDataRequest->requestedFormatId; + + if (requestedFormatId == RegisterClipboardFormatW(_T("FileGroupDescriptorW"))) + { + int len; + int i; + WCHAR* wFileName; + unsigned int uSize; + HRESULT result; + LPDATAOBJECT dataObj; + FORMATETC format_etc; + STGMEDIUM stg_medium; + DROPFILES* dropFiles; + + result = OleGetClipboard(&dataObj); + + if (!SUCCEEDED(result)) + return -1; + + ZeroMemory(&format_etc, sizeof(FORMATETC)); + ZeroMemory(&stg_medium, sizeof(STGMEDIUM)); + + /* try to get FileGroupDescriptorW struct from OLE */ + format_etc.cfFormat = requestedFormatId; + format_etc.tymed = TYMED_HGLOBAL; + format_etc.dwAspect = 1; + format_etc.lindex = -1; + format_etc.ptd = 0; + + result = IDataObject_GetData(dataObj, &format_etc, &stg_medium); + + if (SUCCEEDED(result)) + { + DEBUG_CLIPRDR("Got FileGroupDescriptorW."); + globlemem = (char*) GlobalLock(stg_medium.hGlobal); + uSize = GlobalSize(stg_medium.hGlobal); + size = uSize; + buff = (char*) malloc(uSize); + CopyMemory(buff, globlemem, uSize); + GlobalUnlock(stg_medium.hGlobal); + + ReleaseStgMedium(&stg_medium); + + clear_file_array(clipboard); + } + else + { + /* get DROPFILES struct from OLE */ + format_etc.cfFormat = CF_HDROP; + format_etc.tymed = TYMED_HGLOBAL; + format_etc.dwAspect = 1; + format_etc.lindex = -1; + + result = IDataObject_GetData(dataObj, &format_etc, &stg_medium); + + if (!SUCCEEDED(result)) { + DEBUG_CLIPRDR("dataObj->GetData failed."); + } + + globlemem = (char*) GlobalLock(stg_medium.hGlobal); + + if (!globlemem) + { + GlobalUnlock(stg_medium.hGlobal); + + ReleaseStgMedium(&stg_medium); + clipboard->nFiles = 0; + + goto exit; + } + uSize = GlobalSize(stg_medium.hGlobal); + + dropFiles = (DROPFILES*) malloc(uSize); + memcpy(dropFiles, globlemem, uSize); + + GlobalUnlock(stg_medium.hGlobal); + + ReleaseStgMedium(&stg_medium); + + clear_file_array(clipboard); + + if (dropFiles->fWide) + { + WCHAR* p; + int str_len; + int offset; + int pathLen; + + /* dropFiles contains file names */ + for (wFileName = (WCHAR*)((char*)dropFiles + dropFiles->pFiles); (len = wcslen(wFileName)) > 0; wFileName += len + 1) + { + /* get path name */ + str_len = wcslen(wFileName); + offset = str_len; + /* find the last '\' in full file name */ + for (p = wFileName + offset; *p != L'\\'; p--) + { + ; + } + p += 1; + pathLen = wcslen(wFileName) - wcslen(p); + + wf_cliprdr_add_to_file_arrays(clipboard, wFileName, pathLen); + + if ((clipboard->fileDescriptor[clipboard->nFiles - 1]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + /* this is a directory */ + wf_cliprdr_traverse_directory(clipboard, wFileName, pathLen); + } + } + } + else + { + char* p; + + for (p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0; p += len + 1, clipboard->nFiles++) + { + int cchWideChar; + + cchWideChar = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, NULL, 0); + clipboard->file_names[clipboard->nFiles] = (LPWSTR) malloc(cchWideChar * 2); + MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, clipboard->file_names[clipboard->nFiles], cchWideChar); + + if (clipboard->nFiles == clipboard->file_array_size) + { + clipboard->file_array_size *= 2; + clipboard->fileDescriptor = (FILEDESCRIPTORW**) realloc(clipboard->fileDescriptor, clipboard->file_array_size * sizeof(FILEDESCRIPTORW*)); + clipboard->file_names = (WCHAR**) realloc(clipboard->file_names, clipboard->file_array_size * sizeof(WCHAR*)); + } + } + } + +exit: + size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); + buff = (char*) malloc(size); + + *((UINT32*) buff) = clipboard->nFiles; + + for (i = 0; i < clipboard->nFiles; i++) + { + if (clipboard->fileDescriptor[i]) + { + memcpy(buff + 4 + i * sizeof(FILEDESCRIPTORW), clipboard->fileDescriptor[i], sizeof(FILEDESCRIPTORW)); + } + } + } + + IDataObject_Release(dataObj); + } + else + { + if (!OpenClipboard(clipboard->hwnd)) + return -1; + + hClipdata = GetClipboardData(requestedFormatId); + + if (!hClipdata) + { + CloseClipboard(); + return -1; + } + + globlemem = (char*) GlobalLock(hClipdata); + size = (int) GlobalSize(hClipdata); + + buff = (char*) malloc(size); + CopyMemory(buff, globlemem, size); + + GlobalUnlock(hClipdata); + + CloseClipboard(); + } + + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); + + response.msgFlags = CB_RESPONSE_OK; + response.dataLen = size; + response.requestedFormatData = (BYTE*) buff; + + clipboard->context->ClientFormatDataResponse(clipboard->context, &response); + + free(buff); + + return 1; +} + static int wf_cliprdr_server_format_data_response(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +{ + BYTE* data; + HANDLE hMem; + wfClipboard* clipboard = (wfClipboard*) context->custom; + + hMem = GlobalAlloc(GMEM_FIXED, formatDataResponse->dataLen); + data = (BYTE*) GlobalLock(hMem); + CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); + GlobalUnlock(hMem); + + clipboard->hmem = hMem; + SetEvent(clipboard->response_data_event); + + return 1; +} + +int wf_cliprdr_server_file_contents_request(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + wfClipboard* clipboard = (wfClipboard*) context->custom; + return 1; +} + +int wf_cliprdr_server_file_contents_response(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { wfClipboard* clipboard = (wfClipboard*) context->custom; return 1; @@ -2188,6 +2473,7 @@ void wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr) clipboard = wfc->clipboard; clipboard->wfc = wfc; + clipboard->context = cliprdr; if (0) { @@ -2197,12 +2483,16 @@ void wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr) cliprdr->ServerCapabilities = wf_cliprdr_server_capabilities; cliprdr->ServerFormatList = wf_cliprdr_server_format_list; cliprdr->ServerFormatListResponse = wf_cliprdr_server_format_list_response; + cliprdr->ServerLockClipboardData = wf_cliprdr_server_lock_clipboard_data; + cliprdr->ServerUnlockClipboardData = wf_cliprdr_server_unlock_clipboard_data; cliprdr->ServerFormatDataRequest = wf_cliprdr_server_format_data_request; cliprdr->ServerFormatDataResponse = wf_cliprdr_server_format_data_response; + cliprdr->ServerFileContentsRequest = wf_cliprdr_server_file_contents_request; + cliprdr->ServerFileContentsResponse = wf_cliprdr_server_file_contents_response; } clipboard->channels = context->channels; - clipboard->channel_initialized = FALSE; + clipboard->sync = FALSE; clipboard->map_capacity = 32; clipboard->map_size = 0; diff --git a/client/Windows/wf_cliprdr.h b/client/Windows/wf_cliprdr.h index 3e9589318..9c9d9f982 100644 --- a/client/Windows/wf_cliprdr.h +++ b/client/Windows/wf_cliprdr.h @@ -95,7 +95,9 @@ struct wf_clipboard { wfContext* wfc; rdpChannels* channels; + CliprdrClientContext* context; + BOOL sync; UINT32 capabilities; int map_size; @@ -103,7 +105,6 @@ struct wf_clipboard formatMapping* format_mappings; UINT32 request_format; - BOOL channel_initialized; HWND hwnd; HANDLE hmem; diff --git a/include/freerdp/channels/cliprdr.h b/include/freerdp/channels/cliprdr.h index 3013e8319..22b9fa87d 100644 --- a/include/freerdp/channels/cliprdr.h +++ b/include/freerdp/channels/cliprdr.h @@ -68,6 +68,10 @@ #define CB_FILECLIP_NO_FILE_PATHS 0x00000008 #define CB_CAN_LOCK_CLIPDATA 0x00000010 +/* File Contents Request Flags */ +#define FILECONTENTS_SIZE 0x00000001 +#define FILECONTENTS_RANGE 0x00000002 + #define DEFINE_CLIPRDR_HEADER_COMMON() \ UINT16 msgType; \ UINT16 msgFlags; \ @@ -111,6 +115,14 @@ struct _CLIPRDR_MONITOR_READY }; typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY; +struct _CLIPRDR_TEMP_DIRECTORY +{ + DEFINE_CLIPRDR_HEADER_COMMON(); + + char szTempDir[520]; +}; +typedef struct _CLIPRDR_TEMP_DIRECTORY CLIPRDR_TEMP_DIRECTORY; + struct _CLIPRDR_FORMAT { UINT32 formatId; @@ -133,6 +145,22 @@ struct _CLIPRDR_FORMAT_LIST_RESPONSE }; typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE; +struct _CLIPRDR_LOCK_CLIPBOARD_DATA +{ + DEFINE_CLIPRDR_HEADER_COMMON(); + + UINT32 clipDataId; +}; +typedef struct _CLIPRDR_LOCK_CLIPBOARD_DATA CLIPRDR_LOCK_CLIPBOARD_DATA; + +struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA +{ + DEFINE_CLIPRDR_HEADER_COMMON(); + + UINT32 clipDataId; +}; +typedef struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA CLIPRDR_UNLOCK_CLIPBOARD_DATA; + struct _CLIPRDR_FORMAT_DATA_REQUEST { DEFINE_CLIPRDR_HEADER_COMMON(); @@ -149,5 +177,30 @@ struct _CLIPRDR_FORMAT_DATA_RESPONSE }; typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE; +struct _CLIPRDR_FILE_CONTENTS_REQUEST +{ + DEFINE_CLIPRDR_HEADER_COMMON(); + + UINT32 streamId; + UINT32 listIndex; + UINT32 dwFlags; + UINT32 nPositionLow; + UINT32 nPositionHigh; + UINT32 cbRequested; + UINT32 clipDataId; +}; +typedef struct _CLIPRDR_FILE_CONTENTS_REQUEST CLIPRDR_FILE_CONTENTS_REQUEST; + +struct _CLIPRDR_FILE_CONTENTS_RESPONSE +{ + DEFINE_CLIPRDR_HEADER_COMMON(); + + UINT32 streamId; + UINT32 dwFlags; + UINT32 cbRequested; + BYTE* requestedData; +}; +typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE; + #endif /* FREERDP_CHANNEL_CLIPRDR_H */ diff --git a/include/freerdp/client/cliprdr.h b/include/freerdp/client/cliprdr.h index a29d621d2..da14df53d 100644 --- a/include/freerdp/client/cliprdr.h +++ b/include/freerdp/client/cliprdr.h @@ -34,14 +34,23 @@ typedef struct _cliprdr_client_context CliprdrClientContext; typedef int (*pcCliprdrServerCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities); typedef int (*pcCliprdrClientCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities); typedef int (*pcCliprdrMonitorReady)(CliprdrClientContext* context, CLIPRDR_MONITOR_READY* monitorReady); +typedef int (*pcCliprdrTempDirectory)(CliprdrClientContext* context, CLIPRDR_TEMP_DIRECTORY* tempDirectory); typedef int (*pcCliprdrClientFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList); typedef int (*pcCliprdrServerFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList); typedef int (*pcCliprdrClientFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse); typedef int (*pcCliprdrServerFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse); +typedef int (*pcCliprdrClientLockClipboardData)(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +typedef int (*pcCliprdrServerLockClipboardData)(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +typedef int (*pcCliprdrClientUnlockClipboardData)(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); +typedef int (*pcCliprdrServerUnlockClipboardData)(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); typedef int (*pcCliprdrClientFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest); typedef int (*pcCliprdrServerFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest); typedef int (*pcCliprdrClientFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse); typedef int (*pcCliprdrServerFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse); +typedef int (*pcCliprdrClientFileContentsRequest)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest); +typedef int (*pcCliprdrServerFileContentsRequest)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest); +typedef int (*pcCliprdrClientFileContentsResponse)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse); +typedef int (*pcCliprdrServerFileContentsResponse)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse); struct _cliprdr_client_context { @@ -51,14 +60,23 @@ struct _cliprdr_client_context pcCliprdrServerCapabilities ServerCapabilities; pcCliprdrClientCapabilities ClientCapabilities; pcCliprdrMonitorReady MonitorReady; + pcCliprdrTempDirectory TempDirectory; pcCliprdrClientFormatList ClientFormatList; pcCliprdrServerFormatList ServerFormatList; pcCliprdrClientFormatListResponse ClientFormatListResponse; pcCliprdrServerFormatListResponse ServerFormatListResponse; + pcCliprdrClientLockClipboardData ClientLockClipboardData; + pcCliprdrServerLockClipboardData ServerLockClipboardData; + pcCliprdrClientUnlockClipboardData ClientUnlockClipboardData; + pcCliprdrServerUnlockClipboardData ServerUnlockClipboardData; pcCliprdrClientFormatDataRequest ClientFormatDataRequest; pcCliprdrServerFormatDataRequest ServerFormatDataRequest; pcCliprdrClientFormatDataResponse ClientFormatDataResponse; pcCliprdrServerFormatDataResponse ServerFormatDataResponse; + pcCliprdrClientFileContentsRequest ClientFileContentsRequest; + pcCliprdrServerFileContentsRequest ServerFileContentsRequest; + pcCliprdrClientFileContentsResponse ClientFileContentsResponse; + pcCliprdrServerFileContentsResponse ServerFileContentsResponse; }; struct _CLIPRDR_FORMAT_NAME