Coverage Report

Created: 2024-05-20 06:11

/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
  _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 = NULL;
125
0
  s = Stream_New(NULL, length + RAIL_PDU_HEADER_LENGTH);
126
127
0
  if (!s)
128
0
    return NULL;
129
130
0
  Stream_Seek(s, RAIL_PDU_HEADER_LENGTH);
131
0
  return s;
132
0
}
133
134
/**
135
 * Function description
136
 *
137
 * @return 0 on success, otherwise a Win32 error code
138
 */
139
UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake)
140
0
{
141
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
142
0
    return ERROR_INVALID_DATA;
143
144
0
  Stream_Read_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
145
0
  return CHANNEL_RC_OK;
146
0
}
147
148
void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake)
149
0
{
150
0
  Stream_Write_UINT32(s, handshake->buildNumber); /* buildNumber (4 bytes) */
151
0
}
152
153
/**
154
 * Function description
155
 *
156
 * @return 0 on success, otherwise a Win32 error code
157
 */
158
UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
159
0
{
160
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
161
0
    return ERROR_INVALID_DATA;
162
163
0
  Stream_Read_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
164
0
  Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
165
0
  return CHANNEL_RC_OK;
166
0
}
167
168
void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
169
0
{
170
0
  Stream_Write_UINT32(s, handshakeEx->buildNumber);        /* buildNumber (4 bytes) */
171
0
  Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
172
0
}
173
174
/**
175
 * Function description
176
 *
177
 * @return 0 on success, otherwise a Win32 error code
178
 */
179
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
180
0
{
181
0
  if (!s || !unicode_string)
182
0
    return ERROR_INVALID_PARAMETER;
183
184
0
  if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
185
0
  {
186
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
187
0
    return CHANNEL_RC_NO_MEMORY;
188
0
  }
189
190
0
  Stream_Write_UINT16(s, unicode_string->length);                  /* cbString (2 bytes) */
191
0
  Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
192
0
  return CHANNEL_RC_OK;
193
0
}
194
195
/**
196
 * Function description
197
 *
198
 * @return 0 on success, otherwise a Win32 error code
199
 */
200
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
201
0
{
202
0
  size_t length = 0;
203
204
0
  if (!s || !unicode_string)
205
0
    return ERROR_INVALID_PARAMETER;
206
207
0
  length = unicode_string->length;
208
209
0
  if (length > 0)
210
0
  {
211
0
    if (!Stream_EnsureRemainingCapacity(s, length))
212
0
    {
213
0
      WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
214
0
      return CHANNEL_RC_NO_MEMORY;
215
0
    }
216
217
0
    Stream_Write(s, unicode_string->string, length); /* string */
218
0
  }
219
220
0
  return CHANNEL_RC_OK;
221
0
}
222
223
/**
224
 * Function description
225
 *
226
 * @return 0 on success, otherwise a Win32 error code
227
 */
228
static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
229
0
{
230
0
  if (!s || !highContrast)
231
0
    return ERROR_INVALID_PARAMETER;
232
233
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
234
0
    return ERROR_INVALID_DATA;
235
236
0
  Stream_Read_UINT32(s, highContrast->flags);             /* flags (4 bytes) */
237
0
  Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
238
239
0
  if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
240
0
    return ERROR_INTERNAL_ERROR;
241
0
  return CHANNEL_RC_OK;
242
0
}
243
244
/**
245
 * Function description
246
 *
247
 * @return 0 on success, otherwise a Win32 error code
248
 */
249
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
250
0
{
251
0
  UINT32 colorSchemeLength = 0;
252
253
0
  if (!s || !highContrast)
254
0
    return ERROR_INVALID_PARAMETER;
255
256
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
257
0
    return CHANNEL_RC_NO_MEMORY;
258
259
0
  colorSchemeLength = highContrast->colorScheme.length + 2;
260
0
  Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
261
0
  Stream_Write_UINT32(s, colorSchemeLength);   /* colorSchemeLength (4 bytes) */
262
0
  return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
263
0
}
264
265
/**
266
 * Function description
267
 *
268
 * @return 0 on success, otherwise a Win32 error code
269
 */
