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 (rail->sendHandshake)
368 {
369 RAIL_HANDSHAKE_ORDER clientHandshake = WINPR_C_ARRAY_INIT;
370 clientHandshake.buildNumber = 0x00001DB0;
371 error = context->ClientHandshake(context, &clientHandshake);
372 }
373
374 if (error != CHANNEL_RC_OK)
375 return error;
376
377 if (context->custom)
378 {
379 IFCALLRET(context->ServerHandshake, error, context, &serverHandshake);
380
381 if (error)
382 WLog_ERR(TAG, "context.ServerHandshake failed with error %" PRIu32 "", error);
383 }
384
385 return error;
386}
387
388static UINT rail_read_compartment_info_order(wStream* s,
389 RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
390{
391 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH))
392 return ERROR_INVALID_DATA;
393
394 Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */
395 Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */
396 Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */
397 Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */
398 return CHANNEL_RC_OK;
399}
400
401static UINT rail_recv_compartmentinfo_order(railPlugin* rail, wStream* s)
402{
403 RailClientContext* context = rail_get_client_interface(rail);
404 RAIL_COMPARTMENT_INFO_ORDER pdu = WINPR_C_ARRAY_INIT;
405 UINT error = 0;
406
407 if (!context || !s)
408 return ERROR_INVALID_PARAMETER;
409
410 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
411 return ERROR_BAD_CONFIGURATION;
412
413 if ((error = rail_read_compartment_info_order(s, &pdu)))
414 return error;
415
416 if (context->custom)
417 {
418 IFCALLRET(context->ClientCompartmentInfo, error, context, &pdu);
419
420 if (error)
421 WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error);
422 }
423
424 return error;
425}
426
427BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
428{
429 UINT32 supported = 0;
430 UINT32 masked = 0;
431
432 if (!context || !context->settings)
433 return FALSE;
434
435 const UINT32 level =
436 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportLevel);
437 const UINT32 mask =
438 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportMask);
439 supported = level & mask;
440 masked = (supported & featureMask);
441
442 if (masked != featureMask)
443 {
444 char maskstr[256] = WINPR_C_ARRAY_INIT;
445 char actualstr[256] = WINPR_C_ARRAY_INIT;
446
447 WLog_WARN(TAG, "have %s, require %s",
448 freerdp_rail_support_flags_to_string(supported, actualstr, sizeof(actualstr)),
449 freerdp_rail_support_flags_to_string(featureMask, maskstr, sizeof(maskstr)));
450 return FALSE;
451 }
452
453 return TRUE;
454}
455
461static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
462{
463 RailClientContext* context = rail_get_client_interface(rail);
464 RAIL_HANDSHAKE_EX_ORDER serverHandshake = WINPR_C_ARRAY_INIT;
465 UINT error = 0;
466
467 if (!rail || !context || !s)
468 return ERROR_INVALID_PARAMETER;
469
470 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED))
471 return ERROR_BAD_CONFIGURATION;
472
473 if ((error = rail_read_handshake_ex_order(s, &serverHandshake)))
474 {
475 WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %" PRIu32 "!", error);
476 return error;
477 }
478
479 rail->channelBuildNumber = serverHandshake.buildNumber;
480 rail->channelFlags = serverHandshake.railHandshakeFlags;
481
482 {
483 char buffer[192] = WINPR_C_ARRAY_INIT;
484 WLog_DBG(TAG, "HandshakeFlags=%s [buildNumber=0x%08" PRIx32 "]",
485 rail_handshake_ex_flags_to_string(rail->channelFlags, buffer, sizeof(buffer)),
486 rail->channelBuildNumber);
487 }
488
489 if (rail->sendHandshake)
490 {
491 RAIL_HANDSHAKE_ORDER clientHandshake = WINPR_C_ARRAY_INIT;
492 clientHandshake.buildNumber = 0x00001DB0;
493 /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
494 * Client response is really a Handshake PDU */
495 error = context->ClientHandshake(context, &clientHandshake);
496 }
497
498 if (error != CHANNEL_RC_OK)
499 return error;
500
501 if (context->custom)
502 {
503 IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake);
504
505 if (error)
506 WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %" PRIu32 "", error);
507 }
508
509 return error;
510}
511
517static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s)
518{
519 RailClientContext* context = rail_get_client_interface(rail);
520 RAIL_EXEC_RESULT_ORDER execResult = WINPR_C_ARRAY_INIT;
521 UINT error = 0;
522
523 if (!context || !s)
524 return ERROR_INVALID_PARAMETER;
525
526 if ((error = rail_read_server_exec_result_order(s, &execResult)))
527 {
528 WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %" PRIu32 "!", error);
529 goto fail;
530 }
531
532 if (context->custom)
533 {
534 IFCALLRET(context->ServerExecuteResult, error, context, &execResult);
535
536 if (error)
537 WLog_ERR(TAG, "context.ServerExecuteResult failed with error %" PRIu32 "", error);
538 }
539
540fail:
541 free(execResult.exeOrFile.string);
542 return error;
543}
544
550static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
551{
552 RailClientContext* context = rail_get_client_interface(rail);
553 RAIL_SYSPARAM_ORDER sysparam;
554 UINT error = 0;
555 BOOL extendedSpiSupported = 0;
556
557 if (!context || !s)
558 return ERROR_INVALID_PARAMETER;
559
560 extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
561 if ((error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported)))
562 {
563 WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
564 return error;
565 }
566
567 if (context->custom)
568 {
569 IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
570
571 if (error)
572 WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error);
573 }
574
575 return error;
576}
577
583static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
584{
585 RailClientContext* context = rail_get_client_interface(rail);
586 RAIL_MINMAXINFO_ORDER minMaxInfo = WINPR_C_ARRAY_INIT;
587 UINT error = 0;
588
589 if (!context || !s)
590 return ERROR_INVALID_PARAMETER;
591
592 if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
593 {
594 WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error);
595 return error;
596 }
597
598 if (context->custom)
599 {
600 IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
601
602 if (error)
603 WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error);
604 }
605
606 return error;
607}
608
614static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
615{
616 RailClientContext* context = rail_get_client_interface(rail);
617 RAIL_LOCALMOVESIZE_ORDER localMoveSize = WINPR_C_ARRAY_INIT;
618 UINT error = 0;
619
620 if (!context || !s)
621 return ERROR_INVALID_PARAMETER;
622
623 if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
624 {
625 WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error);
626 return error;
627 }
628
629 if (context->custom)
630 {
631 IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
632
633 if (error)
634 WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error);
635 }
636
637 return error;
638}
639
645static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
646{
647 RailClientContext* context = rail_get_client_interface(rail);
648 RAIL_GET_APPID_RESP_ORDER getAppIdResp = WINPR_C_ARRAY_INIT;
649 UINT error = 0;
650
651 if (!context || !s)
652 return ERROR_INVALID_PARAMETER;
653
654 if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
655 {
656 WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!",
657 error);
658 return error;
659 }
660
661 if (context->custom)
662 {
663 IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
664
665 if (error)
666 WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error);
667 }
668
669 return error;
670}
671
677static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
678{
679 RailClientContext* context = rail_get_client_interface(rail);
680 RAIL_LANGBAR_INFO_ORDER langBarInfo = WINPR_C_ARRAY_INIT;
681 UINT error = 0;
682
683 if (!context)
684 return ERROR_INVALID_PARAMETER;
685
686 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
687 return ERROR_BAD_CONFIGURATION;
688
689 if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
690 {
691 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
692 return error;
693 }
694
695 if (context->custom)
696 {
697 IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
698
699 if (error)
700 WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
701 }
702
703 return error;
704}
705
706static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
707{
708 if (!s || !taskbarInfo)
709 return ERROR_INVALID_PARAMETER;
710
711 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_TASKBAR_INFO_ORDER_LENGTH))
712 return ERROR_INVALID_DATA;
713
714 Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
715 Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
716 Stream_Read_UINT32(s, taskbarInfo->Body);
717 return CHANNEL_RC_OK;
718}
719
720static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
721{
722 RailClientContext* context = rail_get_client_interface(rail);
723 RAIL_TASKBAR_INFO_ORDER taskBarInfo = WINPR_C_ARRAY_INIT;
724 UINT error = 0;
725
726 if (!context)
727 return ERROR_INVALID_PARAMETER;
728
729 /* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
730 * server -> client message only supported if announced. */
731 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
732 return ERROR_BAD_CONFIGURATION;
733
734 if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
735 {
736 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
737 return error;
738 }
739
740 if (context->custom)
741 {
742 IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
743
744 if (error)
745 WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
746 }
747
748 return error;
749}
750
751static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
752{
753 if (!s || !zorder)
754 return ERROR_INVALID_PARAMETER;
755
756 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_Z_ORDER_SYNC_ORDER_LENGTH))
757 return ERROR_INVALID_DATA;
758
759 Stream_Read_UINT32(s, zorder->windowIdMarker);
760 return CHANNEL_RC_OK;
761}
762
763static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
764{
765 RailClientContext* context = rail_get_client_interface(rail);
766 RAIL_ZORDER_SYNC zorder = WINPR_C_ARRAY_INIT;
767 UINT error = 0;
768
769 if (!context)
770 return ERROR_INVALID_PARAMETER;
771
772 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
773 return ERROR_INVALID_DATA;
774
775 if ((error = rail_read_zorder_sync_order(s, &zorder)))
776 {
777 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
778 return error;
779 }
780
781 if (context->custom)
782 {
783 IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
784
785 if (error)
786 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
787 }
788
789 return error;
790}
791
792static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
793{
794 BYTE cloaked = 0;
795
796 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLOAK_ORDER_LENGTH))
797 return ERROR_INVALID_DATA;
798
799 Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
800 Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
801 cloak->cloak = (cloaked != 0);
802 return CHANNEL_RC_OK;
803}
804
805static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
806{
807 RailClientContext* context = rail_get_client_interface(rail);
808 RAIL_CLOAK cloak = WINPR_C_ARRAY_INIT;
809 UINT error = 0;
810
811 if (!context)
812 return ERROR_INVALID_PARAMETER;
813
814 /* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
815 * server -> client message only supported if announced. */
816 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
817 return ERROR_INVALID_DATA;
818
819 if ((error = rail_read_cloak_order(s, &cloak)))
820 {
821 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
822 return error;
823 }
824
825 if (context->custom)
826 {
827 IFCALLRET(context->ServerCloak, error, context, &cloak);
828
829 if (error)
830 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
831 }
832
833 return error;
834}
835
836static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
837{
838 UINT32 active = 0;
839
840 if (!s || !power)
841 return ERROR_INVALID_PARAMETER;
842
843 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH))
844 return ERROR_INVALID_DATA;
845
846 Stream_Read_UINT32(s, active);
847 power->active = active != 0;
848 return CHANNEL_RC_OK;
849}
850
851static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
852{
853 RailClientContext* context = rail_get_client_interface(rail);
854 RAIL_POWER_DISPLAY_REQUEST power = WINPR_C_ARRAY_INIT;
855 UINT error = 0;
856
857 if (!context)
858 return ERROR_INVALID_PARAMETER;
859
860 /* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
861 */
862 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
863 return ERROR_INVALID_DATA;
864
865 if ((error = rail_read_power_display_request_order(s, &power)))
866 {
867 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
868 return error;
869 }
870
871 if (context->custom)
872 {
873 IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
874
875 if (error)
876 WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error);
877 }
878
879 return error;
880}
881
882static UINT rail_read_get_application_id_extended_response_order(wStream* s,
884{
885 if (!s || !id)
886 return ERROR_INVALID_PARAMETER;
887
888 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
889 return ERROR_INVALID_DATA;
890
891 Stream_Read_UINT32(s, id->windowID);
892
893 if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
894 return ERROR_INVALID_DATA;
895
896 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
897 return ERROR_INVALID_DATA;
898
899 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
900 return ERROR_INVALID_DATA;
901
902 Stream_Read_UINT32(s, id->processId);
903
904 if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
905 return ERROR_INVALID_DATA;
906
907 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->processImageName)) >=
908 ARRAYSIZE(id->processImageName))
909 return ERROR_INVALID_DATA;
910
911 return CHANNEL_RC_OK;
912}
913
914static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s)
915{
916 RailClientContext* context = rail_get_client_interface(rail);
917 RAIL_GET_APPID_RESP_EX id = WINPR_C_ARRAY_INIT;
918 UINT error = 0;
919
920 if (!context)
921 return ERROR_INVALID_PARAMETER;
922
923 if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
924 {
925 WLog_ERR(TAG,
926 "rail_read_get_application_id_extended_response_order failed with error %" PRIu32
927 "!",
928 error);
929 return error;
930 }
931
932 if (context->custom)
933 {
934 IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
935
936 if (error)
937 WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "",
938 error);
939 }
940
941 return error;
942}
943
944static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor)
945{
946 WINPR_ASSERT(pTextScaleFactor);
947
948 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
949 return ERROR_INVALID_DATA;
950
951 Stream_Read_UINT32(s, *pTextScaleFactor);
952 return CHANNEL_RC_OK;
953}
954
955static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s)
956{
957 RailClientContext* context = rail_get_client_interface(rail);
958 UINT32 TextScaleFactor = 0;
959 UINT error = 0;
960
961 if (!context)
962 return ERROR_INVALID_PARAMETER;
963
964 if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor)))
965 return error;
966
967 if (context->custom)
968 {
969 IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
970
971 if (error)
972 WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error);
973 }
974
975 return error;
976}
977
978static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate)
979{
980 WINPR_ASSERT(pCaretBlinkRate);
981
982 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
983 return ERROR_INVALID_DATA;
984
985 Stream_Read_UINT32(s, *pCaretBlinkRate);
986 return CHANNEL_RC_OK;
987}
988
989static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
990{
991 RailClientContext* context = rail_get_client_interface(rail);
992 UINT32 CaretBlinkRate = 0;
993 UINT error = 0;
994
995 if (!context)
996 return ERROR_INVALID_PARAMETER;
997 if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate)))
998 return error;
999
1000 if (context->custom)
1001 {
1002 IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
1003
1004 if (error)
1005 WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error);
1006 }
1007
1008 return error;
1009}
1010
1016UINT rail_order_recv(LPVOID userdata, wStream* s)
1017{
1018 char buffer[128] = WINPR_C_ARRAY_INIT;
1019 railPlugin* rail = userdata;
1020 UINT16 orderType = 0;
1021 UINT16 orderLength = 0;
1022 UINT error = CHANNEL_RC_OK;
1023
1024 if (!rail || !s)
1025 return ERROR_INVALID_PARAMETER;
1026
1027 if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
1028 {
1029 WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error);
1030 return error;
1031 }
1032
1033 WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
1034 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
1035
1036 switch (orderType)
1037 {
1038 case TS_RAIL_ORDER_HANDSHAKE:
1039 error = rail_recv_handshake_order(rail, s);
1040 break;
1041
1042 case TS_RAIL_ORDER_COMPARTMENTINFO:
1043 error = rail_recv_compartmentinfo_order(rail, s);
1044 break;
1045
1046 case TS_RAIL_ORDER_HANDSHAKE_EX:
1047 error = rail_recv_handshake_ex_order(rail, s);
1048 break;
1049
1050 case TS_RAIL_ORDER_EXEC_RESULT:
1051 error = rail_recv_exec_result_order(rail, s);
1052 break;
1053
1054 case TS_RAIL_ORDER_SYSPARAM:
1055 error = rail_recv_server_sysparam_order(rail, s);
1056 break;
1057
1058 case TS_RAIL_ORDER_MINMAXINFO:
1059 error = rail_recv_server_minmaxinfo_order(rail, s);
1060 break;
1061
1062 case TS_RAIL_ORDER_LOCALMOVESIZE:
1063 error = rail_recv_server_localmovesize_order(rail, s);
1064 break;
1065
1066 case TS_RAIL_ORDER_GET_APPID_RESP:
1067 error = rail_recv_server_get_appid_resp_order(rail, s);
1068 break;
1069
1070 case TS_RAIL_ORDER_LANGBARINFO:
1071 error = rail_recv_langbar_info_order(rail, s);
1072 break;
1073
1074 case TS_RAIL_ORDER_TASKBARINFO:
1075 error = rail_recv_taskbar_info_order(rail, s);
1076 break;
1077
1078 case TS_RAIL_ORDER_ZORDER_SYNC:
1079 error = rail_recv_zorder_sync_order(rail, s);
1080 break;
1081
1082 case TS_RAIL_ORDER_CLOAK:
1083 error = rail_recv_cloak_order(rail, s);
1084 break;
1085
1086 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
1087 error = rail_recv_power_display_request_order(rail, s);
1088 break;
1089
1090 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
1091 error = rail_recv_get_application_id_extended_response_order(rail, s);
1092 break;
1093
1094 case TS_RAIL_ORDER_TEXTSCALEINFO:
1095 error = rail_recv_textscaleinfo_order(rail, s);
1096 break;
1097
1098 case TS_RAIL_ORDER_CARETBLINKINFO:
1099 error = rail_recv_caretblinkinfo_order(rail, s);
1100 break;
1101
1102 default:
1103 WLog_ERR(TAG, "Unknown RAIL PDU %s received.",
1104 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)));
1105 return ERROR_INVALID_DATA;
1106 }
1107
1108 if (error != CHANNEL_RC_OK)
1109 {
1110 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1111 WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "",
1112 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)),
1113 orderLength);
1114 }
1115
1116 Stream_Free(s, TRUE);
1117 return error;
1118}
1119
1125UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* handshake)
1126{
1127 if (!rail || !handshake)
1128 return ERROR_INVALID_PARAMETER;
1129
1130 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_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_order(s, handshake);
1139 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE);
1140}
1141
1147UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
1148{
1149 if (!rail || !handshakeEx)
1150 return ERROR_INVALID_PARAMETER;
1151
1152 wStream* s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH);
1153
1154 if (!s)
1155 {
1156 WLog_ERR(TAG, "rail_pdu_init failed!");
1157 return CHANNEL_RC_NO_MEMORY;
1158 }
1159
1160 rail_write_handshake_ex_order(s, handshakeEx);
1161 return rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX);
1162}
1163
1169UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
1170{
1171 wStream* s = nullptr;
1172 UINT error = 0;
1173
1174 if (!rail || !clientStatus)
1175 return ERROR_INVALID_PARAMETER;
1176
1177 rail->clientStatus = *clientStatus;
1178 s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
1179
1180 if (!s)
1181 {
1182 WLog_ERR(TAG, "rail_pdu_init failed!");
1183 return CHANNEL_RC_NO_MEMORY;
1184 }
1185
1186 error = rail_write_client_status_order(s, clientStatus);
1187
1188 if (ERROR_SUCCESS != error)
1189 {
1190
1191 Stream_Free(s, TRUE);
1192 return error;
1193 }
1194
1195 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS);
1196}
1197
1203UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
1204 const RAIL_UNICODE_STRING* exeOrFile,
1205 const RAIL_UNICODE_STRING* workingDir,
1206 const RAIL_UNICODE_STRING* arguments)
1207{
1208 wStream* s = nullptr;
1209 UINT error = 0;
1210 size_t length = 0;
1211
1212 if (!rail || !exeOrFile || !workingDir || !arguments)
1213 return ERROR_INVALID_PARAMETER;
1214
1215 length = RAIL_EXEC_ORDER_LENGTH + exeOrFile->length + workingDir->length + arguments->length;
1216 s = rail_pdu_init(length);
1217
1218 if (!s)
1219 {
1220 WLog_ERR(TAG, "rail_pdu_init failed!");
1221 return CHANNEL_RC_NO_MEMORY;
1222 }
1223
1224 if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments)))
1225 {
1226 WLog_ERR(TAG, "rail_write_client_exec_order failed with error %" PRIu32 "!", error);
1227 goto out;
1228 }
1229
1230 return rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC);
1231
1232out:
1233 Stream_Free(s, TRUE);
1234 return error;
1235}
1236
1242UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate)
1243{
1244 wStream* s = nullptr;
1245 UINT error = 0;
1246
1247 if (!rail || !activate)
1248 return ERROR_INVALID_PARAMETER;
1249
1250 s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
1251
1252 if (!s)
1253 {
1254 WLog_ERR(TAG, "rail_pdu_init failed!");
1255 return CHANNEL_RC_NO_MEMORY;
1256 }
1257
1258 error = rail_write_client_activate_order(s, activate);
1259
1260 if (ERROR_SUCCESS != error)
1261 {
1262
1263 Stream_Free(s, TRUE);
1264 return error;
1265 }
1266
1267 return rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE);
1268}
1269
1275UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu)
1276{
1277 wStream* s = nullptr;
1278 UINT error = 0;
1279
1280 if (!rail || !sysmenu)
1281 return ERROR_INVALID_PARAMETER;
1282
1283 s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
1284
1285 if (!s)
1286 {
1287 WLog_ERR(TAG, "rail_pdu_init failed!");
1288 return CHANNEL_RC_NO_MEMORY;
1289 }
1290
1291 error = rail_write_client_sysmenu_order(s, sysmenu);
1292
1293 if (ERROR_SUCCESS != error)
1294 {
1295
1296 Stream_Free(s, TRUE);
1297 return error;
1298 }
1299
1300 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU);
1301}
1302
1308UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand)
1309{
1310 wStream* s = nullptr;
1311 UINT error = 0;
1312
1313 if (!rail || !syscommand)
1314 return ERROR_INVALID_PARAMETER;
1315
1316 s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
1317
1318 if (!s)
1319 {
1320 WLog_ERR(TAG, "rail_pdu_init failed!");
1321 return CHANNEL_RC_NO_MEMORY;
1322 }
1323
1324 error = rail_write_client_syscommand_order(s, syscommand);
1325
1326 if (ERROR_SUCCESS != error)
1327 {
1328
1329 Stream_Free(s, TRUE);
1330 return error;
1331 }
1332
1333 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND);
1334}
1335
1341UINT rail_send_client_notify_event_order(railPlugin* rail,
1342 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
1343{
1344 wStream* s = nullptr;
1345 UINT error = 0;
1346
1347 if (!rail || !notifyEvent)
1348 return ERROR_INVALID_PARAMETER;
1349
1350 s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
1351
1352 if (!s)
1353 {
1354 WLog_ERR(TAG, "rail_pdu_init failed!");
1355 return CHANNEL_RC_NO_MEMORY;
1356 }
1357
1358 error = rail_write_client_notify_event_order(s, notifyEvent);
1359
1360 if (ERROR_SUCCESS != error)
1361 {
1362
1363 Stream_Free(s, TRUE);
1364 return error;
1365 }
1366
1367 return rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT);
1368}
1369
1375UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove)
1376{
1377 wStream* s = nullptr;
1378 UINT error = 0;
1379
1380 if (!rail || !windowMove)
1381 return ERROR_INVALID_PARAMETER;
1382
1383 s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
1384
1385 if (!s)
1386 {
1387 WLog_ERR(TAG, "rail_pdu_init failed!");
1388 return CHANNEL_RC_NO_MEMORY;
1389 }
1390
1391 error = rail_write_client_window_move_order(s, windowMove);
1392
1393 if (ERROR_SUCCESS != error)
1394 {
1395
1396 Stream_Free(s, TRUE);
1397 return error;
1398 }
1399
1400 return rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE);
1401}
1402
1408UINT rail_send_client_get_appid_req_order(railPlugin* rail,
1409 const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
1410{
1411 wStream* s = nullptr;
1412 UINT error = 0;
1413
1414 if (!rail || !getAppIdReq)
1415 return ERROR_INVALID_PARAMETER;
1416
1417 s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
1418
1419 if (!s)
1420 {
1421 WLog_ERR(TAG, "rail_pdu_init failed!");
1422 return CHANNEL_RC_NO_MEMORY;
1423 }
1424
1425 error = rail_write_client_get_appid_req_order(s, getAppIdReq);
1426
1427 if (ERROR_SUCCESS != error)
1428 {
1429
1430 Stream_Free(s, TRUE);
1431 return error;
1432 }
1433 return rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ);
1434}
1435
1441UINT rail_send_client_langbar_info_order(railPlugin* rail,
1442 const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
1443{
1444 wStream* s = nullptr;
1445 UINT error = 0;
1446
1447 if (!rail || !langBarInfo)
1448 return ERROR_INVALID_PARAMETER;
1449
1450 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
1451 return ERROR_BAD_CONFIGURATION;
1452
1453 s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
1454
1455 if (!s)
1456 {
1457 WLog_ERR(TAG, "rail_pdu_init failed!");
1458 return CHANNEL_RC_NO_MEMORY;
1459 }
1460
1461 error = rail_write_langbar_info_order(s, langBarInfo);
1462
1463 if (ERROR_SUCCESS != error)
1464 {
1465
1466 Stream_Free(s, TRUE);
1467 return error;
1468 }
1469 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO);
1470}
1471
1472UINT rail_send_client_languageime_info_order(railPlugin* rail,
1473 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
1474{
1475 wStream* s = nullptr;
1476 UINT error = 0;
1477
1478 if (!rail || !langImeInfo)
1479 return ERROR_INVALID_PARAMETER;
1480
1481 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1482 return ERROR_BAD_CONFIGURATION;
1483
1484 s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH);
1485
1486 if (!s)
1487 {
1488 WLog_ERR(TAG, "rail_pdu_init failed!");
1489 return CHANNEL_RC_NO_MEMORY;
1490 }
1491
1492 error = rail_write_languageime_info_order(s, langImeInfo);
1493
1494 if (ERROR_SUCCESS != error)
1495 {
1496
1497 Stream_Free(s, TRUE);
1498 return error;
1499 }
1500 return rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO);
1501}
1502
1503UINT rail_send_client_compartment_info_order(railPlugin* rail,
1504 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
1505{
1506 wStream* s = nullptr;
1507 UINT error = 0;
1508
1509 if (!rail || !compartmentInfo)
1510 return ERROR_INVALID_PARAMETER;
1511
1512 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
1513 return ERROR_BAD_CONFIGURATION;
1514
1515 s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH);
1516
1517 if (!s)
1518 {
1519 WLog_ERR(TAG, "rail_pdu_init failed!");
1520 return CHANNEL_RC_NO_MEMORY;
1521 }
1522
1523 error = rail_write_compartment_info_order(s, compartmentInfo);
1524
1525 if (ERROR_SUCCESS != error)
1526 {
1527 Stream_Free(s, TRUE);
1528 return error;
1529 }
1530 return rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO);
1531}
1532
1533UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak)
1534{
1535 if (!rail || !cloak)
1536 return ERROR_INVALID_PARAMETER;
1537
1538 wStream* s = rail_pdu_init(5);
1539
1540 if (!s)
1541 {
1542 WLog_ERR(TAG, "rail_pdu_init failed!");
1543 return CHANNEL_RC_NO_MEMORY;
1544 }
1545
1546 Stream_Write_UINT32(s, cloak->windowId);
1547 Stream_Write_UINT8(s, cloak->cloak ? 1 : 0);
1548 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK);
1549}
1550
1551UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap)
1552{
1553 if (!rail)
1554 return ERROR_INVALID_PARAMETER;
1555
1556 /* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */
1557 if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0)
1558 {
1559 RAIL_WINDOW_MOVE_ORDER move = WINPR_C_ARRAY_INIT;
1560 move.top = snap->top;
1561 move.left = snap->left;
1562 move.right = snap->right;
1563 move.bottom = snap->bottom;
1564 move.windowId = snap->windowId;
1565 return rail_send_client_window_move_order(rail, &move);
1566 }
1567
1568 wStream* s = rail_pdu_init(12);
1569
1570 if (!s)
1571 {
1572 WLog_ERR(TAG, "rail_pdu_init failed!");
1573 return CHANNEL_RC_NO_MEMORY;
1574 }
1575
1576 Stream_Write_UINT32(s, snap->windowId);
1577 Stream_Write_INT16(s, snap->left);
1578 Stream_Write_INT16(s, snap->top);
1579 Stream_Write_INT16(s, snap->right);
1580 Stream_Write_INT16(s, snap->bottom);
1581 return rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE);
1582}
1583
1584UINT rail_send_client_text_scale_order(railPlugin* rail, UINT32 textScale)
1585{
1586 if (!rail)
1587 return ERROR_INVALID_PARAMETER;
1588
1589 wStream* s = rail_pdu_init(4);
1590
1591 if (!s)
1592 {
1593 WLog_ERR(TAG, "rail_pdu_init failed!");
1594 return CHANNEL_RC_NO_MEMORY;
1595 }
1596
1597 Stream_Write_UINT32(s, textScale);
1598 return rail_send_pdu(rail, s, TS_RAIL_ORDER_TEXTSCALEINFO);
1599}
1600
1601UINT rail_send_client_caret_blink_rate_order(railPlugin* rail, UINT32 rate)
1602{
1603 if (!rail)
1604 return ERROR_INVALID_PARAMETER;
1605
1606 wStream* s = rail_pdu_init(4);
1607
1608 if (!s)
1609 {
1610 WLog_ERR(TAG, "rail_pdu_init failed!");
1611 return CHANNEL_RC_NO_MEMORY;
1612 }
1613
1614 Stream_Write_UINT32(s, rate);
1615 return rail_send_pdu(rail, s, TS_RAIL_ORDER_CARETBLINKINFO);
1616}
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.