Coverage Report

Created: 2025-07-11 06:46

/src/FreeRDP/channels/rail/rail_common.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RAIL common functions
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
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
#include "rail_common.h"
24
25
#include <winpr/crt.h>
26
#include <freerdp/channels/log.h>
27
28
#define TAG CHANNELS_TAG("rail.common")
29
30
const char* rail_get_order_type_string(UINT16 orderType)
31
0
{
32
0
  switch (orderType)
33
0
  {
34
0
    case TS_RAIL_ORDER_EXEC:
35
0
      return "TS_RAIL_ORDER_EXEC";
36
0
    case TS_RAIL_ORDER_ACTIVATE:
37
0
      return "TS_RAIL_ORDER_ACTIVATE";
38
0
    case TS_RAIL_ORDER_SYSPARAM:
39
0
      return "TS_RAIL_ORDER_SYSPARAM";
40
0
    case TS_RAIL_ORDER_SYSCOMMAND:
41
0
      return "TS_RAIL_ORDER_SYSCOMMAND";
42
0
    case TS_RAIL_ORDER_HANDSHAKE:
43
0
      return "TS_RAIL_ORDER_HANDSHAKE";
44
0
    case TS_RAIL_ORDER_NOTIFY_EVENT:
45
0
      return "TS_RAIL_ORDER_NOTIFY_EVENT";
46
0
    case TS_RAIL_ORDER_WINDOWMOVE:
47
0
      return "TS_RAIL_ORDER_WINDOWMOVE";
48
0
    case TS_RAIL_ORDER_LOCALMOVESIZE:
49
0
      return "TS_RAIL_ORDER_LOCALMOVESIZE";
50
0
    case TS_RAIL_ORDER_MINMAXINFO:
51
0
      return "TS_RAIL_ORDER_MINMAXINFO";
52
0
    case TS_RAIL_ORDER_CLIENTSTATUS:
53
0
      return "TS_RAIL_ORDER_CLIENTSTATUS";
54
0
    case TS_RAIL_ORDER_SYSMENU:
55
0
      return "TS_RAIL_ORDER_SYSMENU";
56
0
    case TS_RAIL_ORDER_LANGBARINFO:
57
0
      return "TS_RAIL_ORDER_LANGBARINFO";
58
0
    case TS_RAIL_ORDER_GET_APPID_REQ:
59
0
      return "TS_RAIL_ORDER_GET_APPID_REQ";
60
0
    case TS_RAIL_ORDER_GET_APPID_RESP:
61
0
      return "TS_RAIL_ORDER_GET_APPID_RESP";
62
0
    case TS_RAIL_ORDER_TASKBARINFO:
63
0
      return "TS_RAIL_ORDER_TASKBARINFO";
64
0
    case TS_RAIL_ORDER_LANGUAGEIMEINFO:
65
0
      return "TS_RAIL_ORDER_LANGUAGEIMEINFO";
66
0
    case TS_RAIL_ORDER_COMPARTMENTINFO:
67
0
      return "TS_RAIL_ORDER_COMPARTMENTINFO";
68
0
    case TS_RAIL_ORDER_HANDSHAKE_EX:
69
0
      return "TS_RAIL_ORDER_HANDSHAKE_EX";
70
0
    case TS_RAIL_ORDER_ZORDER_SYNC:
71
0
      return "TS_RAIL_ORDER_ZORDER_SYNC";
72
0
    case TS_RAIL_ORDER_CLOAK:
73
0
      return "TS_RAIL_ORDER_CLOAK";
74
0
    case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
75
0
      return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST";
76
0
    case TS_RAIL_ORDER_SNAP_ARRANGE:
77
0
      return "TS_RAIL_ORDER_SNAP_ARRANGE";
78
0
    case TS_RAIL_ORDER_GET_APPID_RESP_EX:
79
0
      return "TS_RAIL_ORDER_GET_APPID_RESP_EX";
80
0
    case TS_RAIL_ORDER_EXEC_RESULT:
81
0
      return "TS_RAIL_ORDER_EXEC_RESULT";
82
0
    case TS_RAIL_ORDER_TEXTSCALEINFO:
83
0
      return "TS_RAIL_ORDER_TEXTSCALEINFO";
84
0
    case TS_RAIL_ORDER_CARETBLINKINFO:
85
0
      return "TS_RAIL_ORDER_CARETBLINKINFO";
86
0
    default:
87
0
      return "TS_RAIL_ORDER_UNKNOWN";
88
0
  }
89
0
}
90
91
const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length)
92
0
{
93
0
  (void)_snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType),
