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 free(execResult.exeOrFile.string);
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 RAIL_SYSPARAM_ORDER sysparam;
532 UINT error = 0;
533 BOOL extendedSpiSupported = 0;
534
535 if (!context || !s)
536 return ERROR_INVALID_PARAMETER;
537
538 extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
539 if ((error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported)))
540 {
541 WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
542 return error;
543 }
544
545 if (context->custom)
546 {
547 IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
548
549 if (error)
550 WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error);
551 }
552
553 return error;
554}
555
561static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
562{
563 RailClientContext* context = rail_get_client_interface(rail);
564 RAIL_MINMAXINFO_ORDER minMaxInfo = WINPR_C_ARRAY_INIT;
565 UINT error = 0;
566
567 if (!context || !s)
568 return ERROR_INVALID_PARAMETER;
569
570 if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
571 {
572 WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error);
573 return error;
574 }
575
576 if (context->custom)
577 {
578 IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
579
580 if (error)
581 WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error);
582 }
583
584 return error;
585}
586
592static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
593{
594 RailClientContext* context = rail_get_client_interface(rail);
595 RAIL_LOCALMOVESIZE_ORDER localMoveSize = WINPR_C_ARRAY_INIT;
596 UINT error = 0;
597
598 if (!context || !s)
599 return ERROR_INVALID_PARAMETER;
600
601 if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
602 {
603 WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error);
604 return error;
605 }
606
607 if (context->custom)
608 {
609 IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
610
611 if (error)
612 WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error);
613 }
614
615 return error;
616}
617
623static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
624{
625 RailClientContext* context = rail_get_client_interface(rail);
626 RAIL_GET_APPID_RESP_ORDER getAppIdResp = WINPR_C_ARRAY_INIT;
627 UINT error = 0;
628
629 if (!context || !s)
630 return ERROR_INVALID_PARAMETER;
631
632 if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
633 {
634 WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!",
635 error);
636 return error;
637 }
638
639 if (context->custom)
640 {
641 IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
642
643 if (error)
644 WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error);
645 }
646
647 return error;
648}
649
655static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
656{
657 RailClientContext* context = rail_get_client_interface(rail);
658 RAIL_LANGBAR_INFO_ORDER langBarInfo = WINPR_C_ARRAY_INIT;
659 UINT error = 0;
660
661 if (!context)
662 return ERROR_INVALID_PARAMETER;
663
664 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
665 return ERROR_BAD_CONFIGURATION;
666
667 if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
668 {
669 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
670 return error;
671 }
672
673 if (context->custom)
674 {
675 IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
676
677 if (error)
678 WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
679 }
680
681 return error;
682}
683
684static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
685{
686 if (!s || !taskbarInfo)
687 return ERROR_INVALID_PARAMETER;
688
689 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_TASKBAR_INFO_ORDER_LENGTH))
690 return ERROR_INVALID_DATA;
691
692 Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
693 Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
694 Stream_Read_UINT32(s, taskbarInfo->Body);
695 return CHANNEL_RC_OK;
696}
697
698static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
699{
700 RailClientContext* context = rail_get_client_interface(rail);
701 RAIL_TASKBAR_INFO_ORDER taskBarInfo = WINPR_C_ARRAY_INIT;
702 UINT error = 0;
703
704 if (!context)
705 return ERROR_INVALID_PARAMETER;
706
707 /* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
708 * server -> client message only supported if announced. */
709 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
710 return ERROR_BAD_CONFIGURATION;
711
712 if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
713 {
714 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
715 return error;
716 }
717
718 if (context->custom)
719 {
720 IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
721
722 if (error)
723 WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
724 }
725
726 return error;
727}
728
729static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
730{
731 if (!s || !zorder)
732 return ERROR_INVALID_PARAMETER;
733
734 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_Z_ORDER_SYNC_ORDER_LENGTH))
735 return ERROR_INVALID_DATA;
736
737 Stream_Read_UINT32(s, zorder->windowIdMarker);
738 return CHANNEL_RC_OK;
739}
740
741static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
742{
743 RailClientContext* context = rail_get_client_interface(rail);
744 RAIL_ZORDER_SYNC zorder = WINPR_C_ARRAY_INIT;
745 UINT error = 0;
746
747 if (!context)
748 return ERROR_INVALID_PARAMETER;
749
750 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
751 return ERROR_INVALID_DATA;
752
753 if ((error = rail_read_zorder_sync_order(s, &zorder)))
754 {
755 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
756 return error;
757 }
758
759 if (context->custom)
760 {
761 IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
762
763 if (error)
764 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
765 }
766
767 return error;
768}
769
770static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
771{
772 BYTE cloaked = 0;
773
774 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLOAK_ORDER_LENGTH))
775 return ERROR_INVALID_DATA;
776
777 Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
778 Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
779 cloak->cloak = (cloaked != 0);
780 return CHANNEL_RC_OK;
781}
782
783static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
784{
785 RailClientContext* context = rail_get_client_interface(rail);
786 RAIL_CLOAK cloak = WINPR_C_ARRAY_INIT;
787 UINT error = 0;
788
789 if (!context)
790 return ERROR_INVALID_PARAMETER;
791
792 /* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
793 * server -> client message only supported if announced. */
794 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
795 return ERROR_INVALID_DATA;
796
797 if ((error = rail_read_cloak_order(s, &cloak)))
798 {
799 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
800 return error;
801 }
802
803 if (context->custom)
804 {
805 IFCALLRET(context->ServerCloak, error, context, &cloak);
806
807 if (error)
808 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
809 }
810
811 return error;
812}
813
814static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
815{
816 UINT32 active = 0;
817
818 if (!s || !power)
819 return ERROR_INVALID_PARAMETER;
820
821 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH))
822 return ERROR_INVALID_DATA;
823
824 Stream_Read_UINT32(s, active);
825 power->active = active != 0;
826 return CHANNEL_RC_OK;
827}
828
829static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
830{
831 RailClientContext* context = rail_get_client_interface(rail);
832 RAIL_POWER_DISPLAY_REQUEST power = WINPR_C_ARRAY_INIT;
833 UINT error = 0;
834
835 if (!context)
836 return ERROR_INVALID_PARAMETER;
837
838 /* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
839 */
840 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
841 return ERROR_INVALID_DATA;
842
843 if ((error = rail_read_power_display_request_order(s, &power)))
844 {
845 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
846 return error;
847 }
848
849 if (context->custom)
850 {
851 IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
852
853 if (error)
854 WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error);
855 }
856
857 return error;
858}
859
860static UINT rail_read_get_application_id_extended_response_order(wStream* s,
862{
863 if (!s || !id)
864 return ERROR_INVALID_PARAMETER;
865
866 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
867 return ERROR_INVALID_DATA;
868
869 Stream_Read_UINT32(s, id->windowID);
870
871 if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
872 return ERROR_INVALID_DATA;
873
874 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
875 return ERROR_INVALID_DATA;
876
877 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
878 return ERROR_INVALID_DATA;
879
880 Stream_Read_UINT32(s, id->processId);
881
882 if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
883 return ERROR_INVALID_DATA;
884
885 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->processImageName)) >=
886 ARRAYSIZE(id->processImageName))
887 return ERROR_INVALID_DATA;
888
889 return CHANNEL_RC_OK;
890}
891
892static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s)
893{
894 RailClientContext* context = rail_get_client_interface(rail);
895 RAIL_GET_APPID_RESP_EX id = WINPR_C_ARRAY_INIT;
896 UINT error = 0;
897
898 if (!context)
899 return ERROR_INVALID_PARAMETER;
900
901 if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
902 {
903 WLog_ERR(TAG,
904 "rail_read_get_application_id_extended_response_order failed with error %" PRIu32
905 "!",
906 error);
907 return error;
908 }
909
910 if (context->custom)
911 {
912 IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
913
914 if (error)
915 WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "",
916 error);
917 }
918
919 return error;
920}
921
922static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor)
923{
924 WINPR_ASSERT(pTextScaleFactor);
925
926 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
927 return ERROR_INVALID_DATA;
928
929 Stream_Read_UINT32(s, *pTextScaleFactor);
930 return CHANNEL_RC_OK;
931}
932
933static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s)
934{
935 RailClientContext* context = rail_get_client_interface(rail);
936 UINT32 TextScaleFactor = 0;
937 UINT error = 0;
938
939 if (!context)
940 return ERROR_INVALID_PARAMETER;
941
942 if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor)))
943 return error;
944
945 if (context->custom)
946 {
947 IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
948
949 if (error)
950 WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error);
951 }
952
953 return error;
954}
955
956static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate)
957{
958 WINPR_ASSERT(pCaretBlinkRate);
959
960 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
961 return ERROR_INVALID_DATA;
962
963 Stream_Read_UINT32(s, *pCaretBlinkRate);
964 return CHANNEL_RC_OK;
965}
966
967static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
968{
969 RailClientContext* context = rail_get_client_interface(rail);
970 UINT32 CaretBlinkRate = 0;
971 UINT error = 0;
972
973 if (!context)
974 return ERROR_INVALID_PARAMETER;
975 if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate)))
976 return error;
977
978 if (context->custom)
979 {
980 IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
981
982 if (error)
983 WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error);
984 }
985
986 return error;
987}
988
994UINT rail_order_recv(LPVOID userdata, wStream* s)
995{
996 char buffer[128] = WINPR_C_ARRAY_INIT;
997 railPlugin* rail = userdata;
998 UINT16 orderType = 0;
999 UINT16 orderLength = 0;
1000 UINT error = CHANNEL_RC_OK;
1001
1002 if (!rail || !s)
1003 return ERROR_INVALID_PARAMETER;
1004
1005 if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
1006 {
1007 WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error);
1008 return error;
1009 }
1010
1011 WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
1012 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
1013
1014 switch (orderType)
1015 {
1016 case TS_RAIL_ORDER_HANDSHAKE:
1017 error = rail_recv_handshake_order(rail, s);
1018 break;
1019
1020 case TS_RAIL_ORDER_COMPARTMENTINFO:
1021 error = rail_recv_compartmentinfo_order(rail, s);
1022 break;
1023
1024 case TS_RAIL_ORDER_HANDSHAKE_EX:
1025 error = rail_recv_handshake_ex_order(rail, s);
1026 break;
1027
1028 case TS_RAIL_ORDER_EXEC_RESULT:
1029 error = rail_recv_exec_result_order(rail, s);
1030 break;
1031
1032 case TS_RAIL_ORDER_SYSPARAM:
1033 error = rail_recv_server_sysparam_order(rail, s);
1034 break;
1035
1036 case TS_RAIL_ORDER_MINMAXINFO:
1037 error = rail_recv_server_minmaxinfo_order(rail, s);
1038 break;
1039
1040 case TS_RAIL_ORDER_LOCALMOVESIZE:
1041 error = rail_recv_server_localmovesize_order(rail, s);
1042 break;
1043
1044 case TS_RAIL_ORDER_GET_APPID_RESP:
1045 error = rail_recv_server_get_appid_resp_order(rail, s);
1046 break;
1047
1048 case TS_RAIL_ORDER_LANGBARINFO:
1049 error = rail_recv_langbar_info_order(rail, s);
1050 break;
1051
1052 case TS_RAIL_ORDER_TASKBARINFO:
1053 error = rail_recv_taskbar_info_order(rail, s);
1054 break;
1055
1056 case TS_RAIL_ORDER_ZORDER_SYNC:
1057 error = rail_recv_zorder_sync_order(rail, s);
1058 break;
1059
1060 case TS_RAIL_ORDER_CLOAK:
1061 error = rail_recv_cloak_order(rail, s);
1062 break;
1063
1064 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
1065 error = rail_recv_power_display_request_order(rail, s);
1066 break;
1067
1068 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
1069 error = rail_recv_get_application_id_extended_response_order(rail, s);
1070 break;
1071
1072 case TS_RAIL_ORDER_TEXTSCALEINFO:
1073 error = rail_recv_textscaleinfo_order(rail, s);
1074 break;
1075
1076 case TS_RAIL_ORDER_CARETBLINKINFO:
1077 error = rail_recv_caretblinkinfo_order(rail, s);
1078 break;
1079
1080 default:
1081 WLog_ERR(TAG, "Unknown RAIL PDU %s received.",
1082 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)));
1083 return ERROR_INVALID_DATA;
1084 }
1085
1086 if (error != CHANNEL_RC_OK)
1087 {
1088 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1089 WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "",
1090 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)),
1091 orderLength);
1092 }
1093
1094 Stream_Free(s, TRUE);
1095 return error;
1096}
1097
1103UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake)
1104{
1105 if (!rail || !handshake)
1106 return ERROR_INVALID_PARAMETER;
1107
1108 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
1109
1110 if (!s)
1111 {
1112 WLog_ERR(TAG, "rail_pdu_init failed!");
1113 return CHANNEL_RC_NO_MEMORY;
1114 }
1115
1116 rail_write_handshake_order(s, handshake);
1117 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE);
1118}
1119
1125UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
1126{
1127 if (!rail || !handshakeEx)
1128 return ERROR_INVALID_PARAMETER;
1129
1130 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
1131
1132 if (!s)
1133 {
1134 WLog_ERR(TAG, "rail_pdu_init failed!");
1135 return CHANNEL_RC_NO_MEMORY;
1136 }
1137
1138 rail_write_handshake_ex_order(s, handshakeEx);
1139 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX);
1140}
1141
1147UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
1148{
1149 wStream* s = nullptr;
1150 UINT error = 0;
1151
1152 if (!rail || !clientStatus)
1153 return ERROR_INVALID_PARAMETER;
1154
1155 rail->clientStatus = *clientStatus;
1156 s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
1157
1158 if (!s)
1159 {
1160 WLog_ERR(TAG, "rail_pdu_init failed!");
1161 return CHANNEL_RC_NO_MEMORY;
1162 }
1163
1164 error = rail_write_client_status_order(s, clientStatus);
1165
1166 if (ERROR_SUCCESS != error)
1167 {
1168
1169 Stream_Free(s, TRUE);
1170 return error;
1171 }
1172
1173 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS);
1174}
1175
1181UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
1182 const RAIL_UNICODE_STRING* exeOrFile,
1183 const RAIL_UNICODE_STRING* workingDir,
1184 const RAIL_UNICODE_STRING* arguments)
1185{
1186 wStream* s = nullptr;
1187 UINT error = 0;
1188 size_t length = 0;
1189
1190 if (!rail || !exeOrFile || !workingDir || !arguments)
1191 return ERROR_INVALID_PARAMETER;
1192
1193 length = RAIL_EXEC_ORDER_LENGTH + exeOrFile->length + workingDir->length + arguments->length;
1194 s = rail_pdu_init(length);
1195
1196 if (!s)
1197 {
1198 WLog_ERR(TAG, "rail_pdu_init failed!");
1199 return CHANNEL_RC_NO_MEMORY;
1200 }
1201
1202 if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments)))
1203 {
1204 WLog_ERR(TAG, "rail_write_client_exec_order failed with error %" PRIu32 "!", error);
1205 goto out;
1206 }
1207
1208 return rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC);
1209
1210out:
1211 Stream_Free(s, TRUE);
1212 return error;
1213}
1214
1220UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate)
1221{
1222 wStream* s = nullptr;
1223 UINT error = 0;
1224
1225 if (!rail || !activate)
1226 return ERROR_INVALID_PARAMETER;
1227
1228 s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
1229
1230 if (!s)
1231 {
1232 WLog_ERR(TAG, "rail_pdu_init failed!");
1233 return CHANNEL_RC_NO_MEMORY;
1234 }
1235
1236 error = rail_write_client_activate_order(s, activate);
1237
1238 if (ERROR_SUCCESS != error)
1239 {
1240
1241 Stream_Free(s, TRUE);
1242 return error;
1243 }
1244
1245 return rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE);
1246}
1247
1253UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu)
1254{
1255 wStream* s = nullptr;
1256 UINT error = 0;
1257
1258 if (!rail || !sysmenu)
1259 return ERROR_INVALID_PARAMETER;
1260
1261 s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
1262
1263 if (!s)
1264 {
1265 WLog_ERR(TAG, "rail_pdu_init failed!");
1266 return CHANNEL_RC_NO_MEMORY;
1267 }
1268
1269 error = rail_write_client_sysmenu_order(s, sysmenu);
1270
1271 if (ERROR_SUCCESS != error)
1272 {
1273
1274 Stream_Free(s, TRUE);
1275 return error;
1276 }
1277
1278 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU);
1279}
1280
1286UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand)
1287{
1288 wStream* s = nullptr;
1289 UINT error = 0;
1290
1291 if (!rail || !syscommand)
1292 return ERROR_INVALID_PARAMETER;
1293
1294 s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
1295
1296 if (!s)
1297 {
1298 WLog_ERR(TAG, "rail_pdu_init failed!");
1299 return CHANNEL_RC_NO_MEMORY;
1300 }
1301
1302 error = rail_write_client_syscommand_order(s, syscommand);
1303
1304 if (ERROR_SUCCESS != error)
1305 {
1306
1307 Stream_Free(s, TRUE);
1308 return error;
1309 }
1310
1311 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND);
1312}
1313
1319UINT rail_send_client_notify_event_order(railPlugin* rail,
1320 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
1321{
1322 wStream* s = nullptr;
1323 UINT error = 0;
1324
1325 if (!rail || !notifyEvent)
1326 return ERROR_INVALID_PARAMETER;
1327
1328 s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
1329
1330 if (!s)
1331 {
1332 WLog_ERR(TAG, "rail_pdu_init failed!");
1333 return CHANNEL_RC_NO_MEMORY;
1334 }
1335
1336 error = rail_write_client_notify_event_order(s, notifyEvent);
1337
1338 if (ERROR_SUCCESS != error)
1339 {
1340
1341 Stream_Free(s, TRUE);
1342 return error;
1343 }
1344
1345 return rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT);
1346}
1347
1353UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove)
1354{
1355 wStream* s = nullptr;
1356 UINT error = 0;
1357
1358 if (!rail || !windowMove)
1359 return ERROR_INVALID_PARAMETER;
1360
1361 s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
1362
1363 if (!s)
1364 {
1365 WLog_ERR(TAG, "rail_pdu_init failed!");
1366 return CHANNEL_RC_NO_MEMORY;
1367 }
1368
1369 error = rail_write_client_window_move_order(s, windowMove);
1370
1371 if (ERROR_SUCCESS != error)
1372 {
1373
1374 Stream_Free(s, TRUE);
1375 return error;
1376 }
1377
1378 return rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE);
1379}
1380
1386UINT rail_send_client_get_appid_req_order(railPlugin* rail,
1387 const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
1388{
1389 wStream* s = nullptr;
1390 UINT error = 0;
1391
1392 if (!rail || !getAppIdReq)
1393 return ERROR_INVALID_PARAMETER;
1394
1395 s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
1396
1397 if (!s)
1398 {
1399 WLog_ERR(TAG, "rail_pdu_init failed!");
1400 return CHANNEL_RC_NO_MEMORY;
1401 }
1402
1403 error = rail_write_client_get_appid_req_order(s, getAppIdReq);
1404
1405 if (ERROR_SUCCESS != error)
1406 {
1407
1408 Stream_Free(s, TRUE);
1409 return error;
1410 }
1411 return rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ);
1412}
1413
1419UINT rail_send_client_langbar_info_order(railPlugin* rail,
1420 const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
1421{
1422 wStream* s = nullptr;
1423 UINT error = 0;
1424
1425 if (!rail || !langBarInfo)
1426 return ERROR_INVALID_PARAMETER;
1427
1428 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
1429 return ERROR_BAD_CONFIGURATION;
1430
1431 s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
1432
1433 if (!s)
1434 {
1435 WLog_ERR(TAG, "rail_pdu_init failed!");
1436 return CHANNEL_RC_NO_MEMORY;
1437 }
1438
1439 error = rail_write_langbar_info_order(s, langBarInfo);
1440
1441 if (ERROR_SUCCESS != error)
1442 {
1443
1444 Stream_Free(s, TRUE);
1445 return error;
1446 }
1447 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO);
1448}
1449
1450UINT rail_send_client_languageime_info_order(railPlugin* rail,
1451 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
1452{
1453 wStream* s = nullptr;
1454 UINT error = 0;
1455
1456 if (!rail || !langImeInfo)
1457 return ERROR_INVALID_PARAMETER;
1458
1459 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1460 return ERROR_BAD_CONFIGURATION;
1461
1462 s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH);
1463
1464 if (!s)
1465 {
1466 WLog_ERR(TAG, "rail_pdu_init failed!");
1467 return CHANNEL_RC_NO_MEMORY;
1468 }
1469
1470 error = rail_write_languageime_info_order(s, langImeInfo);
1471
1472 if (ERROR_SUCCESS != error)
1473 {
1474
1475 Stream_Free(s, TRUE);
1476 return error;
1477 }
1478 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO);
1479}
1480
1481UINT rail_send_client_compartment_info_order(railPlugin* rail,
1482 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
1483{
1484 wStream* s = nullptr;
1485 UINT error = 0;
1486
1487 if (!rail || !compartmentInfo)
1488 return ERROR_INVALID_PARAMETER;
1489
1490 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1491 return ERROR_BAD_CONFIGURATION;
1492
1493 s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
1494
1495 if (!s)
1496 {
1497 WLog_ERR(TAG, "rail_pdu_init failed!");
1498 return CHANNEL_RC_NO_MEMORY;
1499 }
1500
1501 error = rail_write_compartment_info_order(s, compartmentInfo);
1502
1503 if (ERROR_SUCCESS != error)
1504 {
1505 Stream_Free(s, TRUE);
1506 return error;
1507 }
1508 return rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO);
1509}
1510
1511UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
1512{
1513 if (!rail || !cloak)
1514 return ERROR_INVALID_PARAMETER;
1515
1516 wStream* s = rail_pdu_init(5);
1517
1518 if (!s)
1519 {
1520 WLog_ERR(TAG, "rail_pdu_init failed!");
1521 return CHANNEL_RC_NO_MEMORY;
1522 }
1523
1524 Stream_Write_UINT32(s, cloak->windowId);
1525 Stream_Write_UINT8(s, cloak->cloak ? 1 : 0);
1526 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK);
1527}
1528
1529UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
1530{
1531 if (!rail)
1532 return ERROR_INVALID_PARAMETER;
1533
1534 /* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */
1535 if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0)
1536 {
1537 RAIL_WINDOW_MOVE_ORDER move = WINPR_C_ARRAY_INIT;
1538 move.top = snap->top;
1539 move.left = snap->left;
1540 move.right = snap->right;
1541 move.bottom = snap->bottom;
1542 move.windowId = snap->windowId;
1543 return rail_send_client_window_move_order(rail, &move);
1544 }
1545
1546 wStream* s = rail_pdu_init(12);
1547
1548 if (!s)
1549 {
1550 WLog_ERR(TAG, "rail_pdu_init failed!");
1551 return CHANNEL_RC_NO_MEMORY;
1552 }
1553
1554 Stream_Write_UINT32(s, snap->windowId);
1555 Stream_Write_INT16(s, snap->left);
1556 Stream_Write_INT16(s, snap->top);
1557 Stream_Write_INT16(s, snap->right);
1558 Stream_Write_INT16(s, snap->bottom);
1559 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE);
1560}
1561
1562UINT rail_send_client_text_scale_order(railPlugin* rail, UINT32 textScale)
1563{
1564 if (!rail)
1565 return ERROR_INVALID_PARAMETER;
1566
1567 wStream* s = rail_pdu_init(4);
1568
1569 if (!s)
1570 {
1571 WLog_ERR(TAG, "rail_pdu_init failed!");
1572 return CHANNEL_RC_NO_MEMORY;
1573 }
1574
1575 Stream_Write_UINT32(s, textScale);
1576 return rail_send_pdu(rail, s, TS_RAIL_ORDER_TEXTSCALEINFO);
1577}
1578
1579UINT rail_send_client_caret_blink_rate_order(railPlugin* rail, UINT32 rate)
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, rate);
1593 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CARETBLINKINFO);
1594}
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.