Coverage Report

Created: 2024-05-20 06:11

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