Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/channels/rail/client/rail_main.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RAIL Virtual Channel Plugin
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
7
 * Copyright 2011 Vic Lee
8
 * Copyright 2015 Thincast Technologies GmbH
9
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
11
 * Copyright 2017 Thincast Technologies GmbH
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 *     http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25
26
#include <freerdp/config.h>
27
28
#include <winpr/crt.h>
29
30
#include <freerdp/types.h>
31
#include <freerdp/constants.h>
32
#include <freerdp/freerdp.h>
33
34
#include "rail_orders.h"
35
#include "rail_main.h"
36
37
#include "../../../channels/client/addin.h"
38
39
RailClientContext* rail_get_client_interface(railPlugin* rail)
40
0
{
41
0
  RailClientContext* pInterface = NULL;
42
43
0
  if (!rail)
44
0
    return NULL;
45
46
0
  pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
47
0
  return pInterface;
48
0
}
49
50
/**
51
 * Function description
52
 *
53
 * @return 0 on success, otherwise a Win32 error code
54
 */
55
static UINT rail_send(railPlugin* rail, wStream* s)
56
0
{
57
0
  UINT status = 0;
58
59
0
  if (!rail)
60
0
  {
61
0
    Stream_Free(s, TRUE);
62
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
63
0
  }
64
65
0
  status = rail->channelEntryPoints.pVirtualChannelWriteEx(
66
0
      rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
67
68
0
  if (status != CHANNEL_RC_OK)
69
0
  {
70
0
    Stream_Free(s, TRUE);
71
0
    WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
72
0
             WTSErrorToString(status), status);
73
0
  }
74
75
0
  return status;
76
0
}
77
78
/**
79
 * Function description
80
 *
81
 * @return 0 on success, otherwise a Win32 error code
82
 */
83
UINT rail_send_channel_data(railPlugin* rail, wStream* src)
84
0
{
85
0
  if (!rail || !src)
86
0
  {
87
0
    Stream_Free(src, TRUE);
88
0
    return ERROR_INVALID_PARAMETER;
89
0
  }
90
91
0
  return rail_send(rail, src);
92
0
}
93
94
/**
95
 * Callback Interface
96
 */
97
98
/**
99
 * Function description
100
 *
101
 * @return 0 on success, otherwise a Win32 error code
102
 */
103
static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec)
104
0
{
105
0
  const char* exeOrFile = NULL;
106
0
  UINT error = 0;
107
0
  railPlugin* rail = NULL;
108
0
  UINT16 flags = 0;
109
0
  RAIL_UNICODE_STRING ruExeOrFile = { 0 };
110
0
  RAIL_UNICODE_STRING ruWorkingDir = { 0 };
111
0
  RAIL_UNICODE_STRING ruArguments = { 0 };
112
113
0
  if (!context || !exec)
114
0
    return ERROR_INVALID_PARAMETER;
115
116
0
  rail = (railPlugin*)context->handle;
117
0
  exeOrFile = exec->RemoteApplicationProgram;
118
0
  flags = exec->flags;
119
120
0
  if (!exeOrFile)
121
0
    return ERROR_INVALID_PARAMETER;
122
123
0
  if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
124
0
                                  &ruExeOrFile) || /* RemoteApplicationProgram */
125
0
      !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
126
0
                                  &ruWorkingDir) || /* ShellWorkingDirectory */
127
0
      !utf8_string_to_rail_string(exec->RemoteApplicationArguments,
128
0
                                  &ruArguments)) /* RemoteApplicationCmdLine */
129
0
    error = ERROR_INTERNAL_ERROR;
130
0
  else
131
0
    error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
132
133
0
  free(ruExeOrFile.string);
134
0
  free(ruWorkingDir.string);
135
0
  free(ruArguments.string);
136
0
  return error;
137
0
}
138
139
/**
140
 * Function description
141
 *
142
 * @return 0 on success, otherwise a Win32 error code
143
 */