94
0
                  orderType);
95
0
  return buffer;
96
0
}
97
98
/**
99
 * Function description
100
 *
101
 * @return 0 on success, otherwise a Win32 error code
102
 */
103
UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength)
104
0
{
105
0
  if (!s || !orderType || !orderLength)
106
0
    return ERROR_INVALID_PARAMETER;
107
108
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
109
0
    return ERROR_INVALID_DATA;
110
111
0
  Stream_Read_UINT16(s, *orderType);   /* orderType (2 bytes) */
112
0
  Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */
113
0
  return CHANNEL_RC_OK;
114
0
}
115
116
void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength)
117
0
{
118
0
  Stream_Write_UINT16(s, orderType);   /* orderType (2 bytes) */
119
0
  Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */
120
0
}
121
122
wStream* rail_pdu_init(size_t length)
123
0
{
124
0
  wStream* s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH);
125
126
0
  if (!s)
127
0
    return NULL;
128
129
0
  Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
130
0
  return s;
131
0
}
132
133
/**
134
 * Function description
135
 *
136
 * @return 0 on success, otherwise a Win32 error code
137
 */
138
UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
139
0
{
140
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
141
0
    return ERROR_INVALID_DATA;
142
143
0
  Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
144
0
  return CHANNEL_RC_OK;
145
0
}
146
147
void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake)
148
0
{
149
0
  Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
150
0
}
151
152
/**
153
 * Function description
154
 *
155
 * @return 0 on success, otherwise a Win32 error code
156
 */
157
UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
158
0
{
159
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
160
0
    return ERROR_INVALID_DATA;
161
162
0
  Stream_Read_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
163
0
  Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
164
0
  return CHANNEL_RC_OK;
165
0
}
166
167
void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
168
0
{
169
0
  Stream_Write_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
170
0
  Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
171
0
}
172
173
/**
174
 * Function description
175
 *
176
 * @return 0 on success, otherwise a Win32 error code
177
 */
178
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
179
0
{
180
0
  if (!s || !unicode_string)
181
0
    return ERROR_INVALID_PARAMETER;
182
183
0
  if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
184
0
  {
185
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
186
0
    return CHANNEL_RC_NO_MEMORY;
187
0
  }
188
189
0
  Stream_Write_UINT16(s, unicode_string->length);                  /* cbString (2 bytes) */
190
0
  Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
191
0
  return CHANNEL_RC_OK;
192
0
}
193
194
/**
195
 * Function description
196
 *
197
 * @return 0 on success, otherwise a Win32 error code
198
 */
199
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
200
0
{
201
0
  size_t length = 0;
202
203
0
  if (!s || !unicode_string)
204
0
    return ERROR_INVALID_PARAMETER;
205
206
0
  length = unicode_string->length;
207
208
0
  if (length > 0)
209
0
  {
210
0
    if (!Stream_EnsureRemainingCapacity(s, length))
211
0
    {
212
0
      WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
213
0
      return CHANNEL_RC_NO_MEMORY;
214
0
    }
215
216
0
    Stream_Write(s, unicode_string->string, length); /* string */
217
0
  }
218
219
0
  return CHANNEL_RC_OK;
220
0
}
221
222
/**
223
 * Function description
224
 *
225
 * @return 0 on success, otherwise a Win32 error code
226
 */
227
static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
228
0
{
229
0
  if (!s || !highContrast)
230
0
    return ERROR_INVALID_PARAMETER;
231
232
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
233
0
    return ERROR_INVALID_DATA;
234
235
0
  Stream_Read_UINT32(s, highContrast->flags);             /* flags (4 bytes) */
236
0
  Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
237
238
0
  if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
239
0
    return ERROR_INTERNAL_ERROR;
240
0
  return CHANNEL_RC_OK;
241
0
}
242
243
/**
244
 * Function description
245
 *
246
 * @return 0 on success, otherwise a Win32 error code
247
 */