270
static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
271
0
{
272
0
  if (!s || !filterKeys)
273
0
    return ERROR_INVALID_PARAMETER;
274
275
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
276
0
    return ERROR_INVALID_DATA;
277
278
0
  Stream_Read_UINT32(s, filterKeys->Flags);
279
0
  Stream_Read_UINT32(s, filterKeys->WaitTime);
280
0
  Stream_Read_UINT32(s, filterKeys->DelayTime);
281
0
  Stream_Read_UINT32(s, filterKeys->RepeatTime);
282
0
  Stream_Read_UINT32(s, filterKeys->BounceTime);
283
0
  return CHANNEL_RC_OK;
284
0
}
285
286
/**
287
 * Function description
288
 *
289
 * @return 0 on success, otherwise a Win32 error code
290
 */
291
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
292
0
{
293
0
  if (!s || !filterKeys)
294
0
    return ERROR_INVALID_PARAMETER;
295
296
0
  if (!Stream_EnsureRemainingCapacity(s, 20))
297
0
    return CHANNEL_RC_NO_MEMORY;
298
299
0
  Stream_Write_UINT32(s, filterKeys->Flags);
300
0
  Stream_Write_UINT32(s, filterKeys->WaitTime);
301
0
  Stream_Write_UINT32(s, filterKeys->DelayTime);
302
0
  Stream_Write_UINT32(s, filterKeys->RepeatTime);
303
0
  Stream_Write_UINT32(s, filterKeys->BounceTime);
304
0
  return CHANNEL_RC_OK;
305
0
}
306
307
/**
308
 * Function description
309
 *
310
 * @return 0 on success, otherwise a Win32 error code
311
 */
312
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
313
0
{
314
0
  BYTE body = 0;
315
0
  UINT error = CHANNEL_RC_OK;
316
317
0
  if (!s || !sysparam)
318
0
    return ERROR_INVALID_PARAMETER;
319
320
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
321
0
    return ERROR_INVALID_DATA;
322
323
0
  Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
324
325
0
  sysparam->params = 0; /* bitflags of received params */
326
327
0
  switch (sysparam->param)
328
0
  {
329
    /* Client sysparams */
330
0
    case SPI_SET_DRAG_FULL_WINDOWS:
331
0
      sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
332
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
333
0
      sysparam->dragFullWindows = body != 0;
334
0
      break;
335
336
0
    case SPI_SET_KEYBOARD_CUES:
337
0
      sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
338
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
339
0
      sysparam->keyboardCues = body != 0;
340
0
      break;
341
342
0
    case SPI_SET_KEYBOARD_PREF:
343
0
      sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
344
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
345
0
      sysparam->keyboardPref = body != 0;
346
0
      break;
347
348
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
349
0
      sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
350
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
351
0
      sysparam->mouseButtonSwap = body != 0;
352
0
      break;
353
354
0
    case SPI_SET_WORK_AREA:
355
0
      sysparam->params |= SPI_MASK_SET_WORK_AREA;
356
357
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
358
0
        return ERROR_INVALID_DATA;
359
360
0
      Stream_Read_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
361
0
      Stream_Read_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
362
0
      Stream_Read_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
363
0
      Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
364
0
      break;
365
366
0
    case SPI_DISPLAY_CHANGE:
367
0
      sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
368
369
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
370
0
        return ERROR_INVALID_DATA;
371
372
0
      Stream_Read_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
373
0
      Stream_Read_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
374
0
      Stream_Read_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
375
0
      Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
376
0
      break;
377
378
0
    case SPI_TASKBAR_POS:
379
0
      sysparam->params |= SPI_MASK_TASKBAR_POS;
380
381
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
382
0
        return ERROR_INVALID_DATA;
383
384
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
385
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
386
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
387
0
      Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
388
0
      break;
389
390
0
    case SPI_SET_HIGH_CONTRAST:
391
0
      sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
392
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
393
0
        return ERROR_INVALID_DATA;
394
395
0
      error = rail_read_high_contrast(s, &sysparam->highContrast);
396
0
      break;
397
398
0
    case SPI_SETCARETWIDTH:
399
0
      sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
400
401
0
      if (!extendedSpiSupported)
402
0
        return ERROR_INVALID_DATA;
403
404
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
405
0
        return ERROR_INVALID_DATA;
406
407
0
      Stream_Read_UINT32(s, sysparam->caretWidth);
408
409
0
      if (sysparam->caretWidth < 0x0001)
410
0
        return ERROR_INVALID_DATA;
411
412
0
      break;
413
414
0
    case SPI_SETSTICKYKEYS:
415
0
      sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
416
417
0
      if (!extendedSpiSupported)
418
0
        return ERROR_INVALID_DATA;
419
420
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
421
0
        return ERROR_INVALID_DATA;
422
423
0
      Stream_Read_UINT32(s, sysparam->stickyKeys);
424
0
      break;
425
426
0
    case SPI_SETTOGGLEKEYS:
427
0
      sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
428
429
0
      if (!extendedSpiSupported)
430
0
        return ERROR_INVALID_DATA;
431
432
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
433
0
        return ERROR_INVALID_DATA;
434
435
0
      Stream_Read_UINT32(s, sysparam->toggleKeys);
436
0
      break;
437
438
0
    case SPI_SETFILTERKEYS:
439
0
      sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
440
441
0
      if (!extendedSpiSupported)
442
0
        return ERROR_INVALID_DATA;
443
444
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
445
0
        return ERROR_INVALID_DATA;
446
447
0
      error = rail_read_filterkeys(s, &sysparam->filterKeys);
448
0
      break;
449
450
    /* Server sysparams */
451
0
    case SPI_SETSCREENSAVEACTIVE:
452
0
      sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
453
454
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
455
0
      sysparam->setScreenSaveActive = body != 0;
456
0
      break;
457
458
0
    case SPI_SETSCREENSAVESECURE:
459
0
      sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
460
461
0
      Stream_Read_UINT8(s, body); /* body (1 byte) */
462
0
      sysparam->setScreenSaveSecure = body != 0;
463
0
      break;
464
465
0
    default:
466
0
      break;
467
0
  }
468
469
0
  return error;
470
0
}
471
472
/**
473
 * Function description
474
 *
475
 * @return 0 on success, otherwise a Win32 err2or code
476
 */