144
static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate)
145
0
{
146
0
  railPlugin* rail = NULL;
147
148
0
  if (!context || !activate)
149
0
    return ERROR_INVALID_PARAMETER;
150
151
0
  rail = (railPlugin*)context->handle;
152
0
  return rail_send_client_activate_order(rail, activate);
153
0
}
154
155
/**
156
 * Function description
157
 *
158
 * @return 0 on success, otherwise a Win32 error code
159
 */
160
static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam)
161
0
{
162
0
  wStream* s = NULL;
163
0
  size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
164
0
  railPlugin* rail = NULL;
165
0
  UINT error = 0;
166
0
  BOOL extendedSpiSupported = 0;
167
168
0
  if (!context || !sysparam)
169
0
    return ERROR_INVALID_PARAMETER;
170
171
0
  rail = (railPlugin*)context->handle;
172
173
0
  switch (sysparam->param)
174
0
  {
175
0
    case SPI_SET_DRAG_FULL_WINDOWS:
176
0
    case SPI_SET_KEYBOARD_CUES:
177
0
    case SPI_SET_KEYBOARD_PREF:
178
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
179
0
      length += 1;
180
0
      break;
181
182
0
    case SPI_SET_WORK_AREA:
183
0
    case SPI_DISPLAY_CHANGE:
184
0
    case SPI_TASKBAR_POS:
185
0
      length += 8;
186
0
      break;
187
188
0
    case SPI_SET_HIGH_CONTRAST:
189
0
      length += sysparam->highContrast.colorSchemeLength + 10;
190
0
      break;
191
192
0
    case SPI_SETFILTERKEYS:
193
0
      length += 20;
194
0
      break;
195
196
0
    case SPI_SETSTICKYKEYS:
197
0
    case SPI_SETCARETWIDTH:
198
0
    case SPI_SETTOGGLEKEYS:
199
0
      length += 4;
200
0
      break;
201
202
0
    default:
203
0
      return ERROR_BAD_ARGUMENTS;
204
0
  }
205
206
0
  s = rail_pdu_init(length);
207
208
0
  if (!s)
209
0
  {
210
0
    WLog_ERR(TAG, "rail_pdu_init failed!");
211
0
    return CHANNEL_RC_NO_MEMORY;
212
0
  }
213
214
0
  extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
215
0
  if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
216
0
  {
217
0
    WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
218
0
    Stream_Free(s, TRUE);
219
0
    return error;
220
0
  }
221
222
0
  return rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM);
223
0
}
224
225
/**
226
 * Function description
227
 *
228
 * @return 0 on success, otherwise a Win32 error code
229
 */
230
static UINT rail_client_system_param(RailClientContext* context,
231
                                     const RAIL_SYSPARAM_ORDER* sysInParam)
232
0
{
233
0
  UINT error = CHANNEL_RC_OK;
234
0
  RAIL_SYSPARAM_ORDER sysparam;
235
236
0
  if (!context || !sysInParam)
237
0
    return ERROR_INVALID_PARAMETER;
238
239
0
  sysparam = *sysInParam;
240
241
0
  if (sysparam.params & SPI_MASK_SET_HIGH_CONTRAST)
242
0
  {
243
0
    sysparam.param = SPI_SET_HIGH_CONTRAST;
244
245
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
246
0
    {
247
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
248
0
      return error;
249
0
    }
250
0
  }
251
252
0
  if (sysparam.params & SPI_MASK_TASKBAR_POS)
253
0
  {
254
0
    sysparam.param = SPI_TASKBAR_POS;
255
256
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
257
0
    {
258
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
259
0
      return error;
260
0
    }
261
0
  }
262
263
0
  if (sysparam.params & SPI_MASK_SET_MOUSE_BUTTON_SWAP)
264
0
  {
265
0
    sysparam.param = SPI_SET_MOUSE_BUTTON_SWAP;
266
267
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
268
0
    {
269
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
270
0
      return error;
271
0
    }
272
0
  }
273
274
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_PREF)
275
0
  {
276
0
    sysparam.param = SPI_SET_KEYBOARD_PREF;
277
278
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
279
0
    {
280
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
281
0
      return error;
282
0
    }
283
0
  }
