FreeRDP
Loading...
Searching...
No Matches
rail_orders.c
1
25#include <freerdp/config.h>
26
27#include <winpr/crt.h>
28#include <winpr/cast.h>
29
30#include <freerdp/channels/log.h>
31#include <freerdp/freerdp.h>
32
33#include "rail_orders.h"
34
35static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask);
36
42UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType)
43{
44 char buffer[128] = WINPR_C_ARRAY_INIT;
45
46 if (!rail || !s)
47 {
48 Stream_Free(s, TRUE);
49 return ERROR_INVALID_PARAMETER;
50 }
51
52 const UINT16 orderLength = (UINT16)Stream_GetPosition(s);
53 Stream_ResetPosition(s);
54 if (!rail_write_pdu_header(s, orderType, orderLength))
55 goto fail;
56 if (!Stream_SetPosition(s, orderLength))
57 goto fail;
58 WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %" PRIu16 "",
59 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
60 return rail_send_channel_data(rail, s);
61
62fail:
63 Stream_Free(s, TRUE);
64 return ERROR_INVALID_DATA;
65}
66
72static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDER* execResult)
73{
74 if (!s || !execResult)
75 return ERROR_INVALID_PARAMETER;
76
77 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_EXEC_RESULT_ORDER_LENGTH))
78 return ERROR_INVALID_DATA;
79
80 Stream_Read_UINT16(s, execResult->flags); /* flags (2 bytes) */
81 Stream_Read_UINT16(s, execResult->execResult); /* execResult (2 bytes) */
82 Stream_Read_UINT32(s, execResult->rawResult); /* rawResult (4 bytes) */
83 Stream_Seek_UINT16(s); /* padding (2 bytes) */
84 return rail_read_unicode_string(s, &execResult->exeOrFile)
85 ? CHANNEL_RC_OK
86 : ERROR_INTERNAL_ERROR; /* exeOrFile */
87}
88
94static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* minmaxinfo)
95{
96 if (!s || !minmaxinfo)
97 return ERROR_INVALID_PARAMETER;
98
99 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_MINMAXINFO_ORDER_LENGTH))
100 return ERROR_INVALID_DATA;
101
102 Stream_Read_UINT32(s, minmaxinfo->windowId); /* windowId (4 bytes) */
103 Stream_Read_INT16(s, minmaxinfo->maxWidth); /* maxWidth (2 bytes) */
104 Stream_Read_INT16(s, minmaxinfo->maxHeight); /* maxHeight (2 bytes) */
105 Stream_Read_INT16(s, minmaxinfo->maxPosX); /* maxPosX (2 bytes) */
106 Stream_Read_INT16(s, minmaxinfo->maxPosY); /* maxPosY (2 bytes) */
107 Stream_Read_INT16(s, minmaxinfo->minTrackWidth); /* minTrackWidth (2 bytes) */
108 Stream_Read_INT16(s, minmaxinfo->minTrackHeight); /* minTrackHeight (2 bytes) */
109 Stream_Read_INT16(s, minmaxinfo->maxTrackWidth); /* maxTrackWidth (2 bytes) */
110 Stream_Read_INT16(s, minmaxinfo->maxTrackHeight); /* maxTrackHeight (2 bytes) */
111 return CHANNEL_RC_OK;
112}
113
119static UINT rail_read_server_localmovesize_order(wStream* s,
120 RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
121{
122 UINT16 isMoveSizeStart = 0;
123
124 if (!s || !localMoveSize)
125 return ERROR_INVALID_PARAMETER;
126
127 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_LOCALMOVESIZE_ORDER_LENGTH))
128 return ERROR_INVALID_DATA;
129
130 Stream_Read_UINT32(s, localMoveSize->windowId); /* windowId (4 bytes) */
131 Stream_Read_UINT16(s, isMoveSizeStart); /* isMoveSizeStart (2 bytes) */
132 localMoveSize->isMoveSizeStart = (isMoveSizeStart != 0);
133 Stream_Read_UINT16(s, localMoveSize->moveSizeType); /* moveSizeType (2 bytes) */
134 Stream_Read_INT16(s, localMoveSize->posX); /* posX (2 bytes) */
135 Stream_Read_INT16(s, localMoveSize->posY); /* posY (2 bytes) */
136 return CHANNEL_RC_OK;
137}
138
144static UINT rail_read_server_get_appid_resp_order(wStream* s,
145 RAIL_GET_APPID_RESP_ORDER* getAppidResp)
146{
147 if (!s || !getAppidResp)
148 return ERROR_INVALID_PARAMETER;
149
150 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_GET_APPID_RESP_ORDER_LENGTH))
151 return ERROR_INVALID_DATA;
152
153 Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */
154 if (!Stream_Read_UTF16_String(
155 s, getAppidResp->applicationId,
156 ARRAYSIZE(getAppidResp->applicationId))) /* applicationId (260 UNICODE chars) */
157 return ERROR_INVALID_DATA;
158 return CHANNEL_RC_OK;
159}
160
166static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
167{
168 if (!s || !langbarInfo)
169 return ERROR_INVALID_PARAMETER;
170
171 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_LANGBAR_INFO_ORDER_LENGTH))
172 return ERROR_INVALID_DATA;
173
174 Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
175 return CHANNEL_RC_OK;
176}
177
178static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
179{
180 if (!s || !clientStatus)
181 return ERROR_INVALID_PARAMETER;
182
183 Stream_Write_UINT32(s, clientStatus->flags); /* flags (4 bytes) */
184 return ERROR_SUCCESS;
185}
186
192static UINT rail_write_client_exec_order(wStream* s, UINT16 flags,
193 const RAIL_UNICODE_STRING* exeOrFile,
194 const RAIL_UNICODE_STRING* workingDir,
195 const RAIL_UNICODE_STRING* arguments)
196{
197 UINT error = 0;
198
199 if (!s || !exeOrFile || !workingDir || !arguments)
200 return ERROR_INVALID_PARAMETER;
201
202 /* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC)
203 * Check argument limits */
204 if ((exeOrFile->length > 520) || (workingDir->length > 520) || (arguments->length > 16000))
205 {
206 WLog_ERR(TAG,
207 "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%" PRIu16
208 " [max=520], WorkingDir=%" PRIu16 " [max=520], Arguments=%" PRIu16 " [max=16000]",
209 exeOrFile->length, workingDir->length, arguments->length);
210 return ERROR_BAD_ARGUMENTS;
211 }
212
213 Stream_Write_UINT16(s, flags); /* flags (2 bytes) */
214 Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */
215 Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */
216 Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */
217
218 if ((error = rail_write_unicode_string_value(s, exeOrFile)))
219 {
220 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
221 return error;
222 }
223
224 if ((error = rail_write_unicode_string_value(s, workingDir)))
225 {
226 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
227 return error;
228 }
229
230 if ((error = rail_write_unicode_string_value(s, arguments)))
231 {
232 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
233 return error;
234 }
235
236 return error;
237}
238
239static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate)
240{
241 BYTE enabled = 0;
242
243 if (!s || !activate)
244 return ERROR_INVALID_PARAMETER;
245
246 Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */
247 enabled = activate->enabled ? 1 : 0;
248 Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */
249 return ERROR_SUCCESS;
250}
251
252static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER* sysmenu)
253{
254 if (!s || !sysmenu)
255 return ERROR_INVALID_PARAMETER;
256
257 Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */
258 Stream_Write_INT16(s, sysmenu->left); /* left (2 bytes) */
259 Stream_Write_INT16(s, sysmenu->top); /* top (2 bytes) */
260 return ERROR_SUCCESS;
261}
262
263static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND_ORDER* syscommand)
264{
265 if (!s || !syscommand)
266 return ERROR_INVALID_PARAMETER;
267
268 Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */
269 Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */
270 return ERROR_SUCCESS;
271}
272
273static UINT rail_write_client_notify_event_order(wStream* s,
274 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
275{
276 if (!s || !notifyEvent)
277 return ERROR_INVALID_PARAMETER;
278
279 Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */
280 Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */
281 Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */
282 return ERROR_SUCCESS;
283}
284
285static UINT rail_write_client_window_move_order(wStream* s,
286 const RAIL_WINDOW_MOVE_ORDER* windowMove)
287{
288 if (!s || !windowMove)
289 return ERROR_INVALID_PARAMETER;
290
291 Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */
292 Stream_Write_INT16(s, windowMove->left); /* left (2 bytes) */
293 Stream_Write_INT16(s, windowMove->top); /* top (2 bytes) */
294 Stream_Write_INT16(s, windowMove->right); /* right (2 bytes) */
295 Stream_Write_INT16(s, windowMove->bottom); /* bottom (2 bytes) */
296 return ERROR_SUCCESS;
297}
298
299static UINT rail_write_client_get_appid_req_order(wStream* s,
300 const RAIL_GET_APPID_REQ_ORDER* getAppidReq)
301{
302 if (!s || !getAppidReq)
303 return ERROR_INVALID_PARAMETER;
304
305 Stream_Write_UINT32(s, getAppidReq->windowId); /* windowId (4 bytes) */
306 return ERROR_SUCCESS;
307}
308
309static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
310{
311 if (!s || !langbarInfo)
312 return ERROR_INVALID_PARAMETER;
313
314 Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
315 return ERROR_SUCCESS;
316}
317
318static UINT rail_write_languageime_info_order(wStream* s,
319 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
320{
321 if (!s || !langImeInfo)
322 return ERROR_INVALID_PARAMETER;
323
324 Stream_Write_UINT32(s, langImeInfo->ProfileType);
325 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(UINT16, langImeInfo->LanguageID));
326 Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID));
327 Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID));
328 Stream_Write_UINT32(s, langImeInfo->KeyboardLayout);
329 return ERROR_SUCCESS;
330}
331
332static UINT rail_write_compartment_info_order(wStream* s,
333 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
334{
335 if (!s || !compartmentInfo)
336 return ERROR_INVALID_PARAMETER;
337
338 Stream_Write_UINT32(s, compartmentInfo->ImeState);
339 Stream_Write_UINT32(s, compartmentInfo->ImeConvMode);
340 Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode);
341 Stream_Write_UINT32(s, compartmentInfo->KanaMode);
342 return ERROR_SUCCESS;
343}
344
350static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
351{
352 RailClientContext* context = rail_get_client_interface(rail);
353 RAIL_HANDSHAKE_ORDER serverHandshake = WINPR_C_ARRAY_INIT;
354 UINT error = 0;
355
356 if (!context || !s)
357 return ERROR_INVALID_PARAMETER;
358
359 if ((error = rail_read_handshake_order(s, &serverHandshake)))
360 {
361 WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error);
362 return error;
363 }
364
365 rail->channelBuildNumber = serverHandshake.buildNumber;
366
367 if (context->custom)
368 {
369 IFCALLRET(context->ServerHandshake, error, context, &serverHandshake);
370
371 if (error)
372 WLog_ERR(TAG, "context.ServerHandshake failed with error %" PRIu32 "", error);
373 }
374
375 return error;
376}
377
378static UINT rail_read_compartment_info_order(wStream* s,
379 RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
380{
381 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH))
382 return ERROR_INVALID_DATA;
383
384 Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */
385 Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */
386 Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */
387 Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */
388 return CHANNEL_RC_OK;
389}
390
391static UINT rail_recv_compartmentinfo_order(railPlugin* rail, wStream* s)
392{
393 RailClientContext* context = rail_get_client_interface(rail);
394 RAIL_COMPARTMENT_INFO_ORDER pdu = WINPR_C_ARRAY_INIT;
395 UINT error = 0;
396
397 if (!context || !s)
398 return ERROR_INVALID_PARAMETER;
399
400 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
401 return ERROR_BAD_CONFIGURATION;
402
403 if ((error = rail_read_compartment_info_order(s, &pdu)))
404 return error;
405
406 if (context->custom)
407 {
408 IFCALLRET(context->ClientCompartmentInfo, error, context, &pdu);
409
410 if (error)
411 WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error);
412 }
413
414 return error;
415}
416
417BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
418{
419 UINT32 supported = 0;
420 UINT32 masked = 0;
421
422 if (!context || !context->settings)
423 return FALSE;
424
425 const UINT32 level =
426 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportLevel);
427 const UINT32 mask =
428 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportMask);
429 supported = level & mask;
430 masked = (supported & featureMask);
431
432 if (masked != featureMask)
433 {
434 char maskstr[256] = WINPR_C_ARRAY_INIT;
435 char actualstr[256] = WINPR_C_ARRAY_INIT;
436
437 WLog_WARN(TAG, "have %s, require %s",
438 freerdp_rail_support_flags_to_string(supported, actualstr, sizeof(actualstr)),
439 freerdp_rail_support_flags_to_string(featureMask, maskstr, sizeof(maskstr)));
440 return FALSE;
441 }
442
443 return TRUE;
444}
445
451static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
452{
453 RailClientContext* context = rail_get_client_interface(rail);
454 RAIL_HANDSHAKE_EX_ORDER serverHandshake = WINPR_C_ARRAY_INIT;
455 UINT error = 0;
456
457 if (!rail || !context || !s)
458 return ERROR_INVALID_PARAMETER;
459
460 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED))
461 return ERROR_BAD_CONFIGURATION;
462
463 if ((error = rail_read_handshake_ex_order(s, &serverHandshake)))
464 {
465 WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %" PRIu32 "!", error);
466 return error;
467 }
468
469 rail->channelBuildNumber = serverHandshake.buildNumber;
470 rail->channelFlags = serverHandshake.railHandshakeFlags;
471
472 {
473 char buffer[192] = WINPR_C_ARRAY_INIT;
474 WLog_DBG(TAG, "HandshakeFlags=%s [buildNumber=0x%08" PRIx32 "]",
475 rail_handshake_ex_flags_to_string(rail->channelFlags, buffer, sizeof(buffer)),
476 rail->channelBuildNumber);
477 }
478
479 if (context->custom)
480 {
481 IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake);
482
483 if (error)
484 WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %" PRIu32 "", error);
485 }
486
487 return error;
488}
489
495static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s)
496{
497 RailClientContext* context = rail_get_client_interface(rail);
498 RAIL_EXEC_RESULT_ORDER execResult = WINPR_C_ARRAY_INIT;
499 UINT error = 0;
500
501 if (!context || !s)
502 return ERROR_INVALID_PARAMETER;
503
504 if ((error = rail_read_server_exec_result_order(s, &execResult)))
505 {
506 WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %" PRIu32 "!", error);
507 goto fail;
508 }
509
510 if (context->custom)
511 {
512 IFCALLRET(context->ServerExecuteResult, error, context, &execResult);
513
514 if (error)
515 WLog_ERR(TAG, "context.ServerExecuteResult failed with error %" PRIu32 "", error);
516 }
517
518fail:
519 rail_unicode_string_free(&execResult.exeOrFile);
520 return error;
521}
522
528static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
529{
530 RailClientContext* context = rail_get_client_interface(rail);
531
532 if (!context || !s)
533 return ERROR_INVALID_PARAMETER;
534
535 const BOOL extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
536 RAIL_SYSPARAM_ORDER sysparam = WINPR_C_ARRAY_INIT;
537 UINT error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported);
538 if (error)
539 {
540 WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
541 goto fail;
542 }
543
544 if (context->custom)
545 {
546 IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
547
548 if (error)
549 WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error);
550 }
551fail:
552 rail_unicode_string_free(&sysparam.highContrast.colorScheme);
553
554 return error;
555}
556
562static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
563{
564 RailClientContext* context = rail_get_client_interface(rail);
565 RAIL_MINMAXINFO_ORDER minMaxInfo = WINPR_C_ARRAY_INIT;
566 UINT error = 0;
567
568 if (!context || !s)
569 return ERROR_INVALID_PARAMETER;
570
571 if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
572 {
573 WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error);
574 return error;
575 }
576
577 if (context->custom)
578 {
579 IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
580
581 if (error)
582 WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error);
583 }
584
585 return error;
586}
587
593static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
594{
595 RailClientContext* context = rail_get_client_interface(rail);
596 RAIL_LOCALMOVESIZE_ORDER localMoveSize = WINPR_C_ARRAY_INIT;
597 UINT error = 0;
598
599 if (!context || !s)
600 return ERROR_INVALID_PARAMETER;
601
602 if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
603 {
604 WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error);
605 return error;
606 }
607
608 if (context->custom)
609 {
610 IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
611
612 if (error)
613 WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error);
614 }
615
616 return error;
617}
618
624static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
625{
626 RailClientContext* context = rail_get_client_interface(rail);
627 RAIL_GET_APPID_RESP_ORDER getAppIdResp = WINPR_C_ARRAY_INIT;
628 UINT error = 0;
629
630 if (!context || !s)
631 return ERROR_INVALID_PARAMETER;
632
633 if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
634 {
635 WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!",
636 error);
637 return error;
638 }
639
640 if (context->custom)
641 {
642 IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
643
644 if (error)
645 WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error);
646 }
647
648 return error;
649}
650
656static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
657{
658 RailClientContext* context = rail_get_client_interface(rail);
659 RAIL_LANGBAR_INFO_ORDER langBarInfo = WINPR_C_ARRAY_INIT;
660 UINT error = 0;
661
662 if (!context)
663 return ERROR_INVALID_PARAMETER;
664
665 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
666 return ERROR_BAD_CONFIGURATION;
667
668 if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
669 {
670 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
671 return error;
672 }
673
674 if (context->custom)
675 {
676 IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
677
678 if (error)
679 WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
680 }
681
682 return error;
683}
684
685static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
686{
687 if (!s || !taskbarInfo)
688 return ERROR_INVALID_PARAMETER;
689
690 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_TASKBAR_INFO_ORDER_LENGTH))
691 return ERROR_INVALID_DATA;
692
693 Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
694 Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
695 Stream_Read_UINT32(s, taskbarInfo->Body);
696 return CHANNEL_RC_OK;
697}
698
699static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
700{
701 RailClientContext* context = rail_get_client_interface(rail);
702 RAIL_TASKBAR_INFO_ORDER taskBarInfo = WINPR_C_ARRAY_INIT;
703 UINT error = 0;
704
705 if (!context)
706 return ERROR_INVALID_PARAMETER;
707
708 /* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
709 * server -> client message only supported if announced. */
710 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
711 return ERROR_BAD_CONFIGURATION;
712
713 if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
714 {
715 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
716 return error;
717 }
718
719 if (context->custom)
720 {
721 IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
722
723 if (error)
724 WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
725 }
726
727 return error;
728}
729
730static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
731{
732 if (!s || !zorder)
733 return ERROR_INVALID_PARAMETER;
734
735 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_Z_ORDER_SYNC_ORDER_LENGTH))
736 return ERROR_INVALID_DATA;
737
738 Stream_Read_UINT32(s, zorder->windowIdMarker);
739 return CHANNEL_RC_OK;
740}
741
742static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
743{
744 RailClientContext* context = rail_get_client_interface(rail);
745 RAIL_ZORDER_SYNC zorder = WINPR_C_ARRAY_INIT;
746 UINT error = 0;
747
748 if (!context)
749 return ERROR_INVALID_PARAMETER;
750
751 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
752 return ERROR_BAD_CONFIGURATION;
753
754 if ((error = rail_read_zorder_sync_order(s, &zorder)))
755 {
756 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
757 return error;
758 }
759
760 if (context->custom)
761 {
762 IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
763
764 if (error)
765 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
766 }
767
768 return error;
769}
770
771static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
772{
773 BYTE cloaked = 0;
774
775 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLOAK_ORDER_LENGTH))
776 return ERROR_INVALID_DATA;
777
778 Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
779 Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
780 cloak->cloak = (cloaked != 0);
781 return CHANNEL_RC_OK;
782}
783
784static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
785{
786 RailClientContext* context = rail_get_client_interface(rail);
787 RAIL_CLOAK cloak = WINPR_C_ARRAY_INIT;
788 UINT error = 0;
789
790 if (!context)
791 return ERROR_INVALID_PARAMETER;
792
793 /* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
794 * server -> client message only supported if announced. */
795 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
796 return ERROR_INVALID_DATA;
797
798 if ((error = rail_read_cloak_order(s, &cloak)))
799 {
800 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
801 return error;
802 }
803
804 if (context->custom)
805 {
806 IFCALLRET(context->ServerCloak, error, context, &cloak);
807
808 if (error)
809 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
810 }
811
812 return error;
813}
814
815static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
816{
817 UINT32 active = 0;
818
819 if (!s || !power)
820 return ERROR_INVALID_PARAMETER;
821
822 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH))
823 return ERROR_INVALID_DATA;
824
825 Stream_Read_UINT32(s, active);
826 power->active = active != 0;
827 return CHANNEL_RC_OK;
828}
829
830static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
831{
832 RailClientContext* context = rail_get_client_interface(rail);
833 RAIL_POWER_DISPLAY_REQUEST power = WINPR_C_ARRAY_INIT;
834 UINT error = 0;
835
836 if (!context)
837 return ERROR_INVALID_PARAMETER;
838
839 /* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
840 */
841 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
842 return ERROR_BAD_CONFIGURATION;
843
844 if ((error = rail_read_power_display_request_order(s, &power)))
845 {
846 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
847 return error;
848 }
849
850 if (context->custom)
851 {
852 IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
853
854 if (error)
855 WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error);
856 }
857
858 return error;
859}
860
861static UINT rail_read_get_application_id_extended_response_order(wStream* s,
863{
864 if (!s || !id)
865 return ERROR_INVALID_PARAMETER;
866
867 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
868 return ERROR_INVALID_DATA;
869
870 Stream_Read_UINT32(s, id->windowID);
871
872 if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
873 return ERROR_INVALID_DATA;
874
875 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
876 return ERROR_INVALID_DATA;
877
878 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
879 return ERROR_INVALID_DATA;
880
881 Stream_Read_UINT32(s, id->processId);
882
883 if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
884 return ERROR_INVALID_DATA;
885
886 if (_wcsnlen(id->processImageName, ARRAYSIZE(id->processImageName)) >=
887 ARRAYSIZE(id->processImageName))
888 return ERROR_INVALID_DATA;
889
890 return CHANNEL_RC_OK;
891}
892
893static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s)
894{
895 RailClientContext* context = rail_get_client_interface(rail);
896 RAIL_GET_APPID_RESP_EX id = WINPR_C_ARRAY_INIT;
897 UINT error = 0;
898
899 if (!context)
900 return ERROR_INVALID_PARAMETER;
901
902 if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
903 {
904 WLog_ERR(TAG,
905 "rail_read_get_application_id_extended_response_order failed with error %" PRIu32
906 "!",
907 error);
908 return error;
909 }
910
911 if (context->custom)
912 {
913 IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
914
915 if (error)
916 WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "",
917 error);
918 }
919
920 return error;
921}
922
923static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor)
924{
925 WINPR_ASSERT(pTextScaleFactor);
926
927 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
928 return ERROR_INVALID_DATA;
929
930 Stream_Read_UINT32(s, *pTextScaleFactor);
931 return CHANNEL_RC_OK;
932}
933
934static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s)
935{
936 RailClientContext* context = rail_get_client_interface(rail);
937 UINT32 TextScaleFactor = 0;
938 UINT error = 0;
939
940 if (!context)
941 return ERROR_INVALID_PARAMETER;
942
943 if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor)))
944 return error;
945
946 if (context->custom)
947 {
948 IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
949
950 if (error)
951 WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error);
952 }
953
954 return error;
955}
956
957static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate)
958{
959 WINPR_ASSERT(pCaretBlinkRate);
960
961 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
962 return ERROR_INVALID_DATA;
963
964 Stream_Read_UINT32(s, *pCaretBlinkRate);
965 return CHANNEL_RC_OK;
966}
967
968static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
969{
970 RailClientContext* context = rail_get_client_interface(rail);
971 UINT32 CaretBlinkRate = 0;
972 UINT error = 0;
973
974 if (!context)
975 return ERROR_INVALID_PARAMETER;
976 if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate)))
977 return error;
978
979 if (context->custom)
980 {
981 IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
982
983 if (error)
984 WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error);
985 }
986
987 return error;
988}
989
995UINT rail_order_recv(LPVOID userdata, wStream* s)
996{
997 char buffer[128] = WINPR_C_ARRAY_INIT;
998 railPlugin* rail = userdata;
999 UINT16 orderType = 0;
1000 UINT16 orderLength = 0;
1001 UINT error = CHANNEL_RC_OK;
1002
1003 if (!rail || !s)
1004 {
1005 error = ERROR_INVALID_PARAMETER;
1006 goto fail;
1007 }
1008
1009 if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
1010 {
1011 WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error);
1012 error = ERROR_INVALID_DATA;
1013 goto fail;
1014 }
1015
1016 WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
1017 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
1018
1019 switch (orderType)
1020 {
1021 case TS_RAIL_ORDER_HANDSHAKE:
1022 error = rail_recv_handshake_order(rail, s);
1023 break;
1024
1025 case TS_RAIL_ORDER_COMPARTMENTINFO:
1026 error = rail_recv_compartmentinfo_order(rail, s);
1027 break;
1028
1029 case TS_RAIL_ORDER_HANDSHAKE_EX:
1030 error = rail_recv_handshake_ex_order(rail, s);
1031 break;
1032
1033 case TS_RAIL_ORDER_EXEC_RESULT:
1034 error = rail_recv_exec_result_order(rail, s);
1035 break;
1036
1037 case TS_RAIL_ORDER_SYSPARAM:
1038 error = rail_recv_server_sysparam_order(rail, s);
1039 break;
1040
1041 case TS_RAIL_ORDER_MINMAXINFO:
1042 error = rail_recv_server_minmaxinfo_order(rail, s);
1043 break;
1044
1045 case TS_RAIL_ORDER_LOCALMOVESIZE:
1046 error = rail_recv_server_localmovesize_order(rail, s);
1047 break;
1048
1049 case TS_RAIL_ORDER_GET_APPID_RESP:
1050 error = rail_recv_server_get_appid_resp_order(rail, s);
1051 break;
1052
1053 case TS_RAIL_ORDER_LANGBARINFO:
1054 error = rail_recv_langbar_info_order(rail, s);
1055 break;
1056
1057 case TS_RAIL_ORDER_TASKBARINFO:
1058 error = rail_recv_taskbar_info_order(rail, s);
1059 break;
1060
1061 case TS_RAIL_ORDER_ZORDER_SYNC:
1062 error = rail_recv_zorder_sync_order(rail, s);
1063 break;
1064
1065 case TS_RAIL_ORDER_CLOAK:
1066 error = rail_recv_cloak_order(rail, s);
1067 break;
1068
1069 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
1070 error = rail_recv_power_display_request_order(rail, s);
1071 break;
1072
1073 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
1074 error = rail_recv_get_application_id_extended_response_order(rail, s);
1075 break;
1076
1077 case TS_RAIL_ORDER_TEXTSCALEINFO:
1078 error = rail_recv_textscaleinfo_order(rail, s);
1079 break;
1080
1081 case TS_RAIL_ORDER_CARETBLINKINFO:
1082 error = rail_recv_caretblinkinfo_order(rail, s);
1083 break;
1084
1085 default:
1086 WLog_ERR(TAG, "Unknown RAIL PDU %s received.",
1087 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)));
1088 return ERROR_INVALID_DATA;
1089 }
1090
1091 if (error == ERROR_BAD_CONFIGURATION)
1092 {
1093 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1094 WLog_Print(rail->log, WLOG_WARN,
1095 "%s - SERVER BUG: The support for this feature was not announced!",
1096 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)));
1097
1098 if (freerdp_settings_get_bool(rail->rdpcontext->settings,
1099 FreeRDP_AllowUnanouncedOrdersFromServer))
1100 error = CHANNEL_RC_OK;
1101 }
1102 if (error != CHANNEL_RC_OK)
1103 {
1104 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1105 WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "",
1106 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)),
1107 orderLength);
1108 }
1109
1110fail:
1111 Stream_Free(s, TRUE);
1112 return error;
1113}
1114
1120UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake)
1121{
1122 if (!rail || !handshake)
1123 return ERROR_INVALID_PARAMETER;
1124
1125 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
1126
1127 if (!s)
1128 {
1129 WLog_ERR(TAG, "rail_pdu_init failed!");
1130 return CHANNEL_RC_NO_MEMORY;
1131 }
1132
1133 rail_write_handshake_order(s, handshake);
1134 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE);
1135}
1136
1142UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
1143{
1144 if (!rail || !handshakeEx)
1145 return ERROR_INVALID_PARAMETER;
1146
1147 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
1148
1149 if (!s)
1150 {
1151 WLog_ERR(TAG, "rail_pdu_init failed!");
1152 return CHANNEL_RC_NO_MEMORY;
1153 }
1154
1155 rail_write_handshake_ex_order(s, handshakeEx);
1156 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX);
1157}
1158
1164UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
1165{
1166 wStream* s = nullptr;
1167 UINT error = 0;
1168
1169 if (!rail || !clientStatus)
1170 return ERROR_INVALID_PARAMETER;
1171
1172 rail->clientStatus = *clientStatus;
1173 s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
1174
1175 if (!s)
1176 {
1177 WLog_ERR(TAG, "rail_pdu_init failed!");
1178 return CHANNEL_RC_NO_MEMORY;
1179 }
1180
1181 error = rail_write_client_status_order(s, clientStatus);
1182
1183 if (ERROR_SUCCESS != error)
1184 {
1185
1186 Stream_Free(s, TRUE);
1187 return error;
1188 }
1189
1190 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS);
1191}
1192
1198UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
1199 const RAIL_UNICODE_STRING* exeOrFile,
1200 const RAIL_UNICODE_STRING* workingDir,
1201 const RAIL_UNICODE_STRING* arguments)
1202{
1203 wStream* s = nullptr;
1204 UINT error = 0;
1205 size_t length = 0;
1206
1207 if (!rail || !exeOrFile || !workingDir || !arguments)
1208 return ERROR_INVALID_PARAMETER;
1209
1210 length = RAIL_EXEC_ORDER_LENGTH + exeOrFile->length + workingDir->length + arguments->length;
1211 s = rail_pdu_init(length);
1212
1213 if (!s)
1214 {
1215 WLog_ERR(TAG, "rail_pdu_init failed!");
1216 return CHANNEL_RC_NO_MEMORY;
1217 }
1218
1219 if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments)))
1220 {
1221 WLog_ERR(TAG, "rail_write_client_exec_order failed with error %" PRIu32 "!", error);
1222 goto out;
1223 }
1224
1225 return rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC);
1226
1227out:
1228 Stream_Free(s, TRUE);
1229 return error;
1230}
1231
1237UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate)
1238{
1239 wStream* s = nullptr;
1240 UINT error = 0;
1241
1242 if (!rail || !activate)
1243 return ERROR_INVALID_PARAMETER;
1244
1245 s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
1246
1247 if (!s)
1248 {
1249 WLog_ERR(TAG, "rail_pdu_init failed!");
1250 return CHANNEL_RC_NO_MEMORY;
1251 }
1252
1253 error = rail_write_client_activate_order(s, activate);
1254
1255 if (ERROR_SUCCESS != error)
1256 {
1257
1258 Stream_Free(s, TRUE);
1259 return error;
1260 }
1261
1262 return rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE);
1263}
1264
1270UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu)
1271{
1272 wStream* s = nullptr;
1273 UINT error = 0;
1274
1275 if (!rail || !sysmenu)
1276 return ERROR_INVALID_PARAMETER;
1277
1278 s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
1279
1280 if (!s)
1281 {
1282 WLog_ERR(TAG, "rail_pdu_init failed!");
1283 return CHANNEL_RC_NO_MEMORY;
1284 }
1285
1286 error = rail_write_client_sysmenu_order(s, sysmenu);
1287
1288 if (ERROR_SUCCESS != error)
1289 {
1290
1291 Stream_Free(s, TRUE);
1292 return error;
1293 }
1294
1295 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU);
1296}
1297
1303UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand)
1304{
1305 wStream* s = nullptr;
1306 UINT error = 0;
1307
1308 if (!rail || !syscommand)
1309 return ERROR_INVALID_PARAMETER;
1310
1311 s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
1312
1313 if (!s)
1314 {
1315 WLog_ERR(TAG, "rail_pdu_init failed!");
1316 return CHANNEL_RC_NO_MEMORY;
1317 }
1318
1319 error = rail_write_client_syscommand_order(s, syscommand);
1320
1321 if (ERROR_SUCCESS != error)
1322 {
1323
1324 Stream_Free(s, TRUE);
1325 return error;
1326 }
1327
1328 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND);
1329}
1330
1336UINT rail_send_client_notify_event_order(railPlugin* rail,
1337 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
1338{
1339 wStream* s = nullptr;
1340 UINT error = 0;
1341
1342 if (!rail || !notifyEvent)
1343 return ERROR_INVALID_PARAMETER;
1344
1345 s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
1346
1347 if (!s)
1348 {
1349 WLog_ERR(TAG, "rail_pdu_init failed!");
1350 return CHANNEL_RC_NO_MEMORY;
1351 }
1352
1353 error = rail_write_client_notify_event_order(s, notifyEvent);
1354
1355 if (ERROR_SUCCESS != error)
1356 {
1357
1358 Stream_Free(s, TRUE);
1359 return error;
1360 }
1361
1362 return rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT);
1363}
1364
1370UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove)
1371{
1372 wStream* s = nullptr;
1373 UINT error = 0;
1374
1375 if (!rail || !windowMove)
1376 return ERROR_INVALID_PARAMETER;
1377
1378 s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
1379
1380 if (!s)
1381 {
1382 WLog_ERR(TAG, "rail_pdu_init failed!");
1383 return CHANNEL_RC_NO_MEMORY;
1384 }
1385
1386 error = rail_write_client_window_move_order(s, windowMove);
1387
1388 if (ERROR_SUCCESS != error)
1389 {
1390
1391 Stream_Free(s, TRUE);
1392 return error;
1393 }
1394
1395 return rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE);
1396}
1397
1403UINT rail_send_client_get_appid_req_order(railPlugin* rail,
1404 const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
1405{
1406 wStream* s = nullptr;
1407 UINT error = 0;
1408
1409 if (!rail || !getAppIdReq)
1410 return ERROR_INVALID_PARAMETER;
1411
1412 s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
1413
1414 if (!s)
1415 {
1416 WLog_ERR(TAG, "rail_pdu_init failed!");
1417 return CHANNEL_RC_NO_MEMORY;
1418 }
1419
1420 error = rail_write_client_get_appid_req_order(s, getAppIdReq);
1421
1422 if (ERROR_SUCCESS != error)
1423 {
1424
1425 Stream_Free(s, TRUE);
1426 return error;
1427 }
1428 return rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ);
1429}
1430
1436UINT rail_send_client_langbar_info_order(railPlugin* rail,
1437 const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
1438{
1439 wStream* s = nullptr;
1440 UINT error = 0;
1441
1442 if (!rail || !langBarInfo)
1443 return ERROR_INVALID_PARAMETER;
1444
1445 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
1446 return ERROR_BAD_CONFIGURATION;
1447
1448 s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
1449
1450 if (!s)
1451 {
1452 WLog_ERR(TAG, "rail_pdu_init failed!");
1453 return CHANNEL_RC_NO_MEMORY;
1454 }
1455
1456 error = rail_write_langbar_info_order(s, langBarInfo);
1457
1458 if (ERROR_SUCCESS != error)
1459 {
1460
1461 Stream_Free(s, TRUE);
1462 return error;
1463 }
1464 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO);
1465}
1466
1467UINT rail_send_client_languageime_info_order(railPlugin* rail,
1468 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
1469{
1470 wStream* s = nullptr;
1471 UINT error = 0;
1472
1473 if (!rail || !langImeInfo)
1474 return ERROR_INVALID_PARAMETER;
1475
1476 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1477 return ERROR_BAD_CONFIGURATION;
1478
1479 s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH);
1480
1481 if (!s)
1482 {
1483 WLog_ERR(TAG, "rail_pdu_init failed!");
1484 return CHANNEL_RC_NO_MEMORY;
1485 }
1486
1487 error = rail_write_languageime_info_order(s, langImeInfo);
1488
1489 if (ERROR_SUCCESS != error)
1490 {
1491
1492 Stream_Free(s, TRUE);
1493 return error;
1494 }
1495 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO);
1496}
1497
1498UINT rail_send_client_compartment_info_order(railPlugin* rail,
1499 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
1500{
1501 wStream* s = nullptr;
1502 UINT error = 0;
1503
1504 if (!rail || !compartmentInfo)
1505 return ERROR_INVALID_PARAMETER;
1506
1507 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1508 return ERROR_BAD_CONFIGURATION;
1509
1510 s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
1511
1512 if (!s)
1513 {
1514 WLog_ERR(TAG, "rail_pdu_init failed!");
1515 return CHANNEL_RC_NO_MEMORY;
1516 }
1517
1518 error = rail_write_compartment_info_order(s, compartmentInfo);
1519
1520 if (ERROR_SUCCESS != error)
1521 {
1522 Stream_Free(s, TRUE);
1523 return error;
1524 }
1525 return rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO);
1526}
1527
1528UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
1529{
1530 if (!rail || !cloak)
1531 return ERROR_INVALID_PARAMETER;
1532
1533 wStream* s = rail_pdu_init(5);
1534
1535 if (!s)
1536 {
1537 WLog_ERR(TAG, "rail_pdu_init failed!");
1538 return CHANNEL_RC_NO_MEMORY;
1539 }
1540
1541 Stream_Write_UINT32(s, cloak->windowId);
1542 Stream_Write_UINT8(s, cloak->cloak ? 1 : 0);
1543 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK);
1544}
1545
1546UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
1547{
1548 if (!rail)
1549 return ERROR_INVALID_PARAMETER;
1550
1551 /* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */
1552 if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0)
1553 {
1554 RAIL_WINDOW_MOVE_ORDER move = WINPR_C_ARRAY_INIT;
1555 move.top = snap->top;
1556 move.left = snap->left;
1557 move.right = snap->right;
1558 move.bottom = snap->bottom;
1559 move.windowId = snap->windowId;
1560 return rail_send_client_window_move_order(rail, &move);
1561 }
1562
1563 wStream* s = rail_pdu_init(12);
1564
1565 if (!s)
1566 {
1567 WLog_ERR(TAG, "rail_pdu_init failed!");
1568 return CHANNEL_RC_NO_MEMORY;
1569 }
1570
1571 Stream_Write_UINT32(s, snap->windowId);
1572 Stream_Write_INT16(s, snap->left);
1573 Stream_Write_INT16(s, snap->top);
1574 Stream_Write_INT16(s, snap->right);
1575 Stream_Write_INT16(s, snap->bottom);
1576 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE);
1577}
1578
1579UINT rail_send_client_text_scale_order(railPlugin* rail, UINT32 textScale)
1580{
1581 if (!rail)
1582 return ERROR_INVALID_PARAMETER;
1583
1584 wStream* s = rail_pdu_init(4);
1585
1586 if (!s)
1587 {
1588 WLog_ERR(TAG, "rail_pdu_init failed!");
1589 return CHANNEL_RC_NO_MEMORY;
1590 }
1591
1592 Stream_Write_UINT32(s, textScale);
1593 return rail_send_pdu(rail, s, TS_RAIL_ORDER_TEXTSCALEINFO);
1594}
1595
1596UINT rail_send_client_caret_blink_rate_order(railPlugin* rail, UINT32 rate)
1597{
1598 if (!rail)
1599 return ERROR_INVALID_PARAMETER;
1600
1601 wStream* s = rail_pdu_init(4);
1602
1603 if (!s)
1604 {
1605 WLog_ERR(TAG, "rail_pdu_init failed!");
1606 return CHANNEL_RC_NO_MEMORY;
1607 }
1608
1609 Stream_Write_UINT32(s, rate);
1610 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CARETBLINKINFO);
1611}
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_rail_support_flags_to_string(UINT32 flags, char *buffer, size_t length)
Returns a stringified representation of RAIL support flags.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.