248
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
249
0
{
250
0
  UINT32 colorSchemeLength = 0;
251
252
0
  if (!s || !highContrast)
253
0
    return ERROR_INVALID_PARAMETER;
254
255
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
256
0
    return CHANNEL_RC_NO_MEMORY;
257
258
0
  colorSchemeLength = highContrast->colorScheme.length + 2;
259
0
  Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
260
0
  Stream_Write_UINT32(s, colorSchemeLength);   /* colorSchemeLength (4 bytes) */
261
0
  return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
262
0
}
263
264
/**
265
 * Function description
266
 *
267
 * @return 0 on success, otherwise a Win32 error code
268
 */
269
static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
270
0
{
271
0
  if (!s || !filterKeys)
272
0
    return ERROR_INVALID_PARAMETER;
273
274
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
275
0
    return ERROR_INVALID_DATA;
276
277
0
  Stream_Read_UINT32(s, filterKeys->Flags);
278
0
  Stream_Read_UINT32(s, filterKeys->WaitTime);
279
0
  Stream_Read_UINT32(s, filterKeys->DelayTime);
280
0
  Stream_Read_UINT32(s, filterKeys->RepeatTime);
281
0
  Stream_Read_UINT32(s, filterKeys->BounceTime);
282
0
  return CHANNEL_RC_OK;
283
0
}
284
285
/**
286
 * Function description
287
 *
288
 * @return 0 on success, otherwise a Win32 error code
289
 */
290
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
291
0
{
292
0
  if (!s || !filterKeys)
293
0
    return ERROR_INVALID_PARAMETER;
294
295
0
  if (!Stream_EnsureRemainingCapacity(s, 20))
296
0
    return CHANNEL_RC_NO_MEMORY;
297
298
0
  Stream_Write_UINT32(s, filterKeys->Flags);
299
0
  Stream_Write_UINT32(s, filterKeys->WaitTime);
300
0
  Stream_Write_UINT32(s, filterKeys->DelayTime);
301
0
  Stream_Write_UINT32(s, filterKeys->RepeatTime);
302
0
  Stream_Write_UINT32(s, filterKeys->BounceTime);
303
0
  return CHANNEL_RC_OK;
304
0
}
305
306
/**
307
 * Function description
308
 *
309
 * @return 0 on success, otherwise a Win32 error code
310
 */