284
285
0
  if (sysparam.params & SPI_MASK_SET_DRAG_FULL_WINDOWS)
286
0
  {
287
0
    sysparam.param = SPI_SET_DRAG_FULL_WINDOWS;
288
289
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
290
0
    {
291
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
292
0
      return error;
293
0
    }
294
0
  }
295
296
0
  if (sysparam.params & SPI_MASK_SET_KEYBOARD_CUES)
297
0
  {
298
0
    sysparam.param = SPI_SET_KEYBOARD_CUES;
299
300
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
301
0
    {
302
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
303
0
      return error;
304
0
    }
305
0
  }
306
307
0
  if (sysparam.params & SPI_MASK_SET_WORK_AREA)
308
0
  {
309
0
    sysparam.param = SPI_SET_WORK_AREA;
310
311
0
    if ((error = rail_send_client_sysparam(context, &sysparam)))
312
0
    {
313
0
      WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
314
0
      return error;
315
0
    }
316
0
  }
317
318
0
  return error;
319
0
}
320
321
/**
322
 * Function description
323
 *
324
 * @return 0 on success, otherwise a Win32 error code
325
 */
326
static UINT rail_client_system_command(RailClientContext* context,
327
                                       const RAIL_SYSCOMMAND_ORDER* syscommand)
328
0
{
329
0
  railPlugin* rail = NULL;
330
331
0
  if (!context || !syscommand)
332
0
    return ERROR_INVALID_PARAMETER;
333
334
0
  rail = (railPlugin*)context->handle;
335
0
  return rail_send_client_syscommand_order(rail, syscommand);
336
0
}
337
338
/**
339
 * Function description
340
 *
341
 * @return 0 on success, otherwise a Win32 error code
342
 */
343
static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
344
0
{
345
0
  railPlugin* rail = NULL;
346
347
0
  if (!context || !handshake)
348
0
    return ERROR_INVALID_PARAMETER;
349
350
0
  rail = (railPlugin*)context->handle;
351
0
  return rail_send_handshake_order(rail, handshake);
352
0
}
353
354
/**
355
 * Function description
356
 *
357
 * @return 0 on success, otherwise a Win32 error code
358
 */
359
static UINT rail_client_notify_event(RailClientContext* context,
360
                                     const RAIL_NOTIFY_EVENT_ORDER* notifyEvent)
361
0
{
362
0
  railPlugin* rail = NULL;
363
364
0
  if (!context || !notifyEvent)
365
0
    return ERROR_INVALID_PARAMETER;
366
367
0
  rail = (railPlugin*)context->handle;
368
0
  return rail_send_client_notify_event_order(rail, notifyEvent);
369
0
}
370
371
/**
372
 * Function description
373
 *
374
 * @return 0 on success, otherwise a Win32 error code
375
 */
376
static UINT rail_client_window_move(RailClientContext* context,
377
                                    const RAIL_WINDOW_MOVE_ORDER* windowMove)
378
0
{
379
0
  railPlugin* rail = NULL;
380
381
0
  if (!context || !windowMove)
382
0
    return ERROR_INVALID_PARAMETER;
383
384
0
  rail = (railPlugin*)context->handle;
385
0
  return rail_send_client_window_move_order(rail, windowMove);
386
0
}
387
388
/**
389
 * Function description
390
 *
391
 * @return 0 on success, otherwise a Win32 error code
392
 */
393
static UINT rail_client_information(RailClientContext* context,
394
                                    const RAIL_CLIENT_STATUS_ORDER* clientStatus)
395
0
{
396
0
  railPlugin* rail = NULL;
397
398
0
  if (!context || !clientStatus)
399
0
    return ERROR_INVALID_PARAMETER;
400
401
0
  rail = (railPlugin*)context->handle;
402
0
  return rail_send_client_status_order(rail, clientStatus);
403
0
}
404
405
/**
406
 * Function description
407
 *
408
 * @return 0 on success, otherwise a Win32 error code
409
 */
