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