server: start reading MCS Connect Initial PDU and Client Core Data.
[platform/upstream/freerdp.git] / libfreerdp-core / gcc.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * T.124 Generic Conference Control (GCC)
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include "gcc.h"
21
22 /**
23  * T.124 GCC is defined in:
24  *
25  * http://www.itu.int/rec/T-REC-T.124-199802-S/en
26  * ITU-T T.124 (02/98): Generic Conference Control
27  */
28
29 /**
30  * ConnectData ::= SEQUENCE
31  * {
32  *      t124Identifier  Key,
33  *      connectPDU      OCTET_STRING
34  * }
35  *
36  * Key ::= CHOICE
37  * {
38  *      object                          OBJECT_IDENTIFIER,
39  *      h221NonStandard                 H221NonStandardIdentifier
40  * }
41  *
42  * ConnectGCCPDU ::= CHOICE
43  * {
44  *      conferenceCreateRequest         ConferenceCreateRequest,
45  *      conferenceCreateResponse        ConferenceCreateResponse,
46  *      conferenceQueryRequest          ConferenceQueryRequest,
47  *      conferenceQueryResponse         ConferenceQueryResponse,
48  *      conferenceJoinRequest           ConferenceJoinRequest,
49  *      conferenceJoinResponse          ConferenceJoinResponse,
50  *      conferenceInviteRequest         ConferenceInviteRequest,
51  *      conferenceInviteResponse        ConferenceInviteResponse,
52  *      ...
53  * }
54  *
55  * ConferenceCreateRequest ::= SEQUENCE
56  * {
57  *      conferenceName                  ConferenceName,
58  *      convenerPassword                Password OPTIONAL,
59  *      password                        Password OPTIONAL,
60  *      lockedConference                BOOLEAN,
61  *      listedConference                BOOLEAN,
62  *      conductibleConference           BOOLEAN,
63  *      terminationMethod               TerminationMethod,
64  *      conductorPrivileges             SET OF Privilege OPTIONAL,
65  *      conductedPrivileges             SET OF Privilege OPTIONAL,
66  *      nonConductedPrivileges          SET OF Privilege OPTIONAL,
67  *      conferenceDescription           TextString OPTIONAL,
68  *      callerIdentifier                TextString OPTIONAL,
69  *      userData                        UserData OPTIONAL,
70  *      ...,
71  *      conferencePriority              ConferencePriority OPTIONAL,
72  *      conferenceMode                  ConferenceMode OPTIONAL
73  * }
74  *
75  * ConferenceCreateResponse ::= SEQUENCE
76  * {
77  *      nodeID                          UserID,
78  *      tag                             INTEGER,
79  *      result                          ENUMERATED
80  *      {
81  *              success                         (0),
82  *              userRejected                    (1),
83  *              resourcesNotAvailable           (2),
84  *              rejectedForSymmetryBreaking     (3),
85  *              lockedConferenceNotSupported    (4)
86  *      },
87  *      userData                        UserData OPTIONAL,
88  *      ...
89  * }
90  *
91  * ConferenceName ::= SEQUENCE
92  * {
93  *      numeric                         SimpleNumericString
94  *      text                            SimpleTextString OPTIONAL,
95  *      ...
96  * }
97  *
98  * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
99  *
100  * UserData ::= SET OF SEQUENCE
101  * {
102  *      key                             Key,
103  *      value                           OCTET_STRING OPTIONAL
104  * }
105  *
106  * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
107  *
108  * UserID ::= DynamicChannelID
109  *
110  * ChannelID ::= INTEGER (1..65535)
111  * StaticChannelID ::= INTEGER (1..1000)
112  * DynamicChannelID ::= INTEGER (1001..65535)
113  *
114  */
115
116 /*
117  * OID = 0.0.20.124.0.1
118  * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
119  * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
120  */
121 uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
122
123 uint8 h221_cs_key[4] = "Duca";
124 uint8 h221_sc_key[4] = "McDn";
125
126 /**
127  * Read a GCC Conference Create Request.\n
128  * @msdn{cc240836}
129  * @param s stream
130  * @param settings rdp settings
131  */
132
133 boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings)
134 {
135         uint16 length;
136         uint8 choice;
137         uint8 number;
138         uint8 selection;
139
140         /* ConnectData */
141         if (!per_read_choice(s, &choice))
142                 return False;
143         if (!per_read_object_identifier(s, t124_02_98_oid))
144                 return False;
145
146         /* ConnectData::connectPDU (OCTET_STRING) */
147         if (!per_read_length(s, &length))
148                 return False;
149
150         /* ConnectGCCPDU */
151         if (!per_read_choice(s, &choice))
152                 return False;
153         if (!per_read_selection(s, &selection))
154                 return False;
155
156         /* ConferenceCreateRequest::conferenceName */
157         if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
158                 return False;
159         if (!per_read_padding(s, 1)) /* padding */
160                 return False;
161
162         /* UserData (SET OF SEQUENCE) */
163         if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
164                 return False;
165         if (!per_read_choice(s, &choice) || choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
166                 return False;
167
168         /* h221NonStandard */
169         if (!per_read_octet_string(s, h221_cs_key, 4, 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
170                 return False;
171
172         /* userData::value (OCTET_STRING) */
173         if (!per_read_length(s, &length))
174                 return False;
175         if (stream_get_left(s) < length)
176                 return False;
177         if (!gcc_read_client_data_blocks(s, settings, length))
178                 return False;
179
180         return True;
181 }
182
183 /**
184  * Write a GCC Conference Create Request.\n
185  * @msdn{cc240836}
186  * @param s stream
187  * @param user_data client data blocks
188  */
189
190 void gcc_write_conference_create_request(STREAM* s, STREAM* user_data)
191 {
192         /* ConnectData */
193         per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */
194         per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
195
196         /* ConnectData::connectPDU (OCTET_STRING) */
197         per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
198
199         /* ConnectGCCPDU */
200         per_write_choice(s, 0); /* From ConnectGCCPDU select conferenceCreateRequest (0) of type ConferenceCreateRequest */
201         per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */
202
203         /* ConferenceCreateRequest::conferenceName */
204         per_write_numeric_string(s, (uint8*)"1", 1, 1); /* ConferenceName::numeric */
205         per_write_padding(s, 1); /* padding */
206
207         /* UserData (SET OF SEQUENCE) */
208         per_write_number_of_sets(s, 1); /* one set of UserData */
209         per_write_choice(s, 0xC0); /* UserData::value present + select h221NonStandard (1) */
210
211         /* h221NonStandard */
212         per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
213
214         /* userData::value (OCTET_STRING) */
215         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of client data blocks */
216 }
217
218 void gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
219 {
220         uint16 length;
221         uint32 tag;
222         uint16 nodeID;
223         uint8 result;
224         uint8 choice;
225         uint8 number;
226
227         /* ConnectData */
228         per_read_choice(s, &choice);
229         per_read_object_identifier(s, t124_02_98_oid);
230
231         /* ConnectData::connectPDU (OCTET_STRING) */
232         per_read_length(s, &length);
233
234         /* ConnectGCCPDU */
235         per_read_choice(s, &choice);
236
237         /* ConferenceCreateResponse::nodeID (UserID) */
238         per_read_integer16(s, &nodeID, 1001);
239
240         /* ConferenceCreateResponse::tag (INTEGER) */
241         per_read_integer(s, &tag);
242
243         /* ConferenceCreateResponse::result (ENUMERATED) */
244         per_read_enumerated(s, &result, MCS_Result_enum_length);
245
246         /* number of UserData sets */
247         per_read_number_of_sets(s, &number);
248
249         /* UserData::value present + select h221NonStandard (1) */
250         per_read_choice(s, &choice);
251
252         /* h221NonStandard */
253         per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
254
255         /* userData (OCTET_STRING) */
256         per_read_length(s, &length);
257         gcc_read_server_data_blocks(s, settings, length);
258 }
259
260 boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length)
261 {
262         uint16 type;
263         uint16 blockLength;
264         int pos;
265
266         while (length > 0)
267         {
268                 pos = stream_get_pos(s);
269                 gcc_read_user_data_header(s, &type, &blockLength);
270
271                 switch (type)
272                 {
273                         case CS_CORE:
274                                 if (!gcc_read_client_core_data(s, settings, blockLength - 4))
275                                         return False;
276                                 break;
277
278                         case CS_SECURITY:
279                                 if (!gcc_read_client_security_data(s, settings))
280                                         return False;
281                                 break;
282
283                         case CS_NET:
284                                 if (!gcc_read_client_network_data(s, settings))
285                                         return False;
286                                 break;
287
288                         case CS_CLUSTER:
289                                 if (!gcc_read_client_cluster_data(s, settings))
290                                         return False;
291                                 break;
292
293                         case CS_MONITOR:
294                                 if (!gcc_read_client_monitor_data(s, settings))
295                                         return False;
296                                 break;
297
298                         default:
299                                 break;
300                 }
301
302                 length -= blockLength;
303                 stream_set_pos(s, pos + blockLength);
304         }
305
306         return True;
307 }
308
309 void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
310 {
311         gcc_write_client_core_data(s, settings);
312         gcc_write_client_cluster_data(s, settings);
313         gcc_write_client_security_data(s, settings);
314         gcc_write_client_network_data(s, settings);
315         gcc_write_client_monitor_data(s, settings);
316 }
317
318 void gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
319 {
320         uint16 type;
321         uint16 offset = 0;
322         uint16 blockLength;
323
324         while (offset < length)
325         {
326                 gcc_read_user_data_header(s, &type, &blockLength);
327
328                 switch (type)
329                 {
330                         case SC_CORE:
331                                 gcc_read_server_core_data(s, settings);
332                                 break;
333
334                         case SC_SECURITY:
335                                 gcc_read_server_security_data(s, settings);
336                                 break;
337
338                         case SC_NET:
339                                 gcc_read_server_network_data(s, settings);
340                                 break;
341
342                         default:
343                                 break;
344                 }
345
346                 offset += blockLength;
347         }
348 }
349
350 void gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
351 {
352         stream_read_uint16(s, *type); /* type */
353         stream_read_uint16(s, *length); /* length */
354 }
355
356 /**
357  * Write a user data header (TS_UD_HEADER).\n
358  * @msdn{cc240509}
359  * @param s stream
360  * @param type data block type
361  * @param length data block length
362  */
363
364 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
365 {
366         stream_write_uint16(s, type); /* type */
367         stream_write_uint16(s, length); /* length */
368 }
369
370 /**
371  * Read a client core data block (TS_UD_CS_CORE).\n
372  * @msdn{cc240510}
373  * @param s stream
374  * @param settings rdp settings
375  */
376
377 boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
378 {
379         uint32 version;
380         uint16 colorDepth = 0;
381         uint16 postBeta2ColorDepth = 0;
382         uint16 highColorDepth = 0;
383         uint16 supportedColorDepths = 0;
384         uint16 earlyCapabilityFlags = 0;
385         uint32 serverSelectedProtocol = 0;
386         char* str;
387
388         /* Length of all required fields, until imeFileName */
389         if (blockLength < 128)
390                 return False;
391
392         stream_read_uint32(s, version); /* version */
393         settings->rdp_version = (version == RDP_VERSION_4 ? 5 : 4);
394
395         stream_read_uint16(s, settings->width); /* desktopWidth */
396         stream_read_uint16(s, settings->height); /* desktopHeight */
397         stream_read_uint16(s, colorDepth); /* colorDepth */
398         stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */
399         stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */
400         stream_read_uint32(s, settings->client_build); /* clientBuild */
401         
402         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
403         str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32);
404         stream_seek(s, 32);
405         snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str);
406         xfree(str);
407
408         stream_read_uint32(s, settings->kbd_type); /* keyboardType */
409         stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */
410         stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
411
412         stream_seek(s, 64); /* imeFileName */
413
414         blockLength -= 128;
415
416         /**
417          * The following fields are all optional. If one field is present, all of the preceding
418          * fields MUST also be present. If one field is not present, all of the subsequent fields
419          * MUST NOT be present.
420          * We must check the bytes left before reading each field.
421          */
422
423         do
424         {
425                 if (blockLength < 2)
426                         break;
427                 stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
428                 blockLength -= 2;
429
430                 if (blockLength < 2)
431                         break;
432                 stream_seek_uint16(s); /* clientProductID */
433                 blockLength -= 2;
434
435                 if (blockLength < 4)
436                         break;
437                 stream_seek_uint32(s); /* serialNumber */
438                 blockLength -= 4;
439
440                 if (blockLength < 2)
441                         break;
442                 stream_read_uint16(s, highColorDepth); /* highColorDepth */
443                 blockLength -= 2;
444
445                 if (blockLength < 2)
446                         break;
447                 stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */
448                 blockLength -= 2;
449
450                 if (blockLength < 2)
451                         break;
452                 stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
453                 blockLength -= 2;
454
455                 if (blockLength < 64)
456                         break;
457                 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
458                 stream_seek(s, 64);
459                 snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
460                 xfree(str);
461                 blockLength -= 64;
462
463                 if (blockLength < 1)
464                         break;
465                 stream_read_uint8(s, settings->performance_flags); /* connectionType */
466                 blockLength -= 1;
467
468                 if (blockLength < 1)
469                         break;
470                 stream_seek_uint8(s); /* pad1octet */
471                 blockLength -= 1;
472
473                 if (blockLength < 4)
474                         break;
475                 stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */
476                 blockLength -= 4;
477
478                 if (settings->selected_protocol != serverSelectedProtocol)
479                         return False;
480         } while (0);
481
482         return True;
483 }
484
485 /**
486  * Write a client core data block (TS_UD_CS_CORE).\n
487  * @msdn{cc240510}
488  * @param s stream
489  * @param settings rdp settings
490  */
491
492 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
493 {
494         uint32 version;
495         char* clientName;
496         size_t clientNameLength;
497         uint8 connectionType;
498         uint16 highColorDepth;
499         uint16 supportedColorDepths;
500         uint16 earlyCapabilityFlags;
501         char* clientDigProductId;
502         size_t clientDigProductIdLength;
503
504         gcc_write_user_data_header(s, CS_CORE, 216);
505
506         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
507         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
508         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
509
510         stream_write_uint32(s, version); /* version */
511         stream_write_uint16(s, settings->width); /* desktopWidth */
512         stream_write_uint16(s, settings->height); /* desktopHeight */
513         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
514         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
515         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
516         stream_write_uint32(s, settings->client_build); /* clientBuild */
517
518         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
519         if (clientNameLength > 30)
520         {
521                 clientNameLength = 30;
522                 clientName[clientNameLength] = 0;
523                 clientName[clientNameLength + 1] = 0;
524         }
525         stream_write(s, clientName, clientNameLength + 2);
526         stream_write_zero(s, 32 - clientNameLength - 2);
527         xfree(clientName);
528
529         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
530         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
531         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
532
533         stream_write_zero(s, 64); /* imeFileName */
534
535         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
536         stream_write_uint16(s, 1); /* clientProductID */
537         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
538
539         highColorDepth = MIN(settings->color_depth, 24);
540
541         supportedColorDepths =
542                         RNS_UD_24BPP_SUPPORT |
543                         RNS_UD_16BPP_SUPPORT |
544                         RNS_UD_15BPP_SUPPORT;
545
546         connectionType = 0;
547         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
548
549         if (settings->performance_flags == PERF_FLAG_NONE)
550         {
551                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
552                 connectionType = CONNECTION_TYPE_LAN;
553         }
554
555         if (settings->color_depth == 32)
556         {
557                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
558                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
559         }
560
561         stream_write_uint16(s, highColorDepth); /* highColorDepth */
562         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
563
564         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
565
566         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
567         if (clientDigProductIdLength > 62)
568         {
569                 clientDigProductIdLength = 62;
570                 clientDigProductId[clientDigProductIdLength] = 0;
571                 clientDigProductId[clientDigProductIdLength + 1] = 0;
572         }
573         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
574         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
575         xfree(clientDigProductId);
576
577         stream_write_uint8(s, connectionType); /* connectionType */
578         stream_write_uint8(s, 0); /* pad1octet */
579
580         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
581 }
582
583 void gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
584 {
585         uint32 version;
586         uint32 clientRequestedProtocols;
587
588         stream_read_uint32(s, version); /* version */
589         stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
590
591         if (version == RDP_VERSION_4 && settings->rdp_version > 4)
592                 settings->rdp_version = 4;
593         else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
594                 settings->rdp_version = 7;
595 }
596
597 /**
598  * Read a client security data block (TS_UD_CS_SEC).\n
599  * @msdn{cc240511}
600  * @param s stream
601  * @param settings rdp settings
602  */
603
604 boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings)
605 {
606         printf("CS_SECURITY\n");
607         return True;
608 }
609
610 /**
611  * Write a client security data block (TS_UD_CS_SEC).\n
612  * @msdn{cc240511}
613  * @param s stream
614  * @param settings rdp settings
615  */
616
617 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
618 {
619         gcc_write_user_data_header(s, CS_SECURITY, 12);
620
621         if (settings->encryption > 0)
622         {
623                 stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
624                 stream_write_uint32(s, 0); /* extEncryptionMethods */
625         }
626         else
627         {
628                 /* French locale, disable encryption */
629                 stream_write_uint32(s, 0); /* encryptionMethods */
630                 stream_write_uint32(s, settings->encryption_method); /* extEncryptionMethods */
631         }
632 }
633
634 void gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
635 {
636         uint32 encryptionMethod;
637         uint32 encryptionLevel;
638         uint32 serverRandomLen;
639         uint32 serverCertLen;
640
641         stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
642         stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
643         stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
644         stream_read_uint32(s, serverCertLen); /* serverCertLen */
645
646         if (encryptionMethod == 0 && encryptionLevel == 0)
647         {
648                 /* serverRandom and serverRandom must not be present */
649                 return;
650         }
651
652         if (serverRandomLen > 0)
653         {
654                 /* serverRandom */
655                 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
656                 memcpy(settings->server_random.data, s->p, serverRandomLen);
657                 stream_seek(s, serverRandomLen);
658         }
659
660         if (serverCertLen > 0)
661         {
662                 /* serverCertificate */
663                 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
664                 memcpy(settings->server_certificate.data, s->p, serverCertLen);
665                 stream_seek(s, serverCertLen);
666         }
667 }
668
669 /**
670  * Read a client network data block (TS_UD_CS_NET).\n
671  * @msdn{cc240512}
672  * @param s stream
673  * @param settings rdp settings
674  */
675
676 boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings)
677 {
678         printf("CS_NETWORK\n");
679         return True;
680 }
681
682 /**
683  * Write a client network data block (TS_UD_CS_NET).\n
684  * @msdn{cc240512}
685  * @param s stream
686  * @param settings rdp settings
687  */
688
689 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
690 {
691         int i;
692         uint16 length;
693
694         if (settings->num_channels > 0)
695         {
696                 length = settings->num_channels * 12 + 8;
697                 gcc_write_user_data_header(s, CS_NET, length);
698
699                 stream_write_uint32(s, settings->num_channels); /* channelCount */
700
701                 /* channelDefArray */
702                 for (i = 0; i < settings->num_channels; i++)
703                 {
704                         /* CHANNEL_DEF */
705                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
706                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
707                 }
708         }
709 }
710
711 void gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
712 {
713         int i;
714         uint16 MCSChannelId;
715         uint16 channelCount;
716         uint16 channelId;
717
718         stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
719         stream_read_uint16(s, channelCount); /* channelCount */
720
721         if (channelCount != settings->num_channels)
722         {
723                 printf("requested %d channels, got %d instead\n",
724                                 settings->num_channels, channelCount);
725         }
726
727         for (i = 0; i < channelCount; i++)
728         {
729                 stream_read_uint16(s, channelId); /* channelId */
730                 settings->channels[i].chan_id = channelId;
731         }
732
733         if (channelCount % 2 == 1)
734                 stream_seek(s, 2); /* padding */
735 }
736
737 /**
738  * Read a client cluster data block (TS_UD_CS_CLUSTER).\n
739  * @msdn{cc240514}
740  * @param s stream
741  * @param settings rdp settings
742  */
743
744 boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings)
745 {
746         printf("CS_CLUSTER\n");
747         return True;
748 }
749
750 /**
751  * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
752  * @msdn{cc240514}
753  * @param s stream
754  * @param settings rdp settings
755  */
756
757 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
758 {
759         uint32 flags;
760
761         gcc_write_user_data_header(s, CS_CLUSTER, 12);
762
763         flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
764
765         if (settings->console_session || settings->redirected_session_id)
766                 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
767
768         stream_write_uint32(s, flags); /* flags */
769         stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
770 }
771
772 /**
773  * Read a client monitor data block (TS_UD_CS_MONITOR).\n
774  * @msdn{dd305336}
775  * @param s stream
776  * @param settings rdp settings
777  */
778
779 boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings)
780 {
781         printf("CS_MONITOR\n");
782         return True;
783 }
784
785 /**
786  * Write a client monitor data block (TS_UD_CS_MONITOR).\n
787  * @msdn{dd305336}
788  * @param s stream
789  * @param settings rdp settings
790  */
791
792 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
793 {
794         int i;
795         uint16 length;
796         uint32 left, top, right, bottom, flags;
797
798         if (settings->num_monitors > 1)
799         {
800                 length = (20 * settings->num_monitors) + 12;
801                 gcc_write_user_data_header(s, CS_MONITOR, length);
802
803                 stream_write_uint32(s, 0); /* flags */
804                 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
805
806                 for (i = 0; i < settings->num_monitors; i++)
807                 {
808                         left = settings->monitors[i].x;
809                         top = settings->monitors[i].y;
810                         right = settings->monitors[i].x + settings->monitors[i].width - 1;
811                         bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
812                         flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
813
814                         stream_write_uint32(s, left); /* left */
815                         stream_write_uint32(s, top); /* top */
816                         stream_write_uint32(s, right); /* right */
817                         stream_write_uint32(s, bottom); /* bottom */
818                         stream_write_uint32(s, flags); /* flags */
819                 }
820         }
821 }
822