410
static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
411
0
{
412
0
  railPlugin* rail = NULL;
413
414
0
  if (!context || !sysmenu)
415
0
    return ERROR_INVALID_PARAMETER;
416
417
0
  rail = (railPlugin*)context->handle;
418
0
  return rail_send_client_sysmenu_order(rail, sysmenu);
419
0
}
420
421
/**
422
 * Function description
423
 *
424
 * @return 0 on success, otherwise a Win32 error code
425
 */
426
static UINT rail_client_language_bar_info(RailClientContext* context,
427
                                          const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
428
0
{
429
0
  railPlugin* rail = NULL;
430
431
0
  if (!context || !langBarInfo)
432
0
    return ERROR_INVALID_PARAMETER;
433
434
0
  rail = (railPlugin*)context->handle;
435
0
  return rail_send_client_langbar_info_order(rail, langBarInfo);
436
0
}
437
438
static UINT rail_client_language_ime_info(RailClientContext* context,
439
                                          const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
440
0
{
441
0
  railPlugin* rail = NULL;
442
443
0
  if (!context || !langImeInfo)
444
0
    return ERROR_INVALID_PARAMETER;
445
446
0
  rail = (railPlugin*)context->handle;
447
0
  return rail_send_client_languageime_info_order(rail, langImeInfo);
448
0
}
449
450
/**
451
 * Function description
452
 *
453
 * @return 0 on success, otherwise a Win32 error code
454
 */
455
static UINT rail_client_get_appid_request(RailClientContext* context,
456
                                          const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
457
0
{
458
0
  railPlugin* rail = NULL;
459
460
0
  if (!context || !getAppIdReq || !context->handle)
461
0
    return ERROR_INVALID_PARAMETER;
462
463
0
  rail = (railPlugin*)context->handle;
464
0
  return rail_send_client_get_appid_req_order(rail, getAppIdReq);
465
0
}
466
467
static UINT rail_client_compartment_info(RailClientContext* context,
468
                                         const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
469
0
{
470
0
  railPlugin* rail = NULL;
471
472
0
  if (!context || !compartmentInfo || !context->handle)
473
0
    return ERROR_INVALID_PARAMETER;
474
475
0
  rail = (railPlugin*)context->handle;
476
0
  return rail_send_client_compartment_info_order(rail, compartmentInfo);
477
0
}
478
479
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
480
0
{
481
0
  railPlugin* rail = NULL;
482
483
0
  if (!context || !cloak || !context->handle)
484
0
    return ERROR_INVALID_PARAMETER;
485
486
0
  rail = (railPlugin*)context->handle;
487
0
  return rail_send_client_cloak_order(rail, cloak);
488
0
}
489
490
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
491
0
{
492
0
  railPlugin* rail = NULL;
493
494
0
  if (!context || !snap || !context->handle)
495
0
    return ERROR_INVALID_PARAMETER;
496
497
0
  rail = (railPlugin*)context->handle;
498
0
  return rail_send_client_snap_arrange_order(rail, snap);
499
0
}
500
501
static UINT rail_client_text_scale(RailClientContext* context, UINT32 textScale)
502
0
{
503
0
  if (!context || !context->handle)
504
0
    return ERROR_INVALID_PARAMETER;
505
506
0
  railPlugin* rail = (railPlugin*)context->handle;
507
0
  return rail_send_client_text_scale_order(rail, textScale);
508
0
}
509
510
static UINT rail_client_caret_blink_rate(RailClientContext* context, UINT32 rate)
511
0
{
512
0
  if (!context || !context->handle)
513
0
    return ERROR_INVALID_PARAMETER;
514
515
0
  railPlugin* rail = (railPlugin*)context->handle;
516
0
  return rail_send_client_caret_blink_rate_order(rail, rate);
517
0
}
518
519
static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
520
                                                         UINT event, LPVOID pData,
521
                                                         UINT32 dataLength, UINT32 totalLength,
522
                                                         UINT32 dataFlags)
523
0
{
524
0
  UINT error = CHANNEL_RC_OK;
525
0
  railPlugin* rail = (railPlugin*)lpUserParam;
526
527
0
  switch (event)
528
0
  {
529
0
    case CHANNEL_EVENT_DATA_RECEIVED:
530
0
      if (!rail || (rail->OpenHandle != openHandle))
531
0
      {
532
0
        WLog_ERR(TAG, "error no match");
533
0
        return;
534
0
      }
535
536
0
      if ((error = channel_client_post_message(rail->MsgsHandle, pData, dataLength,
537
0
                                               totalLength, dataFlags)))
538
0
      {
539
0
        WLog_ERR(TAG,
540
0
                 "rail_virtual_channel_event_data_received"
541
0
                 " failed with error %" PRIu32 "!",
542
0
                 error);
543
0
      }
544
545
0
      break;
546
547
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
548
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
549
0
    {
550
0
      wStream* s = (wStream*)pData;
551
0
      Stream_Free(s, TRUE);
552
0
    }
553
0
    break;
554
555
0
    case CHANNEL_EVENT_USER:
556
0
      break;
557
0
    default:
558
0
      break;
559
0
  }
560
561
0
  if (error && rail && rail->rdpcontext)
562
0
    setChannelError(rail->rdpcontext, error,
563
0
                    "rail_virtual_channel_open_event reported an error");
564
0
}
565
566
/**
567
 * Function description
568
 *
569
 * @return 0 on success, otherwise a Win32 error code
570
 */
571
static UINT rail_virtual_channel_event_connected(railPlugin* rail, WINPR_ATTR_UNUSED LPVOID pData,
572
                                                 WINPR_ATTR_UNUSED UINT32 dataLength)
573
0
{
574
0
  RailClientContext* context = rail_get_client_interface(rail);
575
0
  UINT status = CHANNEL_RC_OK;
576
577
0
  WINPR_ASSERT(rail);
578
579
0
  if (context)
580
0
  {
581
0
    IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
582
583
0
    if (status != CHANNEL_RC_OK)
584
0
      WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]",
585
0
               WTSErrorToString(status), status);
586
0
  }
587
0
  rail->MsgsHandle = channel_client_create_handler(rail->rdpcontext, rail, rail_order_recv,
588
0
                                                   RAIL_SVC_CHANNEL_NAME);
589
0
  if (!rail->MsgsHandle)
590
0
    return ERROR_INTERNAL_ERROR;
591
592
0
  return rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
593
0
                                                        rail->channelDef.name,
594
0
                                                        rail_virtual_channel_open_event_ex);
595
0
}
596
597
/**
598
 * Function description
599
 *
600
 * @return 0 on success, otherwise a Win32 error code
601
 */
