/src/FreeRDP/channels/cliprdr/client/cliprdr_format.c
Line | Count | Source (jump to first uncovered line) |
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 | const UINT32 mask = |
129 | 0 | freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); |
130 | 0 | filteredFormatList = cliprdr_filter_format_list( |
131 | 0 | &formatList, mask, CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES); |
132 | 0 | if (filteredFormatList.numFormats == 0) |
133 | 0 | goto error_out; |
134 | | |
135 | 0 | const DWORD level = WLOG_DEBUG; |
136 | 0 | if (WLog_IsLevelActive(cliprdr->log, level)) |
137 | 0 | { |
138 | 0 | WLog_Print(cliprdr->log, level, "ServerFormatList: numFormats: %" PRIu32 "", |
139 | 0 | formatList.numFormats); |
140 | 0 | for (size_t x = 0; x < formatList.numFormats; x++) |
141 | 0 | { |
142 | 0 | const CLIPRDR_FORMAT* format = &formatList.formats[x]; |
143 | 0 | WLog_Print(cliprdr->log, level, "[%" PRIu32 "]: id=0x%08" PRIx32 " [%s|%s]", x, |
144 | 0 | format->formatId, ClipboardGetFormatIdString(format->formatId), |
145 | 0 | format->formatName); |
146 | 0 | } |
147 | |
|
148 | 0 | WLog_Print(cliprdr->log, level, "ServerFormatList [filtered]: numFormats: %" PRIu32 "", |
149 | 0 | filteredFormatList.numFormats); |
150 | 0 | for (size_t x = 0; x < filteredFormatList.numFormats; x++) |
151 | 0 | { |
152 | 0 | const CLIPRDR_FORMAT* format = &filteredFormatList.formats[x]; |
153 | 0 | WLog_Print(cliprdr->log, level, "[%" PRIu32 "]: id=0x%08" PRIx32 " [%s|%s]", x, |
154 | 0 | format->formatId, ClipboardGetFormatIdString(format->formatId), |
155 | 0 | format->formatName); |
156 | 0 | } |
157 | 0 | } |
158 | |
|
159 | 0 | if (context->ServerFormatList) |
160 | 0 | { |
161 | 0 | if ((error = context->ServerFormatList(context, &filteredFormatList))) |
162 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, "ServerFormatList failed with error %" PRIu32 "", |
163 | 0 | error); |
164 | 0 | } |
165 | |
|
166 | 0 | error_out: |
167 | 0 | cliprdr_free_format_list(&filteredFormatList); |
168 | 0 | cliprdr_free_format_list(&formatList); |
169 | 0 | return error; |
170 | 0 | } |
171 | | |
172 | | /** |
173 | | * Function description |
174 | | * |
175 | | * @return 0 on success, otherwise a Win32 error code |
176 | | */ |
177 | | UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, WINPR_ATTR_UNUSED wStream* s, |
178 | | UINT32 dataLen, UINT16 msgFlags) |
179 | 0 | { |
180 | 0 | CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 }; |
181 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
182 | 0 | UINT error = CHANNEL_RC_OK; |
183 | |
|
184 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatListResponse"); |
185 | |
|
186 | 0 | formatListResponse.common.msgType = CB_FORMAT_LIST_RESPONSE; |
187 | 0 | formatListResponse.common.msgFlags = msgFlags; |
188 | 0 | formatListResponse.common.dataLen = dataLen; |
189 | |
|
190 | 0 | IFCALLRET(context->ServerFormatListResponse, error, context, &formatListResponse); |
191 | 0 | if (error) |
192 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
193 | 0 | "ServerFormatListResponse failed with error %" PRIu32 "!", error); |
194 | |
|
195 | 0 | return error; |
196 | 0 | } |
197 | | |
198 | | /** |
199 | | * Function description |
200 | | * |
201 | | * @return 0 on success, otherwise a Win32 error code |
202 | | */ |
203 | | UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, |
204 | | UINT16 msgFlags) |
205 | 0 | { |
206 | 0 | CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest = { 0 }; |
207 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
208 | 0 | UINT error = CHANNEL_RC_OK; |
209 | |
|
210 | 0 | formatDataRequest.common.msgType = CB_FORMAT_DATA_REQUEST; |
211 | 0 | formatDataRequest.common.msgFlags = msgFlags; |
212 | 0 | formatDataRequest.common.dataLen = dataLen; |
213 | |
|
214 | 0 | if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) |
215 | 0 | return error; |
216 | | |
217 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatDataRequest (0x%08" PRIx32 " [%s])", |
218 | 0 | formatDataRequest.requestedFormatId, |
219 | 0 | ClipboardGetFormatIdString(formatDataRequest.requestedFormatId)); |
220 | |
|
221 | 0 | const UINT32 mask = |
222 | 0 | freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); |
223 | 0 | if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0) |
224 | 0 | { |
225 | 0 | return cliprdr_send_error_response(cliprdr, CB_FORMAT_DATA_RESPONSE); |
226 | 0 | } |
227 | | |
228 | 0 | context->lastRequestedFormatId = formatDataRequest.requestedFormatId; |
229 | 0 | IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest); |
230 | 0 | if (error) |
231 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
232 | 0 | "ServerFormatDataRequest failed with error %" PRIu32 "!", error); |
233 | |
|
234 | 0 | return error; |
235 | 0 | } |
236 | | |
237 | | /** |
238 | | * Function description |
239 | | * |
240 | | * @return 0 on success, otherwise a Win32 error code |
241 | | */ |
242 | | UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, |
243 | | UINT16 msgFlags) |
244 | 0 | { |
245 | 0 | CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse = { 0 }; |
246 | 0 | CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); |
247 | 0 | UINT error = CHANNEL_RC_OK; |
248 | |
|
249 | 0 | WLog_Print(cliprdr->log, WLOG_DEBUG, |
250 | 0 | "ServerFormatDataResponse: msgFlags=0x%08" PRIx32 ", dataLen=%" PRIu32, msgFlags, |
251 | 0 | dataLen); |
252 | |
|
253 | 0 | formatDataResponse.common.msgType = CB_FORMAT_DATA_RESPONSE; |
254 | 0 | formatDataResponse.common.msgFlags = msgFlags; |
255 | 0 | formatDataResponse.common.dataLen = dataLen; |
256 | |
|
257 | 0 | if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) |
258 | 0 | return error; |
259 | | |
260 | 0 | const UINT32 mask = |
261 | 0 | freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask); |
262 | 0 | if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0) |
263 | 0 | { |
264 | 0 | WLog_Print(cliprdr->log, WLOG_WARN, |
265 | 0 | "Received ServerFormatDataResponse but remote -> local clipboard is disabled"); |
266 | 0 | return CHANNEL_RC_OK; |
267 | 0 | } |
268 | | |
269 | 0 | IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse); |
270 | 0 | if (error) |
271 | 0 | WLog_Print(cliprdr->log, WLOG_ERROR, |
272 | 0 | "ServerFormatDataResponse failed with error %" PRIu32 "!", error); |
273 | |
|
274 | 0 | return error; |
275 | 0 | } |