311
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
312
0
{
313
0
  BYTE body = 0;
314
0
  UINT error = CHANNEL_RC_OK;
315
316
0
  if (!s || !sysparam)
317
0
    return ERROR_INVALID_PARAMETER;
318
319
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
320
0
    return ERROR_INVALID_DATA;
321
322
0
  Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
323
324
0
  sysparam->params = 0; /* bitflags of received params */
325
326
0
  switch (sysparam->param)
327
0
  {
328
    /* Client sysparams */
329
0
    case SPI_SET_DRAG_FULL_WINDOWS:
330
0
      sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
331
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
332
0
      sysparam->dragFullWindows = body != 0;
333
0
      break;
334
335
0
    case SPI_SET_KEYBOARD_CUES:
336
0
      sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
337
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
338
0
      sysparam->keyboardCues = body != 0;
339
0
      break;
340
341
0
    case SPI_SET_KEYBOARD_PREF:
342
0
      sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
343
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
344
0
      sysparam->keyboardPref = body != 0;
345
0
      break;
346
347
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
348
0
      sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
349
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
350
0
      sysparam->mouseButtonSwap = body != 0;
351
0
      break;
352
353
0
    case SPI_SET_WORK_AREA:
354
0
      sysparam->params |= SPI_MASK_SET_WORK_AREA;
355
356
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
357
0
        return ERROR_INVALID_DATA;
358
359
0
      Stream_Read_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
360
0
      Stream_Read_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
361
0
      Stream_Read_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
362
0
      Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
363
0
      break;
364
365
0
    case SPI_DISPLAY_CHANGE:
366
0
      sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
367
368
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
369
0
        return ERROR_INVALID_DATA;
370
371
0
      Stream_Read_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
372
0
      Stream_Read_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
373
0
      Stream_Read_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
374
0
      Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
375
0
      break;
376
377
0
    case SPI_TASKBAR_POS:
378
0
      sysparam->params |= SPI_MASK_TASKBAR_POS;
379
380
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
381
0
        return ERROR_INVALID_DATA;
382
383
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
384
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
385
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
386
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
387
0
      break;
388
389
0
    case SPI_SET_HIGH_CONTRAST:
390
0
      sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
391
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
392
0
        return ERROR_INVALID_DATA;
393
394
0
      error = rail_read_high_contrast(s, &sysparam->highContrast);
395
0
      break;
396
397
0
    case SPI_SETCARETWIDTH:
398
0
      sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
399
400
0
      if (!extendedSpiSupported)
401
0
        return ERROR_INVALID_DATA;
402
403
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
404
0
        return ERROR_INVALID_DATA;
405
406
0
      Stream_Read_UINT32(s, sysparam->caretWidth);
407
408
0
      if (sysparam->caretWidth < 0x0001)
409
0
        return ERROR_INVALID_DATA;
410
411
0
      break;
412
413
0
    case SPI_SETSTICKYKEYS:
414
0
      sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
415
416
0
      if (!extendedSpiSupported)
417
0
        return ERROR_INVALID_DATA;
418
419
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
420
0
        return ERROR_INVALID_DATA;
421
422
0
      Stream_Read_UINT32(s, sysparam->stickyKeys);
423
0
      break;
424
425
0
    case SPI_SETTOGGLEKEYS:
426
0
      sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
427
428
0
      if (!extendedSpiSupported)
429
0
        return ERROR_INVALID_DATA;
430
431
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
432
0
        return ERROR_INVALID_DATA;
433
434
0
      Stream_Read_UINT32(s, sysparam->toggleKeys);
435
0
      break;
436
437
0
    case SPI_SETFILTERKEYS:
438
0
      sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
439
440
0
      if (!extendedSpiSupported)
441
0
        return ERROR_INVALID_DATA;
442
443
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
444
0
        return ERROR_INVALID_DATA;
445
446
0
      error = rail_read_filterkeys(s, &sysparam->filterKeys);
447
0
      break;
448
449
    /* Server sysparams */
450
0
    case SPI_SETSCREENSAVEACTIVE:
451
0
      sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
452
453
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
454
0
      sysparam->setScreenSaveActive = body != 0;
455
0
      break;
456
457
0
    case SPI_SETSCREENSAVESECURE:
458
0
      sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
459
460
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
461
0
      sysparam->setScreenSaveSecure = body != 0;
462
0
      break;
463
464
0
    default:
465
0
      break;
466
0
  }
467
468
0
  return error;
469
0
}
470
471
/**
472
 * Function description
473
 *
474
 * @return 0 on success, otherwise a Win32 err2or code
475
 */
476
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
477
                               BOOL extendedSpiSupported)