602
static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
603
0
{
604
0
  UINT rc = 0;
605
606
0
  channel_client_quit_handler(rail->MsgsHandle);
607
0
  if (rail->OpenHandle == 0)
608
0
    return CHANNEL_RC_OK;
609
610
0
  WINPR_ASSERT(rail->channelEntryPoints.pVirtualChannelCloseEx);
611
0
  rc = rail->channelEntryPoints.pVirtualChannelCloseEx(rail->InitHandle, rail->OpenHandle);
612
613
0
  if (CHANNEL_RC_OK != rc)
614
0
  {
615
0
    WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
616
0
             rc);
617
0
    return rc;
618
0
  }
619
620
0
  rail->OpenHandle = 0;
621
622
0
  return CHANNEL_RC_OK;
623
0
}
624
625
static void rail_virtual_channel_event_terminated(railPlugin* rail)
626
0
{
627
0
  rail->InitHandle = 0;
628
0
  free(rail->context);
629
0
  free(rail);
630
0
}
631
632
static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
633
                                                         UINT event, LPVOID pData, UINT dataLength)
634
0
{
635
0
  UINT error = CHANNEL_RC_OK;
636
0
  railPlugin* rail = (railPlugin*)lpUserParam;
637
638
0
  if (!rail || (rail->InitHandle != pInitHandle))
639
0
  {
640
0
    WLog_ERR(TAG, "error no match");
641
0
    return;
642
0
  }
643
644
0
  switch (event)
645
0
  {
646
0
    case CHANNEL_EVENT_CONNECTED:
647
0
      if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
648
0
        WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
649
0
                 error);
650
651
0
      break;
652
653
0
    case CHANNEL_EVENT_DISCONNECTED:
654
0
      if ((error = rail_virtual_channel_event_disconnected(rail)))
655
0
        WLog_ERR(TAG,
656
0
                 "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
657
0
                 error);
658
659
0
      break;
660
661
0
    case CHANNEL_EVENT_TERMINATED:
662
0
      rail_virtual_channel_event_terminated(rail);
663
0
      break;
664
665
0
    case CHANNEL_EVENT_ATTACHED:
666
0
    case CHANNEL_EVENT_DETACHED:
667
0
    default:
668
0
      break;
669
0
  }
