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