/src/FreeRDP/channels/cliprdr/client/cliprdr_format.c
Line | Count | Source |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Clipboard Virtual Channel |
4 | | * |
5 | | * Copyright 2009-2011 Jay Sorg |
6 | | * Copyright 2010-2011 Vic Lee |
7 | | * Copyright 2015 Thincast Technologies GmbH |
8 | | * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com> |
9 | | * |
10 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
11 | | * you may not use this file except in compliance with the License. |
12 | | * You may obtain a copy of the License at |
13 | | * |
14 | | * http://www.apache.org/licenses/LICENSE-2.0 |
15 | | * |
16 | | * Unless required by applicable law or agreed to in writing, software |
17 | | * distributed under the License is distributed on an "AS IS" BASIS, |
18 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
19 | | * See the License for the specific language governing permissions and |
20 | | * limitations under the License. |
21 | | */ |
22 | | |
23 | | #include <freerdp/config.h> |
24 | | |
25 | | #include <winpr/crt.h> |
26 | | #include <winpr/print.h> |
27 | | #include <winpr/clipboard.h> |
28 | | |
29 | | #include <freerdp/types.h> |
30 | | #include <freerdp/freerdp.h> |
31 | | #include <freerdp/settings.h> |
32 | | #include <freerdp/constants.h> |
33 | | #include <freerdp/client/cliprdr.h> |
34 | | |
35 | | #include "cliprdr_main.h" |
36 | | #include "cliprdr_format.h" |
37 | | #include "../cliprdr_common.h" |
38 | | |
39 | | CLIPRDR_FORMAT_LIST cliprdr_filter_format_list(const CLIPRDR_FORMAT_LIST* list, const UINT32 mask, |
40 | | const UINT32 checkMask) |
41 | 0 | { |
42 | 0 | const UINT32 maskData = |
43 | 0 | checkMask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL); |
44 | 0 | const UINT32 maskFiles = |
45 | 0 | checkMask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES); |
46 | 0 | WINPR_ASSERT(list); |
47 | | |
48 | 0 | CLIPRDR_FORMAT_LIST filtered = { 0 }; |
49 | 0 | filtered.common.msgType = CB_FORMAT_LIST; |
50 | 0 | filtered.numFormats = list->numFormats; |
51 | 0 | filtered.formats = calloc(filtered.numFormats, sizeof(CLIPRDR_FORMAT)); |
52 | |
|
53 | 0 | size_t wpos = 0; |
54 | 0 | if ((mask & checkMask) == checkMask) |
55 | 0 | { |
56 | 0 | for (size_t x = 0; x < list->numFormats; x++) |
57 | 0 | { |
58 | 0 | const CLIPRDR_FORMAT* format = &list->formats[x]; |
59 | 0 | CLIPRDR_FORMAT* cur = &filtered.formats[x]; |
60 | 0 | cur->formatId = format->formatId; |
61 | 0 | if (format->formatName) |
62 | 0 | cur->formatName = _strdup(format->formatName); |
63 | 0 | wpos++; |
64 | 0 | } |
65 | 0 | } |
66 | 0 | else if ((mask & maskFiles) != 0) |
67 | 0 | { |
68 | 0 | for (size_t x = 0; x < list->numFormats; x++) |
69 | 0 | { |
70 | 0 | const CLIPRDR_FORMAT* format = &list->formats[x]; |
71 | 0 | CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; |
72 | |
|
73 | 0 | if (!format->formatName) |
74 | 0 | continue; |
75 | 0 | if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0 || |
76 | 0 | strcmp(format->formatName, type_FileContents) == 0) |
77 | 0 | { |
78 | 0 | cur->formatId = format->formatId; |
79 | 0 | cur->formatName = _strdup(format->formatName); |
80 | 0 | wpos++; |
81 | 0 | } |
82 | 0 | } |
83 | 0 | } |
84 | 0 | else if ((mask & maskData) != 0) |
85 | 0 | { |
86 | 0 | for (size_t x = 0; x < list->numFormats; x++) |
87 | 0 | { |
88 | 0 | const CLIPRDR_FORMAT* format = &list->formats[x]; |
89 | 0 | CLIPRDR_FORMAT* cur = &filtered.formats[wpos]; |
90 | |
|
91 | 0 | if (!format->formatName || |
92 | 0 | (strcmp(format->formatName, type_FileGroupDescriptorW) != 0 && |
93 | 0 | strcmp(format->formatName, type_FileContents) != 0)) |
94 | 0 | { |
95 | 0 | cur->formatId = format->formatId; |
96 | 0 | if (format->formatName) |
97 | 0 | cur->formatName = _strdup(format->formatName); |
98 | 0 | wpos++; |
99 | 0 | } |
100 | 0 | } |
101 | 0 | } |
102 | 0 | WINPR_ASSERT(wpos <= UINT32_MAX); |
103 | 0 | filtered.numFormats = (UINT32)wpos; |
104 | 0 | return filtered; |
105 | 0 | } |
106 | | |
107 | | /** |
108 | | * Function description |
109 | | * |
110 | | * @return 0 on success, otherwise a Win32 error code |
111 | | */ |
112 | | UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, |
113 | | UINT16 msgFlags) |
114 | 0 | { |
115 | 0 | CLIPRDR_FORMAT_LIST formatList = { 0 }; |
116 | 0 | CLIPRDR_FORMAT_LIST filteredFormatList = { 0 }; |
117 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
118 | 0 | UINT error = CHANNEL_RC_OK; |
119 | |
|
120 | 0 | formatList.common.msgType = CB_FORMAT_LIST; |
121 | 0 | formatList.common.msgFlags = msgFlags; |
122 | 0 | formatList.common.dataLen = dataLen; |
123 | |
|
124 | 0 | if ((error = |
125 | 0 | cliprdr_read_format_list(cliprdr->log, s, &formatList, cliprdr->useLongFormatNames))) |
126 | 0 | goto error_out; |
127 | | |
128 | 0 | { |
129 | 0 | const UINT32 mask = freerdp_settings_get_uint32(context->rdpcontext->settings, |
130 | 0 | FreeRDP_ClipboardFeatureMask); |
131 | 0 | filteredFormatList = cliprdr_filter_format_list( |
132 | 0 | &formatList, mask, CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES); |
133 | 0 | } |
134 | |
|
135 | 0 | if (filteredFormatList.numFormats == 0) |
136 | 0 | goto error_out; |
137 | | |
138 | 0 | { |
139 | 0 | const DWORD level = WLOG_DEBUG; |
140 | 0 | if (WLog_IsLevelActive(cliprdr->log, level)) |
141 | 0 | { |
142 | 0 | WLog_Print(cliprdr->log, level, "ServerFormatList: numFormats: %" PRIu32 "", |
143 | 0 | formatList.numFormats); |
144 | 0 | for (size_t x = 0; x < formatList.numFormats; x++) |
145 | 0 | { |
146 | 0 | const CLIPRDR_FORMAT* format = &formatList.formats[x]; |
147 | 0 | WLog_Print(cliprdr->log, level, "[%" PRIuz "]: id=0x%08" PRIx32 " [%s|%s]", x, |
148 | 0 | format->formatId, ClipboardGetFormatIdString(format->formatId), |
149 | 0 | format->formatName); |
150 | 0 | } |
151 | |
|
152 | 0 | WLog_Print(cliprdr->log, level, "ServerFormatList [filtered]: numFormats: %" PRIu32 "", |
153 | 0 | filteredFormatList.numFormats); |
154 | 0 | for (size_t x = 0; x < filteredFormatList.numFormats; x++) |
155 | 0 | { |
156 | 0 | const CLIPRDR_FORMAT* format = &filteredFormatList.formats[x]; |
157 | 0 | WLog_Print(cliprdr->log, level, "[%" PRIuz "]: id=0x%08" PRIx32 " [%s|%s]", x, |
158 | 0 | format->formatId, ClipboardGetFormatIdString(format->formatId), |
159 | 0 | format->formatName); |
160 | 0 | } |
161 | 0 | } |
162 | 0 | } |
163 | |
|
164 | 0 | if (context->ServerFormatList) |
165 | 0 | { |
166 | 0 | if ((error = context->ServerFormatList(context, &filteredFormatList))) |
167 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, "ServerFormatList failed with error %" PRIu32 "", |
168 | 0 | error); |
169 | 0 | } |
170 | |
|
171 | 0 | error_out: |
172 | 0 | cliprdr_free_format_list(&filteredFormatList); |
173 | 0 | cliprdr_free_format_list(&formatList); |
174 | 0 | return error; |
175 | 0 | } |
176 | | |
177 | | /** |
178 | | * Function description |
179 | | * |
180 | | * @return 0 on success, otherwise a Win32 error code |
181 | | */ |
182 | | UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, WINPR_ATTR_UNUSED wStream* s, |
183 | | UINT32 dataLen, UINT16 msgFlags) |
184 | 0 | { |
185 | 0 | CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 }; |
186 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
187 | 0 | UINT error = CHANNEL_RC_OK; |
188 | |
|
189 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse"); |
190 | |
|
191 | 0 | formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE; |
192 | 0 | formatListResponse.common.msgFlags = msgFlags; |
193 | 0 | formatListResponse.common.dataLen = dataLen; |
194 | |
|
195 | 0 | IFCALLRET(context->ServerFormatListResponse, error, context, &formatListResponse); |
196 | 0 | if (error) |
197 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
198 | 0 | "ServerFormatListResponse failed with error %" PRIu32 "!", error); |
199 | |
|
200 | 0 | return error; |
201 | 0 | } |
202 | | |
203 | | /** |
204 | | * Function description |
205 | | * |
206 | | * @return 0 on success, otherwise a Win32 error code |
207 | | */ |
208 | | UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, |
209 | | UINT16 msgFlags) |
210 | 0 | { |
211 | 0 | CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = { 0 }; |
212 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
213 | 0 | UINT error = CHANNEL_RC_OK; |
214 | |
|
215 | 0 | formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST; |
216 | 0 | formatDataRequest.common.msgFlags = msgFlags; |
217 | 0 | formatDataRequest.common.dataLen = dataLen; |
218 | |
|
219 | 0 | if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) |
220 | 0 | return error; |
221 | | |
222 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest (0x%08" PRIx32 " [%s])", |
223 | 0 | formatDataRequest.requestedFormatId, |
224 | 0 | ClipboardGetFormatIdString(formatDataRequest.requestedFormatId)); |
225 | |
|
226 | 0 | const UINT32 mask = |
227 | 0 | freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); |
228 | 0 | if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0) |
229 | 0 | { |
230 | 0 | return cliprdr_send_error_response(cliprdr, CB_FORMAT_DATA_RESPONSE); |
231 | 0 | } |
232 | | |
233 | 0 | context->lastRequestedFormatId = formatDataRequest.requestedFormatId; |
234 | 0 | IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest); |
235 | 0 | if (error) |
236 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
237 | 0 | "ServerFormatDataRequest failed with error %" PRIu32 "!", error); |
238 | |
|
239 | 0 | return error; |
240 | 0 | } |
241 | | |
242 | | /** |
243 | | * Function description |
244 | | * |
245 | | * @return 0 on success, otherwise a Win32 error code |
246 | | */ |
247 | | UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, |
248 | | UINT16 msgFlags) |
249 | 0 | { |
250 | 0 | CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse = { 0 }; |
251 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
252 | 0 | UINT error = CHANNEL_RC_OK; |
253 | |
|
254 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, |
255 | 0 | "ServerFormatDataResponse: msgFlags=0x%08" PRIx32 ", dataLen=%" PRIu32, msgFlags, |
256 | 0 | dataLen); |
257 | |
|
258 | 0 | formatDataResponse.common.msgType = CB_FORMAT_DATA_RESPONSE; |
259 | 0 | formatDataResponse.common.msgFlags = msgFlags; |
260 | 0 | formatDataResponse.common.dataLen = dataLen; |
261 | |
|
262 | 0 | if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) |
263 | 0 | return error; |
264 | | |
265 | 0 | const UINT32 mask = |
266 | 0 | freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); |
267 | 0 | if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0) |
268 | 0 | { |
269 | 0 | WLog_Print(cliprdr->log, WLOG_WARN, |
270 | 0 | "Received ServerFormatDataResponse but remote -> local clipboard is disabled"); |
271 | 0 | return CHANNEL_RC_OK; |
272 | 0 | } |
273 | | |
274 | 0 | IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse); |
275 | 0 | if (error) |
276 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
277 | 0 | "ServerFormatDataResponse failed with error %" PRIu32 "!", error); |
278 | |
|
279 | 0 | return error; |
280 | 0 | } |