670
671
0
  if (error && rail->rdpcontext)
672
0
    setChannelError(rail->rdpcontext, error,
673
0
                    "rail_virtual_channel_init_event_ex reported an error");
674
0
}
675
676
/* rail is always built-in */
677
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
678
679
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
680
                                                         PVOID pInitHandle))
681
0
{
682
0
  UINT rc = 0;
683
0
  railPlugin* rail = NULL;
684
0
  RailClientContext* context = NULL;
685
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
686
0
  BOOL isFreerdp = FALSE;
687
0
  rail = (railPlugin*)calloc(1, sizeof(railPlugin));
688
689
0
  if (!rail)
690
0
  {
691
0
    WLog_ERR(TAG, "calloc failed!");
692
0
    return FALSE;
693
0
  }
694
695
  /* Default to automatically replying to server handshakes */
696
0
  rail->sendHandshake = TRUE;
697
0
  rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
698
0
                             CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
699
0
  (void)sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
700
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
701
702
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
703
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
704
0
  {
705
0
    context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
706
707
0
    if (!context)
708
0
    {
709
0
      WLog_ERR(TAG, "calloc failed!");
710
0
      free(rail);
711
0
      return FALSE;
712
0
    }
713
714
0
    context->handle = (void*)rail;
715
0
    context->custom = NULL;
716
0
    context->ClientExecute = rail_client_execute;
717
0
    context->ClientActivate = rail_client_activate;
718
0
    context->ClientSystemParam = rail_client_system_param;
719
0
    context->ClientSystemCommand = rail_client_system_command;
720
0
    context->ClientHandshake = rail_client_handshake;
721
0
    context->ClientNotifyEvent = rail_client_notify_event;
722
0
    context->ClientWindowMove = rail_client_window_move;
723
0
    context->ClientInformation = rail_client_information;
724
0
    context->ClientSystemMenu = rail_client_system_menu;
725
0
    context->ClientLanguageBarInfo = rail_client_language_bar_info;
726
0
    context->ClientLanguageIMEInfo = rail_client_language_ime_info;
727
0
    context->ClientGetAppIdRequest = rail_client_get_appid_request;
728
0
    context->ClientSnapArrange = rail_client_snap_arrange;
729
0
    context->ClientCloak = rail_client_cloak;
730
0
    context->ClientCompartmentInfo = rail_client_compartment_info;
731
0
    context->ClientTextScale = rail_client_text_scale;
732
0
    context->ClientCaretBlinkRate = rail_client_caret_blink_rate;
733
0
    rail->rdpcontext = pEntryPointsEx->context;
734
0
    rail->context = context;
735
0
    isFreerdp = TRUE;
736
0
  }
737
738
0
  rail->log = WLog_Get("com.freerdp.channels.rail.client");
739
0
  WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
740
0
  CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
741
0
  rail->InitHandle = pInitHandle;
742
0
  rc = rail->channelEntryPoints.pVirtualChannelInitEx(
743
0
      rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
744
0
      rail_virtual_channel_init_event_ex);
745
746
0
  if (CHANNEL_RC_OK != rc)
747
0
  {
748
0
    WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
749
0
    goto error_out;
750
0
  }
751
752
0
  rail->channelEntryPoints.pInterface = context;
753
0
  return TRUE;
754
0
error_out:
755
756
0
  if (isFreerdp)
757
0
    free(rail->context);
758
759
0
  free(rail);
760
0
  return FALSE;
761
0
}