FreeRDP
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 
35 static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask);
36 
42 UINT 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 
67 static 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 
89 static 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 
114 static 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 
139 static 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 
160 static 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 
172 static 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 
186 static 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 
233 static 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 
246 static 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 
257 static 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 
267 static 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 
279 static 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 
293 static 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 
303 static 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 
312 static 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 
326 static 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 
344 static 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 
382 static 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 
395 static 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 
421 BOOL 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 
455 static 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 
511 static 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 
534 fail:
535  free(execResult.exeOrFile.string);
536  return error;
537 }
538 
544 static 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 
577 static 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 
608 static 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 
639 static 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 
671 static 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 
700 static 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 
714 static 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 
745 static 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 
757 static 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 
786 static 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 
799 static 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 
830 static 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 
845 static 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 
876 static 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 
908 static 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 
938 static 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 
949 static 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 
972 static 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 
983 static 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 
1010 UINT 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 
1119 UINT 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 
1141 UINT 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 
1163 UINT 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 
1197 UINT 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 
1226 out:
1227  Stream_Free(s, TRUE);
1228  return error;
1229 }
1230 
1236 UINT 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 
1269 UINT 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 
1302 UINT 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 
1335 UINT 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 
1369 UINT 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 
1402 UINT 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 
1435 UINT 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 
1466 UINT 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 
1497 UINT 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 
1527 UINT 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 
1545 UINT 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 
1578 UINT 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 
1595 UINT 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.