477
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
478
                               BOOL extendedSpiSupported)
479
0
{
480
0
  BYTE body = 0;
481
0
  UINT error = CHANNEL_RC_OK;
482
483
0
  if (!s || !sysparam)
484
0
    return ERROR_INVALID_PARAMETER;
485
486
0
  if (!Stream_EnsureRemainingCapacity(s, 12))
487
0
    return CHANNEL_RC_NO_MEMORY;
488
489
0
  Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
490
491
0
  switch (sysparam->param)
492
0
  {
493
    /* Client sysparams */
494
0
    case SPI_SET_DRAG_FULL_WINDOWS:
495
0
      body = sysparam->dragFullWindows ? 1 : 0;
496
0
      Stream_Write_UINT8(s, body);
497
0
      break;
498
499
0
    case SPI_SET_KEYBOARD_CUES:
500
0
      body = sysparam->keyboardCues ? 1 : 0;
501
0
      Stream_Write_UINT8(s, body);
502
0
      break;
503
504
0
    case SPI_SET_KEYBOARD_PREF:
505
0
      body = sysparam->keyboardPref ? 1 : 0;
506
0
      Stream_Write_UINT8(s, body);
507
0
      break;
508
509
0
    case SPI_SET_MOUSE_BUTTON_SWAP:
510
0
      body = sysparam->mouseButtonSwap ? 1 : 0;
511
0
      Stream_Write_UINT8(s, body);
512
0
      break;
513
514
0
    case SPI_SET_WORK_AREA:
515
0
      Stream_Write_UINT16(s, sysparam->workArea.left);   /* left (2 bytes) */
516
0
      Stream_Write_UINT16(s, sysparam->workArea.top);    /* top (2 bytes) */
517
0
      Stream_Write_UINT16(s, sysparam->workArea.right);  /* right (2 bytes) */
518
0
      Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
519
0
      break;
520
521
0
    case SPI_DISPLAY_CHANGE:
522
0
      Stream_Write_UINT16(s, sysparam->displayChange.left);   /* left (2 bytes) */
523
0
      Stream_Write_UINT16(s, sysparam->displayChange.top);    /* top (2 bytes) */
524
0
      Stream_Write_UINT16(s, sysparam->displayChange.right);  /* right (2 bytes) */
525
0
      Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
526
0
      break;
527
528
0
    case SPI_TASKBAR_POS:
529
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.left);   /* left (2 bytes) */
530
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.top);    /* top (2 bytes) */
531
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.right);  /* right (2 bytes) */
532
0
      Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