478
0
{
479
0
  BYTE body = 0;
480
0
  UINT error = CHANNEL_RC_OK;
481
482
0
  if (!s || !sysparam)
483
0
    return ERROR_INVALID_PARAMETER;
484
485
0
  if (!Stream_EnsureRemainingCapacity(s, 12))
486
0
    return CHANNEL_RC_NO_MEMORY;
487
488
0
  Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
489
490
0
  switch (sysparam->param)
491
0
  {
492
    /* Client sysparams */
493
0
    case SPI_SET_DRAG_FULL_WINDOWS:
494
0
      body = sysparam->dragFullWindows ? 1 : 0;
495
0
      Stream_Write_UINT8(s, body);
496
0
      break;
497
498
0
    case SPI_SET_KEYBOARD_CUES:
499
0
      body = sysparam->keyboardCues ? 1 : 0;
500
0
      Stream_Write_UINT8(s, body);
501
0
      break;
502
503
0
    case SPI_SET_KEYBOARD_PREF:
504
0
      body = sysparam->keyboardPref ? 1 : 0;
505
0
      Stream_Write_UINT8(s, body);
506
0
      break;
507
508
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
509
0
      body = sysparam->mouseButtonSwap ? 1 : 0;
510
0
      Stream_Write_UINT8(s, body);
511
0
      break;
512
513
0
    case SPI_SET_WORK_AREA:
514
0
      Stream_Write_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
515
0
      Stream_Write_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
516
0
      Stream_Write_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
517
0
      Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
518
0
      break;
519
520
0
    case SPI_DISPLAY_CHANGE:
521
0
      Stream_Write_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
522
0
      Stream_Write_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
523
0
      Stream_Write_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
524
0
      Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
525
0
      break;
526
527
0
    case SPI_TASKBAR_POS:
528
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
529
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
530
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
531
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
532
0
      break;
533
534
0
    case SPI_SET_HIGH_CONTRAST:
535
0
      error = rail_write_high_contrast(s, &sysparam->highContrast);
536
0
      break;
537
538
0
    case SPI_SETCARETWIDTH:
539
0
      if (!extendedSpiSupported)
540
0
        return ERROR_INVALID_DATA;
541
542
0
      if (sysparam->caretWidth < 0x0001)
543
0
        return ERROR_INVALID_DATA;
544
545
0
      Stream_Write_UINT32(s, sysparam->caretWidth);
546
0
      break;
547
548
0
    case SPI_SETSTICKYKEYS:
549
0
      if (!extendedSpiSupported)
550
0
        return ERROR_INVALID_DATA;
551
552
0
      Stream_Write_UINT32(s, sysparam->stickyKeys);
553
0
      break;
554
555
0
    case SPI_SETTOGGLEKEYS:
556
0
      if (!extendedSpiSupported)
557
0
        return ERROR_INVALID_DATA;
558
559
0
      Stream_Write_UINT32(s, sysparam->toggleKeys);
560
0
      break;
561
562
0
    case SPI_SETFILTERKEYS:
563
0
      if (!extendedSpiSupported)
564
0
        return ERROR_INVALID_DATA;
565
566
0
      error = rail_write_filterkeys(s, &sysparam->filterKeys);
567
0
      break;
568
569
    /* Server sysparams */
570
0
    case SPI_SETSCREENSAVEACTIVE:
571
0
      body = sysparam->setScreenSaveActive ? 1 : 0;
572
0
      Stream_Write_UINT8(s, body);
573
0
      break;
574
575
0
    case SPI_SETSCREENSAVESECURE:
576
0
      body = sysparam->setScreenSaveSecure ? 1 : 0;
577
0
      Stream_Write_UINT8(s, body);
578
0
      break;
579
580
0
    default:
581
0
      return ERROR_INVALID_PARAMETER;
582
0
  }
583
584
0
  return error;
585
0
}
586
587
BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
588
0
{
589
0
  return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) ? TRUE : FALSE;
590
0
}
591
592
const char* rail_handshake_ex_flags_to_string(UINT32 flags, char* buffer, size_t len)
593
0
{
594
0
  if (len < 1)
595
0
    return NULL;
596
597
0
  (void)_snprintf(buffer, len, "{");
598
0
  char* fbuffer = &buffer[1];
599
0
  len--;
600
601
0
  if (flags & TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF)
602
0
    winpr_str_append("HIDEF", fbuffer, len, "|");
603
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED)
604
0
    winpr_str_append("EXTENDED_SPI_SUPPORTED", fbuffer, len, "|");
605
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED)
606
0
    winpr_str_append("SNAP_ARRANGE_SUPPORTED", fbuffer, len, "|");
607
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED)
608
0
    winpr_str_append("TEXT_SCALE_SUPPORTED", fbuffer, len, "|");
609
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED)
610
0
    winpr_str_append("CARET_BLINK_SUPPORTED", fbuffer, len, "|");
611
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED)
612
0
    winpr_str_append("EXTENDED_SPI_2_SUPPORTED", fbuffer, len, "|");
613
614
0
  char number[16] = { 0 };
615
0
  (void)_snprintf(number, sizeof(number), "[0x%08" PRIx32 "]", flags);
616
0
  winpr_str_append(number, buffer, len, "}");
617
0
  return buffer;
618
0
}