26#include <freerdp/config.h> 
   30#include <freerdp/types.h> 
   31#include <freerdp/constants.h> 
   32#include <freerdp/freerdp.h> 
   34#include "rail_orders.h" 
   37#include "../../../channels/client/addin.h" 
   39RailClientContext* rail_get_client_interface(
railPlugin* rail)
 
   41  RailClientContext* pInterface = NULL;
 
   46  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
 
   62    return CHANNEL_RC_BAD_INIT_HANDLE;
 
   65  status = rail->channelEntryPoints.pVirtualChannelWriteEx(
 
   66      rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
 
   68  if (status != CHANNEL_RC_OK)
 
   71    WLog_ERR(TAG, 
"pVirtualChannelWriteEx failed with %s [%08" PRIX32 
"]",
 
   72             WTSErrorToString(status), status);
 
   87    Stream_Free(src, TRUE);
 
   88    return ERROR_INVALID_PARAMETER;
 
   91  return rail_send(rail, src);
 
  103static UINT rail_client_execute(RailClientContext* context, 
const RAIL_EXEC_ORDER* exec)
 
  105  const char* exeOrFile = NULL;
 
  113  if (!context || !exec)
 
  114    return ERROR_INVALID_PARAMETER;
 
  117  exeOrFile = exec->RemoteApplicationProgram;
 
  121    return ERROR_INVALID_PARAMETER;
 
  123  if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
 
  125      !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
 
  127      !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
 
  129    error = ERROR_INTERNAL_ERROR;
 
  131    error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
 
  133  free(ruExeOrFile.string);
 
  134  free(ruWorkingDir.string);
 
  135  free(ruArguments.string);
 
  144static UINT rail_client_activate(RailClientContext* context, 
const RAIL_ACTIVATE_ORDER* activate)
 
  148  if (!context || !activate)
 
  149    return ERROR_INVALID_PARAMETER;
 
  152  return rail_send_client_activate_order(rail, activate);
 
  160static UINT rail_send_client_sysparam(RailClientContext* context, 
RAIL_SYSPARAM_ORDER* sysparam)
 
  163  size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
 
  166  BOOL extendedSpiSupported = 0;
 
  168  if (!context || !sysparam)
 
  169    return ERROR_INVALID_PARAMETER;
 
  173  switch (sysparam->param)
 
  175    case SPI_SET_DRAG_FULL_WINDOWS:
 
  176    case SPI_SET_KEYBOARD_CUES:
 
  177    case SPI_SET_KEYBOARD_PREF:
 
  178    case SPI_SET_MOUSE_BUTTON_SWAP:
 
  182    case SPI_SET_WORK_AREA:
 
  183    case SPI_DISPLAY_CHANGE:
 
  184    case SPI_TASKBAR_POS:
 
  188    case SPI_SET_HIGH_CONTRAST:
 
  189      length += sysparam->highContrast.colorSchemeLength + 10;
 
  192    case SPI_SETFILTERKEYS:
 
  196    case SPI_SETSTICKYKEYS:
 
  197    case SPI_SETCARETWIDTH:
 
  198    case SPI_SETTOGGLEKEYS:
 
  203      return ERROR_BAD_ARGUMENTS;
 
  206  s = rail_pdu_init(length);
 
  210    WLog_ERR(TAG, 
"rail_pdu_init failed!");
 
  211    return CHANNEL_RC_NO_MEMORY;
 
  214  extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
 
  215  if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
 
  217    WLog_ERR(TAG, 
"rail_write_client_sysparam_order failed with error %" PRIu32 
"!", error);
 
  218    Stream_Free(s, TRUE);
 
  222  return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
 
  230static UINT rail_client_system_param(RailClientContext* context,
 
  233  UINT error = CHANNEL_RC_OK;
 
  236  if (!context || !sysInParam)
 
  237    return ERROR_INVALID_PARAMETER;
 
  239  sysparam = *sysInParam;
 
  241  if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
 
  243    sysparam.param = SPI_SET_HIGH_CONTRAST;
 
  245    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  247      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  252  if (sysparam.params & SPI_MASK_TASKBAR_POS)
 
  254    sysparam.param = SPI_TASKBAR_POS;
 
  256    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  258      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  263  if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
 
  265    sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
 
  267    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  269      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  274  if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
 
  276    sysparam.param = SPI_SET_KEYBOARD_PREF;
 
  278    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  280      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  285  if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
 
  287    sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
 
  289    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  291      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  296  if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
 
  298    sysparam.param = SPI_SET_KEYBOARD_CUES;
 
  300    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  302      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  307  if (sysparam.params & SPI_MASK_SET_WORK_AREA)
 
  309    sysparam.param = SPI_SET_WORK_AREA;
 
  311    if ((error = rail_send_client_sysparam(context, &sysparam)))
 
  313      WLog_ERR(TAG, 
"rail_send_client_sysparam failed with error %" PRIu32 
"!", error);
 
  326static UINT rail_client_system_command(RailClientContext* context,
 
  331  if (!context || !syscommand)
 
  332    return ERROR_INVALID_PARAMETER;
 
  335  return rail_send_client_syscommand_order(rail, syscommand);
 
  343static UINT rail_client_handshake(RailClientContext* context, 
const RAIL_HANDSHAKE_ORDER* handshake)
 
  347  if (!context || !handshake)
 
  348    return ERROR_INVALID_PARAMETER;
 
  351  return rail_send_handshake_order(rail, handshake);
 
  359static UINT rail_client_notify_event(RailClientContext* context,
 
  364  if (!context || !notifyEvent)
 
  365    return ERROR_INVALID_PARAMETER;
 
  368  return rail_send_client_notify_event_order(rail, notifyEvent);
 
  376static UINT rail_client_window_move(RailClientContext* context,
 
  381  if (!context || !windowMove)
 
  382    return ERROR_INVALID_PARAMETER;
 
  385  return rail_send_client_window_move_order(rail, windowMove);
 
  393static UINT rail_client_information(RailClientContext* context,
 
  398  if (!context || !clientStatus)
 
  399    return ERROR_INVALID_PARAMETER;
 
  402  return rail_send_client_status_order(rail, clientStatus);
 
  410static UINT rail_client_system_menu(RailClientContext* context, 
const RAIL_SYSMENU_ORDER* sysmenu)
 
  414  if (!context || !sysmenu)
 
  415    return ERROR_INVALID_PARAMETER;
 
  418  return rail_send_client_sysmenu_order(rail, sysmenu);
 
  426static UINT rail_client_language_bar_info(RailClientContext* context,
 
  431  if (!context || !langBarInfo)
 
  432    return ERROR_INVALID_PARAMETER;
 
  435  return rail_send_client_langbar_info_order(rail, langBarInfo);
 
  438static UINT rail_client_language_ime_info(RailClientContext* context,
 
  443  if (!context || !langImeInfo)
 
  444    return ERROR_INVALID_PARAMETER;
 
  447  return rail_send_client_languageime_info_order(rail, langImeInfo);
 
  455static UINT rail_client_get_appid_request(RailClientContext* context,
 
  460  if (!context || !getAppIdReq || !context->handle)
 
  461    return ERROR_INVALID_PARAMETER;
 
  464  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
 
  467static UINT rail_client_compartment_info(RailClientContext* context,
 
  472  if (!context || !compartmentInfo || !context->handle)
 
  473    return ERROR_INVALID_PARAMETER;
 
  476  return rail_send_client_compartment_info_order(rail, compartmentInfo);
 
  479static UINT rail_client_cloak(RailClientContext* context, 
const RAIL_CLOAK* cloak)
 
  483  if (!context || !cloak || !context->handle)
 
  484    return ERROR_INVALID_PARAMETER;
 
  487  return rail_send_client_cloak_order(rail, cloak);
 
  490static UINT rail_client_snap_arrange(RailClientContext* context, 
const RAIL_SNAP_ARRANGE* snap)
 
  494  if (!context || !snap || !context->handle)
 
  495    return ERROR_INVALID_PARAMETER;
 
  498  return rail_send_client_snap_arrange_order(rail, snap);
 
  501static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
 
  503  if (!context || !context->handle)
 
  504    return ERROR_INVALID_PARAMETER;
 
  507  return rail_send_client_text_scale_order(rail, textScale);
 
  510static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
 
  512  if (!context || !context->handle)
 
  513    return ERROR_INVALID_PARAMETER;
 
  516  return rail_send_client_caret_blink_rate_order(rail, rate);
 
  519static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
 
  520                                                         UINT event, LPVOID pData,
 
  521                                                         UINT32 dataLength, UINT32 totalLength,
 
  524  UINT error = CHANNEL_RC_OK;
 
  529    case CHANNEL_EVENT_DATA_RECEIVED:
 
  530      if (!rail || (rail->OpenHandle != openHandle))
 
  532        WLog_ERR(TAG, 
"error no match");
 
  536      if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
 
  537                                               totalLength, dataFlags)))
 
  540                 "rail_virtual_channel_event_data_received" 
  541                 " failed with error %" PRIu32 
"!",
 
  547    case CHANNEL_EVENT_WRITE_CANCELLED:
 
  548    case CHANNEL_EVENT_WRITE_COMPLETE:
 
  551      Stream_Free(s, TRUE);
 
  555    case CHANNEL_EVENT_USER:
 
  561  if (error && rail && rail->rdpcontext)
 
  562    setChannelError(rail->rdpcontext, error,
 
  563                    "rail_virtual_channel_open_event reported an error");
 
  571static UINT rail_virtual_channel_event_connected(
railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
 
  572                                                 WINPR_ATTR_UNUSED UINT32 dataLength)
 
  574  RailClientContext* context = rail_get_client_interface(rail);
 
  575  UINT status = CHANNEL_RC_OK;
 
  581    IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
 
  583    if (status != CHANNEL_RC_OK)
 
  584      WLog_ERR(TAG, 
"context->OnOpen failed with %s [%08" PRIX32 
"]",
 
  585               WTSErrorToString(status), status);
 
  587  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
 
  588                                                   RAIL_SVC_CHANNEL_NAME);
 
  589  if (!rail->MsgsHandle)
 
  590    return ERROR_INTERNAL_ERROR;
 
  592  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
 
  593                                                        rail->channelDef.name,
 
  594                                                        rail_virtual_channel_open_event_ex);
 
  602static UINT rail_virtual_channel_event_disconnected(
railPlugin* rail)
 
  606  channel_client_quit_handler(rail->MsgsHandle);
 
  607  if (rail->OpenHandle == 0)
 
  608    return CHANNEL_RC_OK;
 
  610  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
 
  611  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
 
  613  if (CHANNEL_RC_OK != rc)
 
  615    WLog_ERR(TAG, 
"pVirtualChannelCloseEx failed with %s [%08" PRIX32 
"]", WTSErrorToString(rc),
 
  620  rail->OpenHandle = 0;
 
  622  return CHANNEL_RC_OK;
 
  625static void rail_virtual_channel_event_terminated(
railPlugin* rail)
 
  627  rail->InitHandle = 0;
 
  632static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
 
  633                                                         UINT event, LPVOID pData, UINT dataLength)
 
  635  UINT error = CHANNEL_RC_OK;
 
  638  if (!rail || (rail->InitHandle != pInitHandle))
 
  640    WLog_ERR(TAG, 
"error no match");
 
  646    case CHANNEL_EVENT_CONNECTED:
 
  647      if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
 
  648        WLog_ERR(TAG, 
"rail_virtual_channel_event_connected failed with error %" PRIu32 
"!",
 
  653    case CHANNEL_EVENT_DISCONNECTED:
 
  654      if ((error = rail_virtual_channel_event_disconnected(rail)))
 
  656                 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 
"!",
 
  661    case CHANNEL_EVENT_TERMINATED:
 
  662      rail_virtual_channel_event_terminated(rail);
 
  665    case CHANNEL_EVENT_ATTACHED:
 
  666    case CHANNEL_EVENT_DETACHED:
 
  671  if (error && rail->rdpcontext)
 
  672    setChannelError(rail->rdpcontext, error,
 
  673                    "rail_virtual_channel_init_event_ex reported an error");
 
  677#define VirtualChannelEntryEx rail_VirtualChannelEntryEx 
  679FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
 
  684  RailClientContext* context = NULL;
 
  686  BOOL isFreerdp = FALSE;
 
  691    WLog_ERR(TAG, 
"calloc failed!");
 
  696  rail->sendHandshake = TRUE;
 
  697  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
 
  698                             CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
 
  699  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
 
  703      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
 
  705    context = (RailClientContext*)calloc(1, 
sizeof(RailClientContext));
 
  709      WLog_ERR(TAG, 
"calloc failed!");
 
  714    context->handle = (
void*)rail;
 
  715    context->custom = NULL;
 
  716    context->ClientExecute = rail_client_execute;
 
  717    context->ClientActivate = rail_client_activate;
 
  718    context->ClientSystemParam = rail_client_system_param;
 
  719    context->ClientSystemCommand = rail_client_system_command;
 
  720    context->ClientHandshake = rail_client_handshake;
 
  721    context->ClientNotifyEvent = rail_client_notify_event;
 
  722    context->ClientWindowMove = rail_client_window_move;
 
  723    context->ClientInformation = rail_client_information;
 
  724    context->ClientSystemMenu = rail_client_system_menu;
 
  725    context->ClientLanguageBarInfo = rail_client_language_bar_info;
 
  726    context->ClientLanguageIMEInfo = rail_client_language_ime_info;
 
  727    context->ClientGetAppIdRequest = rail_client_get_appid_request;
 
  728    context->ClientSnapArrange = rail_client_snap_arrange;
 
  729    context->ClientCloak = rail_client_cloak;
 
  730    context->ClientCompartmentInfo = rail_client_compartment_info;
 
  731    context->ClientTextScale = rail_client_text_scale;
 
  732    context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
 
  733    rail->rdpcontext = pEntryPointsEx->context;
 
  734    rail->context = context;
 
  738  rail->log = WLog_Get(
"com.freerdp.channels.rail.client");
 
  739  WLog_Print(rail->log, WLOG_DEBUG, 
"VirtualChannelEntryEx");
 
  741  rail->InitHandle = pInitHandle;
 
  742  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
 
  743      rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
 
  744      rail_virtual_channel_init_event_ex);
 
  746  if (CHANNEL_RC_OK != rc)
 
  748    WLog_ERR(TAG, 
"failed with %s [%08" PRIX32 
"]", WTSErrorToString(rc), rc);
 
  752  rail->channelEntryPoints.pInterface = context;