2 * FreeRDP: A Remote Desktop Protocol Client
3 * T.124 Generic Conference Control (GCC)
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * T.124 GCC is defined in:
25 * http://www.itu.int/rec/T-REC-T.124-199802-S/en
26 * ITU-T T.124 (02/98): Generic Conference Control
30 * ConnectData ::= SEQUENCE
33 * connectPDU OCTET_STRING
38 * object OBJECT_IDENTIFIER,
39 * h221NonStandard H221NonStandardIdentifier
42 * ConnectGCCPDU ::= CHOICE
44 * conferenceCreateRequest ConferenceCreateRequest,
45 * conferenceCreateResponse ConferenceCreateResponse,
46 * conferenceQueryRequest ConferenceQueryRequest,
47 * conferenceQueryResponse ConferenceQueryResponse,
48 * conferenceJoinRequest ConferenceJoinRequest,
49 * conferenceJoinResponse ConferenceJoinResponse,
50 * conferenceInviteRequest ConferenceInviteRequest,
51 * conferenceInviteResponse ConferenceInviteResponse,
55 * ConferenceCreateRequest ::= SEQUENCE
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,
71 * conferencePriority ConferencePriority OPTIONAL,
72 * conferenceMode ConferenceMode OPTIONAL
75 * ConferenceCreateResponse ::= SEQUENCE
83 * resourcesNotAvailable (2),
84 * rejectedForSymmetryBreaking (3),
85 * lockedConferenceNotSupported (4)
87 * userData UserData OPTIONAL,
91 * ConferenceName ::= SEQUENCE
93 * numeric SimpleNumericString
94 * text SimpleTextString OPTIONAL,
98 * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
100 * UserData ::= SET OF SEQUENCE
103 * value OCTET_STRING OPTIONAL
106 * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
108 * UserID ::= DynamicChannelID
110 * ChannelID ::= INTEGER (1..65535)
111 * StaticChannelID ::= INTEGER (1..1000)
112 * DynamicChannelID ::= INTEGER (1001..65535)
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"
121 uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
123 uint8 h221_cs_key[4] = "Duca";
124 uint8 h221_sc_key[4] = "McDn";
127 * Read a GCC Conference Create Request.\n
130 * @param settings rdp settings
133 boolean gcc_read_conference_create_request(STREAM* s, rdpSettings* settings)
141 if (!per_read_choice(s, &choice))
143 if (!per_read_object_identifier(s, t124_02_98_oid))
146 /* ConnectData::connectPDU (OCTET_STRING) */
147 if (!per_read_length(s, &length))
151 if (!per_read_choice(s, &choice))
153 if (!per_read_selection(s, &selection))
156 /* ConferenceCreateRequest::conferenceName */
157 if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
159 if (!per_read_padding(s, 1)) /* padding */
162 /* UserData (SET OF SEQUENCE) */
163 if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
165 if (!per_read_choice(s, &choice) || choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
168 /* h221NonStandard */
169 if (!per_read_octet_string(s, h221_cs_key, 4, 4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
172 /* userData::value (OCTET_STRING) */
173 if (!per_read_length(s, &length))
175 if (stream_get_left(s) < length)
177 if (!gcc_read_client_data_blocks(s, settings, length))
184 * Write a GCC Conference Create Request.\n
187 * @param user_data client data blocks
190 void gcc_write_conference_create_request(STREAM* s, STREAM* user_data)
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 */
196 /* ConnectData::connectPDU (OCTET_STRING) */
197 per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
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 */
203 /* ConferenceCreateRequest::conferenceName */
204 per_write_numeric_string(s, (uint8*)"1", 1, 1); /* ConferenceName::numeric */
205 per_write_padding(s, 1); /* padding */
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) */
211 /* h221NonStandard */
212 per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
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 */
218 boolean gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
228 per_read_choice(s, &choice);
229 per_read_object_identifier(s, t124_02_98_oid);
231 /* ConnectData::connectPDU (OCTET_STRING) */
232 per_read_length(s, &length);
235 per_read_choice(s, &choice);
237 /* ConferenceCreateResponse::nodeID (UserID) */
238 per_read_integer16(s, &nodeID, 1001);
240 /* ConferenceCreateResponse::tag (INTEGER) */
241 per_read_integer(s, &tag);
243 /* ConferenceCreateResponse::result (ENUMERATED) */
244 per_read_enumerated(s, &result, MCS_Result_enum_length);
246 /* number of UserData sets */
247 per_read_number_of_sets(s, &number);
249 /* UserData::value present + select h221NonStandard (1) */
250 per_read_choice(s, &choice);
252 /* h221NonStandard */
253 per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
255 /* userData (OCTET_STRING) */
256 per_read_length(s, &length);
257 if (!gcc_read_server_data_blocks(s, settings, length))
263 void gcc_write_conference_create_response(STREAM* s, STREAM* user_data)
266 per_write_choice(s, 0);
267 per_write_object_identifier(s, t124_02_98_oid);
269 /* ConnectData::connectPDU (OCTET_STRING) */
270 per_write_length(s, stream_get_length(user_data) + 2);
273 per_write_choice(s, 0x14);
275 /* ConferenceCreateResponse::nodeID (UserID) */
276 per_write_integer16(s, 0x79F3, 1001);
278 /* ConferenceCreateResponse::tag (INTEGER) */
279 per_write_integer(s, 1);
281 /* ConferenceCreateResponse::result (ENUMERATED) */
282 per_write_enumerated(s, 0, MCS_Result_enum_length);
284 /* number of UserData sets */
285 per_write_number_of_sets(s, 1);
287 /* UserData::value present + select h221NonStandard (1) */
288 per_write_choice(s, 0xC0);
290 /* h221NonStandard */
291 per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
293 /* userData (OCTET_STRING) */
294 per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of server data blocks */
297 boolean gcc_read_client_data_blocks(STREAM* s, rdpSettings *settings, int length)
305 pos = stream_get_pos(s);
306 gcc_read_user_data_header(s, &type, &blockLength);
311 if (!gcc_read_client_core_data(s, settings, blockLength - 4))
316 if (!gcc_read_client_security_data(s, settings, blockLength - 4))
321 if (!gcc_read_client_network_data(s, settings, blockLength - 4))
326 if (!gcc_read_client_cluster_data(s, settings, blockLength - 4))
331 if (!gcc_read_client_monitor_data(s, settings, blockLength - 4))
339 length -= blockLength;
340 stream_set_pos(s, pos + blockLength);
346 void gcc_write_client_data_blocks(STREAM* s, rdpSettings *settings)
348 gcc_write_client_core_data(s, settings);
349 gcc_write_client_cluster_data(s, settings);
350 gcc_write_client_security_data(s, settings);
351 gcc_write_client_network_data(s, settings);
352 gcc_write_client_monitor_data(s, settings);
355 boolean gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length)
361 while (offset < length)
363 if (!gcc_read_user_data_header(s, &type, &blockLength))
369 if (!gcc_read_server_core_data(s, settings))
374 if (!gcc_read_server_security_data(s, settings))
379 if (!gcc_read_server_network_data(s, settings))
387 offset += blockLength;
393 void gcc_write_server_data_blocks(STREAM* s, rdpSettings *settings)
395 gcc_write_server_core_data(s, settings);
396 gcc_write_server_network_data(s, settings);
397 gcc_write_server_security_data(s, settings);
400 boolean gcc_read_user_data_header(STREAM* s, uint16* type, uint16* length)
402 stream_read_uint16(s, *type); /* type */
403 stream_read_uint16(s, *length); /* length */
405 if (stream_get_left(s) < *length - 4)
412 * Write a user data header (TS_UD_HEADER).\n
415 * @param type data block type
416 * @param length data block length
419 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
421 stream_write_uint16(s, type); /* type */
422 stream_write_uint16(s, length); /* length */
426 * Read a client core data block (TS_UD_CS_CORE).\n
429 * @param settings rdp settings
432 boolean gcc_read_client_core_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
435 uint16 colorDepth = 0;
436 uint16 postBeta2ColorDepth = 0;
437 uint16 highColorDepth = 0;
438 uint16 supportedColorDepths = 0;
439 uint16 earlyCapabilityFlags = 0;
440 uint32 serverSelectedProtocol = 0;
443 /* Length of all required fields, until imeFileName */
444 if (blockLength < 128)
447 stream_read_uint32(s, version); /* version */
448 settings->rdp_version = (version == RDP_VERSION_4 ? 4 : 7);
450 stream_read_uint16(s, settings->width); /* desktopWidth */
451 stream_read_uint16(s, settings->height); /* desktopHeight */
452 stream_read_uint16(s, colorDepth); /* colorDepth */
453 stream_seek_uint16(s); /* SASSequence (Secure Access Sequence) */
454 stream_read_uint32(s, settings->kbd_layout); /* keyboardLayout */
455 stream_read_uint32(s, settings->client_build); /* clientBuild */
457 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
458 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 32);
460 snprintf(settings->client_hostname, sizeof(settings->client_hostname), "%s", str);
463 stream_read_uint32(s, settings->kbd_type); /* keyboardType */
464 stream_read_uint32(s, settings->kbd_subtype); /* keyboardSubType */
465 stream_read_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
467 stream_seek(s, 64); /* imeFileName */
472 * The following fields are all optional. If one field is present, all of the preceding
473 * fields MUST also be present. If one field is not present, all of the subsequent fields
474 * MUST NOT be present.
475 * We must check the bytes left before reading each field.
482 stream_read_uint16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
487 stream_seek_uint16(s); /* clientProductID */
492 stream_seek_uint32(s); /* serialNumber */
497 stream_read_uint16(s, highColorDepth); /* highColorDepth */
502 stream_read_uint16(s, supportedColorDepths); /* supportedColorDepths */
507 stream_read_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
510 if (blockLength < 64)
512 str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
514 snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
520 stream_read_uint8(s, settings->performance_flags); /* connectionType */
525 stream_seek_uint8(s); /* pad1octet */
530 stream_read_uint32(s, serverSelectedProtocol); /* serverSelectedProtocol */
533 if (settings->selected_protocol != serverSelectedProtocol)
537 if (highColorDepth > 0)
538 settings->color_depth = highColorDepth;
539 else if (postBeta2ColorDepth > 0)
541 switch (postBeta2ColorDepth)
543 case RNS_UD_COLOR_4BPP:
544 settings->color_depth = 4;
546 case RNS_UD_COLOR_8BPP:
547 settings->color_depth = 8;
549 case RNS_UD_COLOR_16BPP_555:
550 settings->color_depth = 15;
552 case RNS_UD_COLOR_16BPP_565:
553 settings->color_depth = 16;
555 case RNS_UD_COLOR_24BPP:
556 settings->color_depth = 24;
566 case RNS_UD_COLOR_4BPP:
567 settings->color_depth = 4;
569 case RNS_UD_COLOR_8BPP:
570 settings->color_depth = 8;
581 * Write a client core data block (TS_UD_CS_CORE).\n
584 * @param settings rdp settings
587 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
591 size_t clientNameLength;
592 uint8 connectionType;
593 uint16 highColorDepth;
594 uint16 supportedColorDepths;
595 uint16 earlyCapabilityFlags;
596 char* clientDigProductId;
597 size_t clientDigProductIdLength;
599 gcc_write_user_data_header(s, CS_CORE, 216);
601 version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
602 clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
603 clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
605 stream_write_uint32(s, version); /* version */
606 stream_write_uint16(s, settings->width); /* desktopWidth */
607 stream_write_uint16(s, settings->height); /* desktopHeight */
608 stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
609 stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
610 stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
611 stream_write_uint32(s, settings->client_build); /* clientBuild */
613 /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
614 if (clientNameLength > 30)
616 clientNameLength = 30;
617 clientName[clientNameLength] = 0;
618 clientName[clientNameLength + 1] = 0;
620 stream_write(s, clientName, clientNameLength + 2);
621 stream_write_zero(s, 32 - clientNameLength - 2);
624 stream_write_uint32(s, settings->kbd_type); /* keyboardType */
625 stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
626 stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
628 stream_write_zero(s, 64); /* imeFileName */
630 stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
631 stream_write_uint16(s, 1); /* clientProductID */
632 stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
634 highColorDepth = MIN(settings->color_depth, 24);
636 supportedColorDepths =
637 RNS_UD_24BPP_SUPPORT |
638 RNS_UD_16BPP_SUPPORT |
639 RNS_UD_15BPP_SUPPORT;
642 earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
644 if (settings->performance_flags == PERF_FLAG_NONE)
646 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
647 connectionType = CONNECTION_TYPE_LAN;
650 if (settings->color_depth == 32)
652 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
653 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
656 stream_write_uint16(s, highColorDepth); /* highColorDepth */
657 stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
659 stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
661 /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
662 if (clientDigProductIdLength > 62)
664 clientDigProductIdLength = 62;
665 clientDigProductId[clientDigProductIdLength] = 0;
666 clientDigProductId[clientDigProductIdLength + 1] = 0;
668 stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
669 stream_write_zero(s, 64 - clientDigProductIdLength - 2);
670 xfree(clientDigProductId);
672 stream_write_uint8(s, connectionType); /* connectionType */
673 stream_write_uint8(s, 0); /* pad1octet */
675 stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
678 boolean gcc_read_server_core_data(STREAM* s, rdpSettings *settings)
681 uint32 clientRequestedProtocols;
683 stream_read_uint32(s, version); /* version */
684 stream_read_uint32(s, clientRequestedProtocols); /* clientRequestedProtocols */
686 if (version == RDP_VERSION_4 && settings->rdp_version > 4)
687 settings->rdp_version = 4;
688 else if (version == RDP_VERSION_5_PLUS && settings->rdp_version < 5)
689 settings->rdp_version = 7;
694 void gcc_write_server_core_data(STREAM* s, rdpSettings *settings)
696 gcc_write_user_data_header(s, SC_CORE, 12);
698 stream_write_uint32(s, settings->rdp_version == 4 ? RDP_VERSION_4 : RDP_VERSION_5_PLUS);
699 stream_write_uint32(s, settings->requested_protocols); /* clientRequestedProtocols */
703 * Read a client security data block (TS_UD_CS_SEC).\n
706 * @param settings rdp settings
709 boolean gcc_read_client_security_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
714 stream_read_uint32(s, settings->encryption_method); /* encryptionMethods */
715 if (settings->encryption_method == 0)
716 stream_read_uint32(s, settings->encryption_method); /* extEncryptionMethods */
722 * Write a client security data block (TS_UD_CS_SEC).\n
725 * @param settings rdp settings
728 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
730 gcc_write_user_data_header(s, CS_SECURITY, 12);
732 if (settings->encryption > 0)
734 stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
735 stream_write_uint32(s, 0); /* extEncryptionMethods */
739 /* French locale, disable encryption */
740 stream_write_uint32(s, 0); /* encryptionMethods */
741 stream_write_uint32(s, settings->encryption_method); /* extEncryptionMethods */
745 boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
747 uint32 encryptionMethod;
748 uint32 encryptionLevel;
749 uint32 serverRandomLen;
750 uint32 serverCertLen;
752 stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
753 stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
755 if (encryptionMethod == 0 && encryptionLevel == 0)
757 /* serverRandom and serverRandom must not be present */
761 stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
762 stream_read_uint32(s, serverCertLen); /* serverCertLen */
764 if (serverRandomLen > 0)
767 freerdp_blob_alloc(&settings->server_random, serverRandomLen);
768 memcpy(settings->server_random.data, s->p, serverRandomLen);
769 stream_seek(s, serverRandomLen);
772 if (serverCertLen > 0)
774 /* serverCertificate */
775 freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
776 memcpy(settings->server_certificate.data, s->p, serverCertLen);
777 stream_seek(s, serverCertLen);
783 void gcc_write_server_security_data(STREAM* s, rdpSettings *settings)
785 gcc_write_user_data_header(s, SC_SECURITY, 12);
787 stream_write_uint32(s, ENCRYPTION_METHOD_NONE); /* encryptionMethod */
788 stream_write_uint32(s, ENCRYPTION_LEVEL_NONE); /* encryptionLevel */
790 stream_write_uint32(s, 0); /* serverRandomLen */
791 stream_write_uint32(s, 0); /* serverCertLen */
796 * Read a client network data block (TS_UD_CS_NET).\n
799 * @param settings rdp settings
802 boolean gcc_read_client_network_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
809 stream_read_uint32(s, settings->num_channels); /* channelCount */
810 if (blockLength < 4 + settings->num_channels * 12)
812 if (settings->num_channels > 16)
815 /* channelDefArray */
816 for (i = 0; i < settings->num_channels; i++)
819 stream_read(s, settings->channels[i].name, 8); /* name (8 bytes) */
820 stream_read_uint32(s, settings->channels[i].options); /* options (4 bytes) */
821 settings->channels[i].chan_id = MCS_GLOBAL_CHANNEL_ID + 1 + i;
828 * Write a client network data block (TS_UD_CS_NET).\n
831 * @param settings rdp settings
834 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
839 if (settings->num_channels > 0)
841 length = settings->num_channels * 12 + 8;
842 gcc_write_user_data_header(s, CS_NET, length);
844 stream_write_uint32(s, settings->num_channels); /* channelCount */
846 /* channelDefArray */
847 for (i = 0; i < settings->num_channels; i++)
850 stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
851 stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
856 boolean gcc_read_server_network_data(STREAM* s, rdpSettings *settings)
863 stream_read_uint16(s, MCSChannelId); /* MCSChannelId */
864 stream_read_uint16(s, channelCount); /* channelCount */
866 if (channelCount != settings->num_channels)
868 printf("requested %d channels, got %d instead\n",
869 settings->num_channels, channelCount);
872 for (i = 0; i < channelCount; i++)
874 stream_read_uint16(s, channelId); /* channelId */
875 settings->channels[i].chan_id = channelId;
878 if (channelCount % 2 == 1)
879 stream_seek(s, 2); /* padding */
884 void gcc_write_server_network_data(STREAM* s, rdpSettings *settings)
888 gcc_write_user_data_header(s, SC_NET, 8 + settings->num_channels * 2 + (settings->num_channels % 2 == 1 ? 2 : 0));
890 stream_write_uint16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
891 stream_write_uint16(s, settings->num_channels); /* channelCount */
893 for (i = 0; i < settings->num_channels; i++)
895 stream_write_uint16(s, settings->channels[i].chan_id);
898 if (settings->num_channels % 2 == 1)
899 stream_write_uint16(s, 0);
903 * Read a client cluster data block (TS_UD_CS_CLUSTER).\n
906 * @param settings rdp settings
909 boolean gcc_read_client_cluster_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
916 stream_read_uint32(s, flags); /* flags */
918 if ((flags | REDIRECTED_SESSIONID_FIELD_VALID))
919 stream_read_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
925 * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
928 * @param settings rdp settings
931 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
935 gcc_write_user_data_header(s, CS_CLUSTER, 12);
937 flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
939 if (settings->console_session || settings->redirected_session_id)
940 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
942 stream_write_uint32(s, flags); /* flags */
943 stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
947 * Read a client monitor data block (TS_UD_CS_MONITOR).\n
950 * @param settings rdp settings
953 boolean gcc_read_client_monitor_data(STREAM* s, rdpSettings *settings, uint16 blockLength)
955 printf("CS_MONITOR\n");
960 * Write a client monitor data block (TS_UD_CS_MONITOR).\n
963 * @param settings rdp settings
966 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
970 uint32 left, top, right, bottom, flags;
972 if (settings->num_monitors > 1)
974 length = (20 * settings->num_monitors) + 12;
975 gcc_write_user_data_header(s, CS_MONITOR, length);
977 stream_write_uint32(s, 0); /* flags */
978 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
980 for (i = 0; i < settings->num_monitors; i++)
982 left = settings->monitors[i].x;
983 top = settings->monitors[i].y;
984 right = settings->monitors[i].x + settings->monitors[i].width - 1;
985 bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
986 flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
988 stream_write_uint32(s, left); /* left */
989 stream_write_uint32(s, top); /* top */
990 stream_write_uint32(s, right); /* right */
991 stream_write_uint32(s, bottom); /* bottom */
992 stream_write_uint32(s, flags); /* flags */