533
0
      break;
534
535
0
    case SPI_SET_HIGH_CONTRAST:
536
0
      error = rail_write_high_contrast(s, &sysparam->highContrast);
537
0
      break;
538
539
0
    case SPI_SETCARETWIDTH:
540
0
      if (!extendedSpiSupported)
541
0
        return ERROR_INVALID_DATA;
542
543
0
      if (sysparam->caretWidth < 0x0001)
544
0
        return ERROR_INVALID_DATA;
545
546
0
      Stream_Write_UINT32(s, sysparam->caretWidth);
547
0
      break;
548
549
0
    case SPI_SETSTICKYKEYS:
550
0
      if (!extendedSpiSupported)
551
0
        return ERROR_INVALID_DATA;
552
553
0
      Stream_Write_UINT32(s, sysparam->stickyKeys);
554
0
      break;
555
556
0
    case SPI_SETTOGGLEKEYS:
557
0
      if (!extendedSpiSupported)
558
0
        return ERROR_INVALID_DATA;
559
560
0
      Stream_Write_UINT32(s, sysparam->toggleKeys);
561
0
      break;
562
563
0
    case SPI_SETFILTERKEYS:
564
0
      if (!extendedSpiSupported)
565
0
        return ERROR_INVALID_DATA;
566
567
0
      error = rail_write_filterkeys(s, &sysparam->filterKeys);
568
0
      break;
569
570
    /* Server sysparams */
571
0
    case SPI_SETSCREENSAVEACTIVE:
572
0
      body = sysparam->setScreenSaveActive ? 1 : 0;
573
0
      Stream_Write_UINT8(s, body);
574
0
      break;
575
576
0
    case SPI_SETSCREENSAVESECURE:
577
0
      body = sysparam->setScreenSaveSecure ? 1 : 0;
578
0
      Stream_Write_UINT8(s, body);
579
0
      break;
580
581
0
    default:
582
0
      return ERROR_INVALID_PARAMETER;
583
0
  }
584
585
0
  return error;
586
0
}
587
588
BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
589
0
{
590
0
  return (channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED) ? TRUE : FALSE;
591
0
}
592
593
const char* rail_handshake_ex_flags_to_string(UINT32 flags, char* buffer, size_t len)
594
0
{
595
0
  if (len < 1)
596
0
    return NULL;
597
598
0
  _snprintf(buffer, len, "{");
599
0
  char* fbuffer = &buffer[1];
600
0
  len--;
601
602
0
  if (flags & TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF)
603
0
    winpr_str_append("HIDEF", fbuffer, len, "|");
604
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED)
605
0
    winpr_str_append("EXTENDED_SPI_SUPPORTED", fbuffer, len, "|");
606
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED)
607
0
    winpr_str_append("SNAP_ARRANGE_SUPPORTED", fbuffer, len, "|");
608
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED)
609
0
    winpr_str_append("TEXT_SCALE_SUPPORTED", fbuffer, len, "|");
610
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED)
611
0
    winpr_str_append("CARET_BLINK_SUPPORTED", fbuffer, len, "|");
612
0
  if (flags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED)
613
0
    winpr_str_append("EXTENDED_SPI_2_SUPPORTED", fbuffer, len, "|");
614
615
0
  char number[16] = { 0 };
616
0
  _snprintf(number, sizeof(number), "[0x%08" PRIx32 "]", flags);
617
0
  winpr_str_append(number, buffer, len, "}");
618
0
  return buffer;
619
0
}