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
159 if (_wcsnlen(getAppidResp->applicationId, ARRAYSIZE(getAppidResp->applicationId)) >=
160 ARRAYSIZE(getAppidResp->applicationId))
161 return ERROR_INVALID_DATA;
162
163 return CHANNEL_RC_OK;
164}
165
171static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo)
172{
173 if (!s || !langbarInfo)
174 return ERROR_INVALID_PARAMETER;
175
176 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_LANGBAR_INFO_ORDER_LENGTH))
177 return ERROR_INVALID_DATA;
178
179 Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
180 return CHANNEL_RC_OK;
181}
182
183static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ORDER* clientStatus)
184{
185 if (!s || !clientStatus)
186 return ERROR_INVALID_PARAMETER;
187
188 Stream_Write_UINT32(s, clientStatus->flags); /* flags (4 bytes) */
189 return ERROR_SUCCESS;
190}
191
197static UINT rail_write_client_exec_order(wStream* s, UINT16 flags,
198 const RAIL_UNICODE_STRING* exeOrFile,
199 const RAIL_UNICODE_STRING* workingDir,
200 const RAIL_UNICODE_STRING* arguments)
201{
202 UINT error = 0;
203
204 if (!s || !exeOrFile || !workingDir || !arguments)
205 return ERROR_INVALID_PARAMETER;
206
207 /* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC)
208 * Check argument limits */
209 if ((exeOrFile->length > 520) || (workingDir->length > 520) || (arguments->length > 16000))
210 {
211 WLog_ERR(TAG,
212 "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%" PRIu16
213 " [max=520], WorkingDir=%" PRIu16 " [max=520], Arguments=%" PRIu16 " [max=16000]",
214 exeOrFile->length, workingDir->length, arguments->length);
215 return ERROR_BAD_ARGUMENTS;
216 }
217
218 Stream_Write_UINT16(s, flags); /* flags (2 bytes) */
219 Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */
220 Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */
221 Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */
222
223 if ((error = rail_write_unicode_string_value(s, exeOrFile)))
224 {
225 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
226 return error;
227 }
228
229 if ((error = rail_write_unicode_string_value(s, workingDir)))
230 {
231 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
232 return error;
233 }
234
235 if ((error = rail_write_unicode_string_value(s, arguments)))
236 {
237 WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error);
238 return error;
239 }
240
241 return error;
242}
243
244static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate)
245{
246 BYTE enabled = 0;
247
248 if (!s || !activate)
249 return ERROR_INVALID_PARAMETER;
250
251 Stream_Write_UINT32(s, activate->windowId); /* windowId (4 bytes) */
252 enabled = activate->enabled ? 1 : 0;
253 Stream_Write_UINT8(s, enabled); /* enabled (1 byte) */
254 return ERROR_SUCCESS;
255}
256
257static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER* sysmenu)
258{
259 if (!s || !sysmenu)
260 return ERROR_INVALID_PARAMETER;
261
262 Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */
263 Stream_Write_INT16(s, sysmenu->left); /* left (2 bytes) */
264 Stream_Write_INT16(s, sysmenu->top); /* top (2 bytes) */
265 return ERROR_SUCCESS;
266}
267
268static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND_ORDER* syscommand)
269{
270 if (!s || !syscommand)
271 return ERROR_INVALID_PARAMETER;
272
273 Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */
274 Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */
275 return ERROR_SUCCESS;
276}
277
278static UINT rail_write_client_notify_event_order(wStream* s,
279 const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
280{
281 if (!s || !notifyEvent)
282 return ERROR_INVALID_PARAMETER;
283
284 Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */
285 Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */
286 Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */
287 return ERROR_SUCCESS;
288}
289
290static UINT rail_write_client_window_move_order(wStream* s,
291 const RAIL_WINDOW_MOVE_ORDER* windowMove)
292{
293 if (!s || !windowMove)
294 return ERROR_INVALID_PARAMETER;
295
296 Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */
297 Stream_Write_INT16(s, windowMove->left); /* left (2 bytes) */
298 Stream_Write_INT16(s, windowMove->top); /* top (2 bytes) */
299 Stream_Write_INT16(s, windowMove->right); /* right (2 bytes) */
300 Stream_Write_INT16(s, windowMove->bottom); /* bottom (2 bytes) */
301 return ERROR_SUCCESS;
302}
303
304static UINT rail_write_client_get_appid_req_order(wStream* s,
305 const RAIL_GET_APPID_REQ_ORDER* getAppidReq)
306{
307 if (!s || !getAppidReq)
308 return ERROR_INVALID_PARAMETER;
309
310 Stream_Write_UINT32(s, getAppidReq->windowId); /* windowId (4 bytes) */
311 return ERROR_SUCCESS;
312}
313
314static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo)
315{
316 if (!s || !langbarInfo)
317 return ERROR_INVALID_PARAMETER;
318
319 Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* languageBarStatus (4 bytes) */
320 return ERROR_SUCCESS;
321}
322
323static UINT rail_write_languageime_info_order(wStream* s,
324 const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
325{
326 if (!s || !langImeInfo)
327 return ERROR_INVALID_PARAMETER;
328
329 Stream_Write_UINT32(s, langImeInfo->ProfileType);
330 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(UINT16, langImeInfo->LanguageID));
331 Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID));
332 Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID));
333 Stream_Write_UINT32(s, langImeInfo->KeyboardLayout);
334 return ERROR_SUCCESS;
335}
336
337static UINT rail_write_compartment_info_order(wStream* s,
338 const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
339{
340 if (!s || !compartmentInfo)
341 return ERROR_INVALID_PARAMETER;
342
343 Stream_Write_UINT32(s, compartmentInfo->ImeState);
344 Stream_Write_UINT32(s, compartmentInfo->ImeConvMode);
345 Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode);
346 Stream_Write_UINT32(s, compartmentInfo->KanaMode);
347 return ERROR_SUCCESS;
348}
349
355static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s)
356{
357 RailClientContext* context = rail_get_client_interface(rail);
358 RAIL_HANDSHAKE_ORDER serverHandshake = WINPR_C_ARRAY_INIT;
359 UINT error = 0;
360
361 if (!context || !s)
362 return ERROR_INVALID_PARAMETER;
363
364 if ((error = rail_read_handshake_order(s, &serverHandshake)))
365 {
366 WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error);
367 return error;
368 }
369
370 rail->channelBuildNumber = serverHandshake.buildNumber;
371
372 if (context->custom)
373 {
374 IFCALLRET(context->ServerHandshake, error, context, &serverHandshake);
375
376 if (error)
377 WLog_ERR(TAG, "context.ServerHandshake failed with error %" PRIu32 "", error);
378 }
379
380 return error;
381}
382
383static UINT rail_read_compartment_info_order(wStream* s,
384 RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
385{
386 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH))
387 return ERROR_INVALID_DATA;
388
389 Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */
390 Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */
391 Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */
392 Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */
393 return CHANNEL_RC_OK;
394}
395
396static UINT rail_recv_compartmentinfo_order(railPlugin* rail, wStream* s)
397{
398 RailClientContext* context = rail_get_client_interface(rail);
399 RAIL_COMPARTMENT_INFO_ORDER pdu = WINPR_C_ARRAY_INIT;
400 UINT error = 0;
401
402 if (!context || !s)
403 return ERROR_INVALID_PARAMETER;
404
405 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED))
406 return ERROR_BAD_CONFIGURATION;
407
408 if ((error = rail_read_compartment_info_order(s, &pdu)))
409 return error;
410
411 if (context->custom)
412 {
413 IFCALLRET(context->ClientCompartmentInfo, error, context, &pdu);
414
415 if (error)
416 WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error);
417 }
418
419 return error;
420}
421
422BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask)
423{
424 UINT32 supported = 0;
425 UINT32 masked = 0;
426
427 if (!context || !context->settings)
428 return FALSE;
429
430 const UINT32 level =
431 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportLevel);
432 const UINT32 mask =
433 freerdp_settings_get_uint32(context->settings, FreeRDP_RemoteApplicationSupportMask);
434 supported = level & mask;
435 masked = (supported & featureMask);
436
437 if (masked != featureMask)
438 {
439 char maskstr[256] = WINPR_C_ARRAY_INIT;
440 char actualstr[256] = WINPR_C_ARRAY_INIT;
441
442 WLog_WARN(TAG, "have %s, require %s",
443 freerdp_rail_support_flags_to_string(supported, actualstr, sizeof(actualstr)),
444 freerdp_rail_support_flags_to_string(featureMask, maskstr, sizeof(maskstr)));
445 return FALSE;
446 }
447
448 return TRUE;
449}
450
456static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s)
457{
458 RailClientContext* context = rail_get_client_interface(rail);
459 RAIL_HANDSHAKE_EX_ORDER serverHandshake = WINPR_C_ARRAY_INIT;
460 UINT error = 0;
461
462 if (!rail || !context || !s)
463 return ERROR_INVALID_PARAMETER;
464
465 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED))
466 return ERROR_BAD_CONFIGURATION;
467
468 if ((error = rail_read_handshake_ex_order(s, &serverHandshake)))
469 {
470 WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %" PRIu32 "!", error);
471 return error;
472 }
473
474 rail->channelBuildNumber = serverHandshake.buildNumber;
475 rail->channelFlags = serverHandshake.railHandshakeFlags;
476
477 {
478 char buffer[192] = WINPR_C_ARRAY_INIT;
479 WLog_DBG(TAG, "HandshakeFlags=%s [buildNumber=0x%08" PRIx32 "]",
480 rail_handshake_ex_flags_to_string(rail->channelFlags, buffer, sizeof(buffer)),
481 rail->channelBuildNumber);
482 }
483
484 if (context->custom)
485 {
486 IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake);
487
488 if (error)
489 WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %" PRIu32 "", error);
490 }
491
492 return error;
493}
494
500static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s)
501{
502 RailClientContext* context = rail_get_client_interface(rail);
503 RAIL_EXEC_RESULT_ORDER execResult = WINPR_C_ARRAY_INIT;
504 UINT error = 0;
505
506 if (!context || !s)
507 return ERROR_INVALID_PARAMETER;
508
509 if ((error = rail_read_server_exec_result_order(s, &execResult)))
510 {
511 WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %" PRIu32 "!", error);
512 goto fail;
513 }
514
515 if (context->custom)
516 {
517 IFCALLRET(context->ServerExecuteResult, error, context, &execResult);
518
519 if (error)
520 WLog_ERR(TAG, "context.ServerExecuteResult failed with error %" PRIu32 "", error);
521 }
522
523fail:
524 rail_unicode_string_free(&execResult.exeOrFile);
525 return error;
526}
527
533static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s)
534{
535 RailClientContext* context = rail_get_client_interface(rail);
536
537 if (!context || !s)
538 return ERROR_INVALID_PARAMETER;
539
540 const BOOL extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
541 RAIL_SYSPARAM_ORDER sysparam = WINPR_C_ARRAY_INIT;
542 UINT error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported);
543 if (error)
544 {
545 WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error);
546 goto fail;
547 }
548
549 if (context->custom)
550 {
551 IFCALLRET(context->ServerSystemParam, error, context, &sysparam);
552
553 if (error)
554 WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error);
555 }
556fail:
557 rail_unicode_string_free(&sysparam.highContrast.colorScheme);
558
559 return error;
560}
561
567static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s)
568{
569 RailClientContext* context = rail_get_client_interface(rail);
570 RAIL_MINMAXINFO_ORDER minMaxInfo = WINPR_C_ARRAY_INIT;
571 UINT error = 0;
572
573 if (!context || !s)
574 return ERROR_INVALID_PARAMETER;
575
576 if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo)))
577 {
578 WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error);
579 return error;
580 }
581
582 if (context->custom)
583 {
584 IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo);
585
586 if (error)
587 WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error);
588 }
589
590 return error;
591}
592
598static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s)
599{
600 RailClientContext* context = rail_get_client_interface(rail);
601 RAIL_LOCALMOVESIZE_ORDER localMoveSize = WINPR_C_ARRAY_INIT;
602 UINT error = 0;
603
604 if (!context || !s)
605 return ERROR_INVALID_PARAMETER;
606
607 if ((error = rail_read_server_localmovesize_order(s, &localMoveSize)))
608 {
609 WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error);
610 return error;
611 }
612
613 if (context->custom)
614 {
615 IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize);
616
617 if (error)
618 WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error);
619 }
620
621 return error;
622}
623
629static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s)
630{
631 RailClientContext* context = rail_get_client_interface(rail);
632 RAIL_GET_APPID_RESP_ORDER getAppIdResp = WINPR_C_ARRAY_INIT;
633 UINT error = 0;
634
635 if (!context || !s)
636 return ERROR_INVALID_PARAMETER;
637
638 if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp)))
639 {
640 WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!",
641 error);
642 return error;
643 }
644
645 if (context->custom)
646 {
647 IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp);
648
649 if (error)
650 WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error);
651 }
652
653 return error;
654}
655
661static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s)
662{
663 RailClientContext* context = rail_get_client_interface(rail);
664 RAIL_LANGBAR_INFO_ORDER langBarInfo = WINPR_C_ARRAY_INIT;
665 UINT error = 0;
666
667 if (!context)
668 return ERROR_INVALID_PARAMETER;
669
670 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED))
671 return ERROR_BAD_CONFIGURATION;
672
673 if ((error = rail_read_langbar_info_order(s, &langBarInfo)))
674 {
675 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
676 return error;
677 }
678
679 if (context->custom)
680 {
681 IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo);
682
683 if (error)
684 WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error);
685 }
686
687 return error;
688}
689
690static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo)
691{
692 if (!s || !taskbarInfo)
693 return ERROR_INVALID_PARAMETER;
694
695 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_TASKBAR_INFO_ORDER_LENGTH))
696 return ERROR_INVALID_DATA;
697
698 Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage);
699 Stream_Read_UINT32(s, taskbarInfo->WindowIdTab);
700 Stream_Read_UINT32(s, taskbarInfo->Body);
701 return CHANNEL_RC_OK;
702}
703
704static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s)
705{
706 RailClientContext* context = rail_get_client_interface(rail);
707 RAIL_TASKBAR_INFO_ORDER taskBarInfo = WINPR_C_ARRAY_INIT;
708 UINT error = 0;
709
710 if (!context)
711 return ERROR_INVALID_PARAMETER;
712
713 /* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO)
714 * server -> client message only supported if announced. */
715 if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED))
716 return ERROR_BAD_CONFIGURATION;
717
718 if ((error = rail_read_taskbar_info_order(s, &taskBarInfo)))
719 {
720 WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error);
721 return error;
722 }
723
724 if (context->custom)
725 {
726 IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo);
727
728 if (error)
729 WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error);
730 }
731
732 return error;
733}
734
735static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder)
736{
737 if (!s || !zorder)
738 return ERROR_INVALID_PARAMETER;
739
740 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_Z_ORDER_SYNC_ORDER_LENGTH))
741 return ERROR_INVALID_DATA;
742
743 Stream_Read_UINT32(s, zorder->windowIdMarker);
744 return CHANNEL_RC_OK;
745}
746
747static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s)
748{
749 RailClientContext* context = rail_get_client_interface(rail);
750 RAIL_ZORDER_SYNC zorder = WINPR_C_ARRAY_INIT;
751 UINT error = 0;
752
753 if (!context)
754 return ERROR_INVALID_PARAMETER;
755
756 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0)
757 return ERROR_BAD_CONFIGURATION;
758
759 if ((error = rail_read_zorder_sync_order(s, &zorder)))
760 {
761 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
762 return error;
763 }
764
765 if (context->custom)
766 {
767 IFCALLRET(context->ServerZOrderSync, error, context, &zorder);
768
769 if (error)
770 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
771 }
772
773 return error;
774}
775
776static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak)
777{
778 BYTE cloaked = 0;
779
780 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_CLOAK_ORDER_LENGTH))
781 return ERROR_INVALID_DATA;
782
783 Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */
784 Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */
785 cloak->cloak = (cloaked != 0);
786 return CHANNEL_RC_OK;
787}
788
789static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s)
790{
791 RailClientContext* context = rail_get_client_interface(rail);
792 RAIL_CLOAK cloak = WINPR_C_ARRAY_INIT;
793 UINT error = 0;
794
795 if (!context)
796 return ERROR_INVALID_PARAMETER;
797
798 /* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK)
799 * server -> client message only supported if announced. */
800 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0)
801 return ERROR_INVALID_DATA;
802
803 if ((error = rail_read_cloak_order(s, &cloak)))
804 {
805 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
806 return error;
807 }
808
809 if (context->custom)
810 {
811 IFCALLRET(context->ServerCloak, error, context, &cloak);
812
813 if (error)
814 WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error);
815 }
816
817 return error;
818}
819
820static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power)
821{
822 UINT32 active = 0;
823
824 if (!s || !power)
825 return ERROR_INVALID_PARAMETER;
826
827 if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH))
828 return ERROR_INVALID_DATA;
829
830 Stream_Read_UINT32(s, active);
831 power->active = active != 0;
832 return CHANNEL_RC_OK;
833}
834
835static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s)
836{
837 RailClientContext* context = rail_get_client_interface(rail);
838 RAIL_POWER_DISPLAY_REQUEST power = WINPR_C_ARRAY_INIT;
839 UINT error = 0;
840
841 if (!context)
842 return ERROR_INVALID_PARAMETER;
843
844 /* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST)
845 */
846 if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0)
847 return ERROR_BAD_CONFIGURATION;
848
849 if ((error = rail_read_power_display_request_order(s, &power)))
850 {
851 WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error);
852 return error;
853 }
854
855 if (context->custom)
856 {
857 IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power);
858
859 if (error)
860 WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error);
861 }
862
863 return error;
864}
865
866static UINT rail_read_get_application_id_extended_response_order(wStream* s,
868{
869 if (!s || !id)
870 return ERROR_INVALID_PARAMETER;
871
872 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
873 return ERROR_INVALID_DATA;
874
875 Stream_Read_UINT32(s, id->windowID);
876
877 if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID)))
878 return ERROR_INVALID_DATA;
879
880 if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID))
881 return ERROR_INVALID_DATA;
882
883 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
884 return ERROR_INVALID_DATA;
885
886 Stream_Read_UINT32(s, id->processId);
887
888 if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName)))
889 return ERROR_INVALID_DATA;
890
891 if (_wcsnlen(id->processImageName, ARRAYSIZE(id->processImageName)) >=
892 ARRAYSIZE(id->processImageName))
893 return ERROR_INVALID_DATA;
894
895 return CHANNEL_RC_OK;
896}
897
898static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s)
899{
900 RailClientContext* context = rail_get_client_interface(rail);
901 RAIL_GET_APPID_RESP_EX id = WINPR_C_ARRAY_INIT;
902 UINT error = 0;
903
904 if (!context)
905 return ERROR_INVALID_PARAMETER;
906
907 if ((error = rail_read_get_application_id_extended_response_order(s, &id)))
908 {
909 WLog_ERR(TAG,
910 "rail_read_get_application_id_extended_response_order failed with error %" PRIu32
911 "!",
912 error);
913 return error;
914 }
915
916 if (context->custom)
917 {
918 IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id);
919
920 if (error)
921 WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "",
922 error);
923 }
924
925 return error;
926}
927
928static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor)
929{
930 WINPR_ASSERT(pTextScaleFactor);
931
932 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
933 return ERROR_INVALID_DATA;
934
935 Stream_Read_UINT32(s, *pTextScaleFactor);
936 return CHANNEL_RC_OK;
937}
938
939static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s)
940{
941 RailClientContext* context = rail_get_client_interface(rail);
942 UINT32 TextScaleFactor = 0;
943 UINT error = 0;
944
945 if (!context)
946 return ERROR_INVALID_PARAMETER;
947
948 if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor)))
949 return error;
950
951 if (context->custom)
952 {
953 IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor);
954
955 if (error)
956 WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error);
957 }
958
959 return error;
960}
961
962static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate)
963{
964 WINPR_ASSERT(pCaretBlinkRate);
965
966 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
967 return ERROR_INVALID_DATA;
968
969 Stream_Read_UINT32(s, *pCaretBlinkRate);
970 return CHANNEL_RC_OK;
971}
972
973static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s)
974{
975 RailClientContext* context = rail_get_client_interface(rail);
976 UINT32 CaretBlinkRate = 0;
977 UINT error = 0;
978
979 if (!context)
980 return ERROR_INVALID_PARAMETER;
981 if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate)))
982 return error;
983
984 if (context->custom)
985 {
986 IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate);
987
988 if (error)
989 WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error);
990 }
991
992 return error;
993}
994
1000UINT rail_order_recv(LPVOID userdata, wStream* s)
1001{
1002 char buffer[128] = WINPR_C_ARRAY_INIT;
1003 railPlugin* rail = userdata;
1004 UINT16 orderType = 0;
1005 UINT16 orderLength = 0;
1006 UINT error = CHANNEL_RC_OK;
1007
1008 if (!rail || !s)
1009 {
1010 error = ERROR_INVALID_PARAMETER;
1011 goto fail;
1012 }
1013
1014 if ((error = rail_read_pdu_header(s, &orderType, &orderLength)))
1015 {
1016 WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error);
1017 error = ERROR_INVALID_DATA;
1018 goto fail;
1019 }
1020
1021 WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "",
1022 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength);
1023
1024 switch (orderType)
1025 {
1026 case TS_RAIL_ORDER_HANDSHAKE:
1027 error = rail_recv_handshake_order(rail, s);
1028 break;
1029
1030 case TS_RAIL_ORDER_COMPARTMENTINFO:
1031 error = rail_recv_compartmentinfo_order(rail, s);
1032 break;
1033
1034 case TS_RAIL_ORDER_HANDSHAKE_EX:
1035 error = rail_recv_handshake_ex_order(rail, s);
1036 break;
1037
1038 case TS_RAIL_ORDER_EXEC_RESULT:
1039 error = rail_recv_exec_result_order(rail, s);
1040 break;
1041
1042 case TS_RAIL_ORDER_SYSPARAM:
1043 error = rail_recv_server_sysparam_order(rail, s);
1044 break;
1045
1046 case TS_RAIL_ORDER_MINMAXINFO:
1047 error = rail_recv_server_minmaxinfo_order(rail, s);
1048 break;
1049
1050 case TS_RAIL_ORDER_LOCALMOVESIZE:
1051 error = rail_recv_server_localmovesize_order(rail, s);
1052 break;
1053
1054 case TS_RAIL_ORDER_GET_APPID_RESP:
1055 error = rail_recv_server_get_appid_resp_order(rail, s);
1056 break;
1057
1058 case TS_RAIL_ORDER_LANGBARINFO:
1059 error = rail_recv_langbar_info_order(rail, s);
1060 break;
1061
1062 case TS_RAIL_ORDER_TASKBARINFO:
1063 error = rail_recv_taskbar_info_order(rail, s);
1064 break;
1065
1066 case TS_RAIL_ORDER_ZORDER_SYNC:
1067 error = rail_recv_zorder_sync_order(rail, s);
1068 break;
1069
1070 case TS_RAIL_ORDER_CLOAK:
1071 error = rail_recv_cloak_order(rail, s);
1072 break;
1073
1074 case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
1075 error = rail_recv_power_display_request_order(rail, s);
1076 break;
1077
1078 case TS_RAIL_ORDER_GET_APPID_RESP_EX:
1079 error = rail_recv_get_application_id_extended_response_order(rail, s);
1080 break;
1081
1082 case TS_RAIL_ORDER_TEXTSCALEINFO:
1083 error = rail_recv_textscaleinfo_order(rail, s);
1084 break;
1085
1086 case TS_RAIL_ORDER_CARETBLINKINFO:
1087 error = rail_recv_caretblinkinfo_order(rail, s);
1088 break;
1089
1090 default:
1091 WLog_ERR(TAG, "Unknown RAIL PDU %s received.",
1092 rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)));
1093 return ERROR_INVALID_DATA;
1094 }
1095
1096 if (error == ERROR_BAD_CONFIGURATION)
1097 {
1098 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1099 WLog_Print(rail->log, WLOG_WARN,
1100 "%s - SERVER BUG: The support for this feature was not announced!",
1101 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)));
1102
1103 if (freerdp_settings_get_bool(rail->rdpcontext->settings,
1104 FreeRDP_AllowUnanouncedOrdersFromServer))
1105 error = CHANNEL_RC_OK;
1106 }
1107 if (error != CHANNEL_RC_OK)
1108 {
1109 char ebuffer[128] = WINPR_C_ARRAY_INIT;
1110 WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "",
1111 rail_get_order_type_string_full(orderType, ebuffer, sizeof(ebuffer)),
1112 orderLength);
1113 }
1114
1115fail:
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.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.