/src/FreeRDP/channels/rail/client/rail_main.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * RAIL Virtual Channel Plugin |
4 | | * |
5 | | * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com> |
7 | | * Copyright 2011 Vic Lee |
8 | | * Copyright 2015 Thincast Technologies GmbH |
9 | | * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com> |
10 | | * Copyright 2017 Armin Novak <armin.novak@thincast.com> |
11 | | * Copyright 2017 Thincast Technologies GmbH |
12 | | * |
13 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
14 | | * you may not use this file except in compliance with the License. |
15 | | * You may obtain a copy of the License at |
16 | | * |
17 | | * http://www.apache.org/licenses/LICENSE-2.0 |
18 | | * |
19 | | * Unless required by applicable law or agreed to in writing, software |
20 | | * distributed under the License is distributed on an "AS IS" BASIS, |
21 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
22 | | * See the License for the specific language governing permissions and |
23 | | * limitations under the License. |
24 | | */ |
25 | | |
26 | | #include <freerdp/config.h> |
27 | | |
28 | | #include <winpr/crt.h> |
29 | | |
30 | | #include <freerdp/types.h> |
31 | | #include <freerdp/constants.h> |
32 | | #include <freerdp/freerdp.h> |
33 | | |
34 | | #include "rail_orders.h" |
35 | | #include "rail_main.h" |
36 | | |
37 | | #include "../../../channels/client/addin.h" |
38 | | |
39 | | RailClientContext* rail_get_client_interface(railPlugin* rail) |
40 | 0 | { |
41 | 0 | RailClientContext* pInterface = NULL; |
42 | |
|
43 | 0 | if (!rail) |
44 | 0 | return NULL; |
45 | | |
46 | 0 | pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface; |
47 | 0 | return pInterface; |
48 | 0 | } |
49 | | |
50 | | /** |
51 | | * Function description |
52 | | * |
53 | | * @return 0 on success, otherwise a Win32 error code |
54 | | */ |
55 | | static UINT rail_send(railPlugin* rail, wStream* s) |
56 | 0 | { |
57 | 0 | UINT status = 0; |
58 | |
|
59 | 0 | if (!rail) |
60 | 0 | { |
61 | 0 | Stream_Free(s, TRUE); |
62 | 0 | return CHANNEL_RC_BAD_INIT_HANDLE; |
63 | 0 | } |
64 | | |
65 | 0 | status = rail->channelEntryPoints.pVirtualChannelWriteEx( |
66 | 0 | rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s); |
67 | |
|
68 | 0 | if (status != CHANNEL_RC_OK) |
69 | 0 | { |
70 | 0 | Stream_Free(s, TRUE); |
71 | 0 | WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", |
72 | 0 | WTSErrorToString(status), status); |
73 | 0 | } |
74 | |
|
75 | 0 | return status; |
76 | 0 | } |
77 | | |
78 | | /** |
79 | | * Function description |
80 | | * |
81 | | * @return 0 on success, otherwise a Win32 error code |
82 | | */ |
83 | | UINT rail_send_channel_data(railPlugin* rail, wStream* src) |
84 | 0 | { |
85 | 0 | wStream* s = NULL; |
86 | 0 | size_t length = 0; |
87 | |
|
88 | 0 | if (!rail || !src) |
89 | 0 | return ERROR_INVALID_PARAMETER; |
90 | | |
91 | 0 | length = Stream_GetPosition(src); |
92 | 0 | s = Stream_New(NULL, length); |
93 | |
|
94 | 0 | if (!s) |
95 | 0 | { |
96 | 0 | WLog_ERR(TAG, "Stream_New failed!"); |
97 | 0 | return CHANNEL_RC_NO_MEMORY; |
98 | 0 | } |
99 | | |
100 | 0 | Stream_Write(s, Stream_Buffer(src), length); |
101 | 0 | return rail_send(rail, s); |
102 | 0 | } |
103 | | |
104 | | /** |
105 | | * Callback Interface |
106 | | */ |
107 | | |
108 | | /** |
109 | | * Function description |
110 | | * |
111 | | * @return 0 on success, otherwise a Win32 error code |
112 | | */ |
113 | | static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec) |
114 | 0 | { |
115 | 0 | const char* exeOrFile = NULL; |
116 | 0 | UINT error = 0; |
117 | 0 | railPlugin* rail = NULL; |
118 | 0 | UINT16 flags = 0; |
119 | 0 | RAIL_UNICODE_STRING ruExeOrFile = { 0 }; |
120 | 0 | RAIL_UNICODE_STRING ruWorkingDir = { 0 }; |
121 | 0 | RAIL_UNICODE_STRING ruArguments = { 0 }; |
122 | |
|
123 | 0 | if (!context || !exec) |
124 | 0 | return ERROR_INVALID_PARAMETER; |
125 | | |
126 | 0 | rail = (railPlugin*)context->handle; |
127 | 0 | exeOrFile = exec->RemoteApplicationProgram; |
128 | 0 | flags = exec->flags; |
129 | |
|
130 | 0 | if (!exeOrFile) |
131 | 0 | return ERROR_INVALID_PARAMETER; |
132 | | |
133 | 0 | if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram, |
134 | 0 | &ruExeOrFile) || /* RemoteApplicationProgram */ |
135 | 0 | !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir, |
136 | 0 | &ruWorkingDir) || /* ShellWorkingDirectory */ |
137 | 0 | !utf8_string_to_rail_string(exec->RemoteApplicationArguments, |
138 | 0 | &ruArguments)) /* RemoteApplicationCmdLine */ |
139 | 0 | error = ERROR_INTERNAL_ERROR; |
140 | 0 | else |
141 | 0 | error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments); |
142 | |
|
143 | 0 | free(ruExeOrFile.string); |
144 | 0 | free(ruWorkingDir.string); |
145 | 0 | free(ruArguments.string); |
146 | 0 | return error; |
147 | 0 | } |
148 | | |
149 | | /** |
150 | | * Function description |
151 | | * |
152 | | * @return 0 on success, otherwise a Win32 error code |
153 | | */ |
154 | | static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate) |
155 | 0 | { |
156 | 0 | railPlugin* rail = NULL; |
157 | |
|
158 | 0 | if (!context || !activate) |
159 | 0 | return ERROR_INVALID_PARAMETER; |
160 | | |
161 | 0 | rail = (railPlugin*)context->handle; |
162 | 0 | return rail_send_client_activate_order(rail, activate); |
163 | 0 | } |
164 | | |
165 | | /** |
166 | | * Function description |
167 | | * |
168 | | * @return 0 on success, otherwise a Win32 error code |
169 | | */ |
170 | | static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam) |
171 | 0 | { |
172 | 0 | wStream* s = NULL; |
173 | 0 | size_t length = RAIL_SYSPARAM_ORDER_LENGTH; |
174 | 0 | railPlugin* rail = NULL; |
175 | 0 | UINT error = 0; |
176 | 0 | BOOL extendedSpiSupported = 0; |
177 | |
|
178 | 0 | if (!context || !sysparam) |
179 | 0 | return ERROR_INVALID_PARAMETER; |
180 | | |
181 | 0 | rail = (railPlugin*)context->handle; |
182 | |
|
183 | 0 | switch (sysparam->param) |
184 | 0 | { |
185 | 0 | case SPI_SET_DRAG_FULL_WINDOWS: |
186 | 0 | case SPI_SET_KEYBOARD_CUES: |
187 | 0 | case SPI_SET_KEYBOARD_PREF: |
188 | 0 | case SPI_SET_MOUSE_BUTTON_SWAP: |
189 | 0 | length += 1; |
190 | 0 | break; |
191 | | |
192 | 0 | case SPI_SET_WORK_AREA: |
193 | 0 | case SPI_DISPLAY_CHANGE: |
194 | 0 | case SPI_TASKBAR_POS: |
195 | 0 | length += 8; |
196 | 0 | break; |
197 | | |
198 | 0 | case SPI_SET_HIGH_CONTRAST: |
199 | 0 | length += sysparam->highContrast.colorSchemeLength + 10; |
200 | 0 | break; |
201 | | |
202 | 0 | case SPI_SETFILTERKEYS: |
203 | 0 | length += 20; |
204 | 0 | break; |
205 | | |
206 | 0 | case SPI_SETSTICKYKEYS: |
207 | 0 | case SPI_SETCARETWIDTH: |
208 | 0 | case SPI_SETTOGGLEKEYS: |
209 | 0 | length += 4; |
210 | 0 | break; |
211 | | |
212 | 0 | default: |
213 | 0 | return ERROR_BAD_ARGUMENTS; |
214 | 0 | } |
215 | | |
216 | 0 | s = rail_pdu_init(length); |
217 | |
|
218 | 0 | if (!s) |
219 | 0 | { |
220 | 0 | WLog_ERR(TAG, "rail_pdu_init failed!"); |
221 | 0 | return CHANNEL_RC_NO_MEMORY; |
222 | 0 | } |
223 | | |
224 | 0 | extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags); |
225 | 0 | if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported))) |
226 | 0 | { |
227 | 0 | WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error); |
228 | 0 | Stream_Free(s, TRUE); |
229 | 0 | return error; |
230 | 0 | } |
231 | | |
232 | 0 | if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM))) |
233 | 0 | { |
234 | 0 | WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error); |
235 | 0 | } |
236 | |
|
237 | 0 | Stream_Free(s, TRUE); |
238 | 0 | return error; |
239 | 0 | } |
240 | | |
241 | | /** |
242 | | * Function description |
243 | | * |
244 | | * @return 0 on success, otherwise a Win32 error code |
245 | | */ |
246 | | static UINT rail_client_system_param(RailClientContext* context, |
247 | | const RAIL_SYSPARAM_ORDER* sysInParam) |
248 | 0 | { |
249 | 0 | UINT error = CHANNEL_RC_OK; |
250 | 0 | RAIL_SYSPARAM_ORDER sysparam; |
251 | |
|
252 | 0 | if (!context || !sysInParam) |
253 | 0 | return ERROR_INVALID_PARAMETER; |
254 | | |
255 | 0 | sysparam = *sysInParam; |
256 | |
|
257 | 0 | if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST) |
258 | 0 | { |
259 | 0 | sysparam.param = SPI_SET_HIGH_CONTRAST; |
260 | |
|
261 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
262 | 0 | { |
263 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
264 | 0 | return error; |
265 | 0 | } |
266 | 0 | } |
267 | | |
268 | 0 | if (sysparam.params & SPI_MASK_TASKBAR_POS) |
269 | 0 | { |
270 | 0 | sysparam.param = SPI_TASKBAR_POS; |
271 | |
|
272 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
273 | 0 | { |
274 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
275 | 0 | return error; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP) |
280 | 0 | { |
281 | 0 | sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP; |
282 | |
|
283 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
284 | 0 | { |
285 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
286 | 0 | return error; |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | 0 | if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF) |
291 | 0 | { |
292 | 0 | sysparam.param = SPI_SET_KEYBOARD_PREF; |
293 | |
|
294 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
295 | 0 | { |
296 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
297 | 0 | return error; |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | 0 | if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS) |
302 | 0 | { |
303 | 0 | sysparam.param = SPI_SET_DRAG_FULL_WINDOWS; |
304 | |
|
305 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
306 | 0 | { |
307 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
308 | 0 | return error; |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | 0 | if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES) |
313 | 0 | { |
314 | 0 | sysparam.param = SPI_SET_KEYBOARD_CUES; |
315 | |
|
316 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
317 | 0 | { |
318 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
319 | 0 | return error; |
320 | 0 | } |
321 | 0 | } |
322 | | |
323 | 0 | if (sysparam.params & SPI_MASK_SET_WORK_AREA) |
324 | 0 | { |
325 | 0 | sysparam.param = SPI_SET_WORK_AREA; |
326 | |
|
327 | 0 | if ((error = rail_send_client_sysparam(context, &sysparam))) |
328 | 0 | { |
329 | 0 | WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); |
330 | 0 | return error; |
331 | 0 | } |
332 | 0 | } |
333 | | |
334 | 0 | return error; |
335 | 0 | } |
336 | | |
337 | | /** |
338 | | * Function description |
339 | | * |
340 | | * @return 0 on success, otherwise a Win32 error code |
341 | | */ |
342 | | static UINT rail_client_system_command(RailClientContext* context, |
343 | | const RAIL_SYSCOMMAND_ORDER* syscommand) |
344 | 0 | { |
345 | 0 | railPlugin* rail = NULL; |
346 | |
|
347 | 0 | if (!context || !syscommand) |
348 | 0 | return ERROR_INVALID_PARAMETER; |
349 | | |
350 | 0 | rail = (railPlugin*)context->handle; |
351 | 0 | return rail_send_client_syscommand_order(rail, syscommand); |
352 | 0 | } |
353 | | |
354 | | /** |
355 | | * Function description |
356 | | * |
357 | | * @return 0 on success, otherwise a Win32 error code |
358 | | */ |
359 | | static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake) |
360 | 0 | { |
361 | 0 | railPlugin* rail = NULL; |
362 | |
|
363 | 0 | if (!context || !handshake) |
364 | 0 | return ERROR_INVALID_PARAMETER; |
365 | | |
366 | 0 | rail = (railPlugin*)context->handle; |
367 | 0 | return rail_send_handshake_order(rail, handshake); |
368 | 0 | } |
369 | | |
370 | | /** |
371 | | * Function description |
372 | | * |
373 | | * @return 0 on success, otherwise a Win32 error code |
374 | | */ |
375 | | static UINT rail_client_notify_event(RailClientContext* context, |
376 | | const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) |
377 | 0 | { |
378 | 0 | railPlugin* rail = NULL; |
379 | |
|
380 | 0 | if (!context || !notifyEvent) |
381 | 0 | return ERROR_INVALID_PARAMETER; |
382 | | |
383 | 0 | rail = (railPlugin*)context->handle; |
384 | 0 | return rail_send_client_notify_event_order(rail, notifyEvent); |
385 | 0 | } |
386 | | |
387 | | /** |
388 | | * Function description |
389 | | * |
390 | | * @return 0 on success, otherwise a Win32 error code |
391 | | */ |
392 | | static UINT rail_client_window_move(RailClientContext* context, |
393 | | const RAIL_WINDOW_MOVE_ORDER* windowMove) |
394 | 0 | { |
395 | 0 | railPlugin* rail = NULL; |
396 | |
|
397 | 0 | if (!context || !windowMove) |
398 | 0 | return ERROR_INVALID_PARAMETER; |
399 | | |
400 | 0 | rail = (railPlugin*)context->handle; |
401 | 0 | return rail_send_client_window_move_order(rail, windowMove); |
402 | 0 | } |
403 | | |
404 | | /** |
405 | | * Function description |
406 | | * |
407 | | * @return 0 on success, otherwise a Win32 error code |
408 | | */ |
409 | | static UINT rail_client_information(RailClientContext* context, |
410 | | const RAIL_CLIENT_STATUS_ORDER* clientStatus) |
411 | 0 | { |
412 | 0 | railPlugin* rail = NULL; |
413 | |
|
414 | 0 | if (!context || !clientStatus) |
415 | 0 | return ERROR_INVALID_PARAMETER; |
416 | | |
417 | 0 | rail = (railPlugin*)context->handle; |
418 | 0 | return rail_send_client_status_order(rail, clientStatus); |
419 | 0 | } |
420 | | |
421 | | /** |
422 | | * Function description |
423 | | * |
424 | | * @return 0 on success, otherwise a Win32 error code |
425 | | */ |
426 | | static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu) |
427 | 0 | { |
428 | 0 | railPlugin* rail = NULL; |
429 | |
|
430 | 0 | if (!context || !sysmenu) |
431 | 0 | return ERROR_INVALID_PARAMETER; |
432 | | |
433 | 0 | rail = (railPlugin*)context->handle; |
434 | 0 | return rail_send_client_sysmenu_order(rail, sysmenu); |
435 | 0 | } |
436 | | |
437 | | /** |
438 | | * Function description |
439 | | * |
440 | | * @return 0 on success, otherwise a Win32 error code |
441 | | */ |
442 | | static UINT rail_client_language_bar_info(RailClientContext* context, |
443 | | const RAIL_LANGBAR_INFO_ORDER* langBarInfo) |
444 | 0 | { |
445 | 0 | railPlugin* rail = NULL; |
446 | |
|
447 | 0 | if (!context || !langBarInfo) |
448 | 0 | return ERROR_INVALID_PARAMETER; |
449 | | |
450 | 0 | rail = (railPlugin*)context->handle; |
451 | 0 | return rail_send_client_langbar_info_order(rail, langBarInfo); |
452 | 0 | } |
453 | | |
454 | | static UINT rail_client_language_ime_info(RailClientContext* context, |
455 | | const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo) |
456 | 0 | { |
457 | 0 | railPlugin* rail = NULL; |
458 | |
|
459 | 0 | if (!context || !langImeInfo) |
460 | 0 | return ERROR_INVALID_PARAMETER; |
461 | | |
462 | 0 | rail = (railPlugin*)context->handle; |
463 | 0 | return rail_send_client_languageime_info_order(rail, langImeInfo); |
464 | 0 | } |
465 | | |
466 | | /** |
467 | | * Function description |
468 | | * |
469 | | * @return 0 on success, otherwise a Win32 error code |
470 | | */ |
471 | | static UINT rail_client_get_appid_request(RailClientContext* context, |
472 | | const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) |
473 | 0 | { |
474 | 0 | railPlugin* rail = NULL; |
475 | |
|
476 | 0 | if (!context || !getAppIdReq || !context->handle) |
477 | 0 | return ERROR_INVALID_PARAMETER; |
478 | | |
479 | 0 | rail = (railPlugin*)context->handle; |
480 | 0 | return rail_send_client_get_appid_req_order(rail, getAppIdReq); |
481 | 0 | } |
482 | | |
483 | | static UINT rail_client_compartment_info(RailClientContext* context, |
484 | | const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) |
485 | 0 | { |
486 | 0 | railPlugin* rail = NULL; |
487 | |
|
488 | 0 | if (!context || !compartmentInfo || !context->handle) |
489 | 0 | return ERROR_INVALID_PARAMETER; |
490 | | |
491 | 0 | rail = (railPlugin*)context->handle; |
492 | 0 | return rail_send_client_compartment_info_order(rail, compartmentInfo); |
493 | 0 | } |
494 | | |
495 | | static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak) |
496 | 0 | { |
497 | 0 | railPlugin* rail = NULL; |
498 | |
|
499 | 0 | if (!context || !cloak || !context->handle) |
500 | 0 | return ERROR_INVALID_PARAMETER; |
501 | | |
502 | 0 | rail = (railPlugin*)context->handle; |
503 | 0 | return rail_send_client_cloak_order(rail, cloak); |
504 | 0 | } |
505 | | |
506 | | static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap) |
507 | 0 | { |
508 | 0 | railPlugin* rail = NULL; |
509 | |
|
510 | 0 | if (!context || !snap || !context->handle) |
511 | 0 | return ERROR_INVALID_PARAMETER; |
512 | | |
513 | 0 | rail = (railPlugin*)context->handle; |
514 | 0 | return rail_send_client_snap_arrange_order(rail, snap); |
515 | 0 | } |
516 | | |
517 | | static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, |
518 | | UINT event, LPVOID pData, |
519 | | UINT32 dataLength, UINT32 totalLength, |
520 | | UINT32 dataFlags) |
521 | 0 | { |
522 | 0 | UINT error = CHANNEL_RC_OK; |
523 | 0 | railPlugin* rail = (railPlugin*)lpUserParam; |
524 | |
|
525 | 0 | switch (event) |
526 | 0 | { |
527 | 0 | case CHANNEL_EVENT_DATA_RECEIVED: |
528 | 0 | if (!rail || (rail->OpenHandle != openHandle)) |
529 | 0 | { |
530 | 0 | WLog_ERR(TAG, "error no match"); |
531 | 0 | return; |
532 | 0 | } |
533 | | |
534 | 0 | if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength, |
535 | 0 | totalLength, dataFlags))) |
536 | 0 | { |
537 | 0 | WLog_ERR(TAG, |
538 | 0 | "rail_virtual_channel_event_data_received" |
539 | 0 | " failed with error %" PRIu32 "!", |
540 | 0 | error); |
541 | 0 | } |
542 | |
|
543 | 0 | break; |
544 | | |
545 | 0 | case CHANNEL_EVENT_WRITE_CANCELLED: |
546 | 0 | case CHANNEL_EVENT_WRITE_COMPLETE: |
547 | 0 | { |
548 | 0 | wStream* s = (wStream*)pData; |
549 | 0 | Stream_Free(s, TRUE); |
550 | 0 | } |
551 | 0 | break; |
552 | | |
553 | 0 | case CHANNEL_EVENT_USER: |
554 | 0 | break; |
555 | 0 | } |
556 | | |
557 | 0 | if (error && rail && rail->rdpcontext) |
558 | 0 | setChannelError(rail->rdpcontext, error, |
559 | 0 | "rail_virtual_channel_open_event reported an error"); |
560 | |
|
561 | 0 | return; |
562 | 0 | } |
563 | | |
564 | | /** |
565 | | * Function description |
566 | | * |
567 | | * @return 0 on success, otherwise a Win32 error code |
568 | | */ |
569 | | static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength) |
570 | 0 | { |
571 | 0 | RailClientContext* context = rail_get_client_interface(rail); |
572 | 0 | UINT status = CHANNEL_RC_OK; |
573 | |
|
574 | 0 | WINPR_ASSERT(rail); |
575 | | |
576 | 0 | if (context) |
577 | 0 | { |
578 | 0 | IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake); |
579 | |
|
580 | 0 | if (status != CHANNEL_RC_OK) |
581 | 0 | WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]", |
582 | 0 | WTSErrorToString(status), status); |
583 | 0 | } |
584 | 0 | rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv, |
585 | 0 | RAIL_SVC_CHANNEL_NAME); |
586 | 0 | if (!rail->MsgsHandle) |
587 | 0 | return ERROR_INTERNAL_ERROR; |
588 | | |
589 | 0 | return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle, |
590 | 0 | rail->channelDef.name, |
591 | 0 | rail_virtual_channel_open_event_ex); |
592 | 0 | } |
593 | | |
594 | | /** |
595 | | * Function description |
596 | | * |
597 | | * @return 0 on success, otherwise a Win32 error code |
598 | | */ |
599 | | static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) |
600 | 0 | { |
601 | 0 | UINT rc = 0; |
602 | |
|
603 | 0 | channel_client_quit_handler(rail->MsgsHandle); |
604 | 0 | if (rail->OpenHandle == 0) |
605 | 0 | return CHANNEL_RC_OK; |
606 | | |
607 | 0 | WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx); |
608 | 0 | rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle); |
609 | |
|
610 | 0 | if (CHANNEL_RC_OK != rc) |
611 | 0 | { |
612 | 0 | WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), |
613 | 0 | rc); |
614 | 0 | return rc; |
615 | 0 | } |
616 | | |
617 | 0 | rail->OpenHandle = 0; |
618 | |
|
619 | 0 | return CHANNEL_RC_OK; |
620 | 0 | } |
621 | | |
622 | | static void rail_virtual_channel_event_terminated(railPlugin* rail) |
623 | 0 | { |
624 | 0 | rail->InitHandle = 0; |
625 | 0 | free(rail->context); |
626 | 0 | free(rail); |
627 | 0 | } |
628 | | |
629 | | static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, |
630 | | UINT event, LPVOID pData, UINT dataLength) |
631 | 0 | { |
632 | 0 | UINT error = CHANNEL_RC_OK; |
633 | 0 | railPlugin* rail = (railPlugin*)lpUserParam; |
634 | |
|
635 | 0 | if (!rail || (rail->InitHandle != pInitHandle)) |
636 | 0 | { |
637 | 0 | WLog_ERR(TAG, "error no match"); |
638 | 0 | return; |
639 | 0 | } |
640 | | |
641 | 0 | switch (event) |
642 | 0 | { |
643 | 0 | case CHANNEL_EVENT_CONNECTED: |
644 | 0 | if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength))) |
645 | 0 | WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!", |
646 | 0 | error); |
647 | |
|
648 | 0 | break; |
649 | | |
650 | 0 | case CHANNEL_EVENT_DISCONNECTED: |
651 | 0 | if ((error = rail_virtual_channel_event_disconnected(rail))) |
652 | 0 | WLog_ERR(TAG, |
653 | 0 | "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!", |
654 | 0 | error); |
655 | |
|
656 | 0 | break; |
657 | | |
658 | 0 | case CHANNEL_EVENT_TERMINATED: |
659 | 0 | rail_virtual_channel_event_terminated(rail); |
660 | 0 | break; |
661 | | |
662 | 0 | case CHANNEL_EVENT_ATTACHED: |
663 | 0 | case CHANNEL_EVENT_DETACHED: |
664 | 0 | default: |
665 | 0 | break; |
666 | 0 | } |
667 | | |
668 | 0 | if (error && rail->rdpcontext) |
669 | 0 | setChannelError(rail->rdpcontext, error, |
670 | 0 | "rail_virtual_channel_init_event_ex reported an error"); |
671 | 0 | } |
672 | | |
673 | | /* rail is always built-in */ |
674 | | #define VirtualChannelEntryEx rail_VirtualChannelEntryEx |
675 | | |
676 | | FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, |
677 | | PVOID pInitHandle)) |
678 | 0 | { |
679 | 0 | UINT rc = 0; |
680 | 0 | railPlugin* rail = NULL; |
681 | 0 | RailClientContext* context = NULL; |
682 | 0 | CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL; |
683 | 0 | BOOL isFreerdp = FALSE; |
684 | 0 | rail = (railPlugin*)calloc(1, sizeof(railPlugin)); |
685 | |
|
686 | 0 | if (!rail) |
687 | 0 | { |
688 | 0 | WLog_ERR(TAG, "calloc failed!"); |
689 | 0 | return FALSE; |
690 | 0 | } |
691 | | |
692 | | /* Default to automatically replying to server handshakes */ |
693 | 0 | rail->sendHandshake = TRUE; |
694 | 0 | rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | |
695 | 0 | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; |
696 | 0 | sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME); |
697 | 0 | pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; |
698 | |
|
699 | 0 | if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && |
700 | 0 | (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) |
701 | 0 | { |
702 | 0 | context = (RailClientContext*)calloc(1, sizeof(RailClientContext)); |
703 | |
|
704 | 0 | if (!context) |
705 | 0 | { |
706 | 0 | WLog_ERR(TAG, "calloc failed!"); |
707 | 0 | free(rail); |
708 | 0 | return FALSE; |
709 | 0 | } |
710 | | |
711 | 0 | context->handle = (void*)rail; |
712 | 0 | context->custom = NULL; |
713 | 0 | context->ClientExecute = rail_client_execute; |
714 | 0 | context->ClientActivate = rail_client_activate; |
715 | 0 | context->ClientSystemParam = rail_client_system_param; |
716 | 0 | context->ClientSystemCommand = rail_client_system_command; |
717 | 0 | context->ClientHandshake = rail_client_handshake; |
718 | 0 | context->ClientNotifyEvent = rail_client_notify_event; |
719 | 0 | context->ClientWindowMove = rail_client_window_move; |
720 | 0 | context->ClientInformation = rail_client_information; |
721 | 0 | context->ClientSystemMenu = rail_client_system_menu; |
722 | 0 | context->ClientLanguageBarInfo = rail_client_language_bar_info; |
723 | 0 | context->ClientLanguageIMEInfo = rail_client_language_ime_info; |
724 | 0 | context->ClientGetAppIdRequest = rail_client_get_appid_request; |
725 | 0 | context->ClientSnapArrange = rail_client_snap_arrange; |
726 | 0 | context->ClientCloak = rail_client_cloak; |
727 | 0 | context->ClientCompartmentInfo = rail_client_compartment_info; |
728 | 0 | rail->rdpcontext = pEntryPointsEx->context; |
729 | 0 | rail->context = context; |
730 | 0 | isFreerdp = TRUE; |
731 | 0 | } |
732 | | |
733 | 0 | rail->log = WLog_Get("com.freerdp.channels.rail.client"); |
734 | 0 | WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx"); |
735 | 0 | CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); |
736 | 0 | rail->InitHandle = pInitHandle; |
737 | 0 | rc = rail->channelEntryPoints.pVirtualChannelInitEx( |
738 | 0 | rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, |
739 | 0 | rail_virtual_channel_init_event_ex); |
740 | |
|
741 | 0 | if (CHANNEL_RC_OK != rc) |
742 | 0 | { |
743 | 0 | WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc); |
744 | 0 | goto error_out; |
745 | 0 | } |
746 | | |
747 | 0 | rail->channelEntryPoints.pInterface = context; |
748 | 0 | return TRUE; |
749 | 0 | error_out: |
750 | |
|
751 | 0 | if (isFreerdp) |
752 | 0 | free(rail->context); |
753 | |
|
754 | 0 | free(rail); |
755 | 0 | return FALSE; |
756 | 0 | } |