Merge branch 'master' of github.com:FreeRDP/FreeRDP-1.0
[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  * ConferenceName ::= SEQUENCE
76  * {
77  *      numeric                         SimpleNumericString
78  *      text                            SimpleTextString OPTIONAL,
79  *      ...
80  * }
81  *
82  * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
83  *
84  * UserData ::= SET OF SEQUENCE
85  * {
86  *      key                             Key,
87  *      value                           OCTET_STRING OPTIONAL
88  * }
89  *
90  * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
91  *
92  */
93
94 /*
95  * OID = 0.0.20.124.0.1
96  * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
97  * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
98  */
99 uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
100
101 /**
102  * Write a GCC Conference Create Request.\n
103  * @msdn{cc240836}
104  * @param s stream
105  * @param user_data client data blocks
106  */
107
108 void gcc_write_create_conference_request(STREAM* s, STREAM* user_data)
109 {
110         /* ConnectData */
111         per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */
112         per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
113
114         /* ConnectData::connectPDU (OCTET_STRING) */
115         per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */
116
117         /* ConnectGCCPDU */
118         per_write_choice(s, 0); /* From ConnectGCCPDU select conferenceCreateRequest (0) of type ConferenceCreateRequest */
119         per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */
120
121         /* ConferenceCreateRequest::conferenceName */
122         per_write_numeric_string(s, "1", 1, 1); /* ConferenceName::numeric */
123         per_write_padding(s, 1); /* padding */
124
125         /* UserData (SET OF SEQUENCE) */
126         per_write_number_of_sets(s, 1); /* one set of UserData */
127         per_write_choice(s, 0xC0); /* UserData::value present + select h221NonStandard (1) */
128
129         /* h221NonStandard */
130         per_write_octet_string(s, "Duca", 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
131
132         /* userData::value (OCTET_STRING) */
133         per_write_octet_string(s, user_data->data, stream_get_length(user_data), 0); /* array of client data blocks */
134 }
135
136 /**
137  * Write a user data header (TS_UD_HEADER).\n
138  * @msdn{cc240509}
139  * @param s stream
140  * @param type data block type
141  * @param length data block length
142  */
143
144 void gcc_write_user_data_header(STREAM* s, uint16 type, uint16 length)
145 {
146         stream_write_uint16(s, type); /* type */
147         stream_write_uint16(s, length); /* length */
148 }
149
150 /**
151  * Write a client core data block (TS_UD_CS_CORE).\n
152  * @msdn{cc240510}
153  * @param s stream
154  * @param settings rdp settings
155  */
156
157 void gcc_write_client_core_data(STREAM* s, rdpSettings *settings)
158 {
159         uint32 version;
160         uint8* clientName;
161         size_t clientNameLength;
162         uint8 connectionType;
163         uint16 highColorDepth;
164         uint16 supportedColorDepths;
165         uint16 earlyCapabilityFlags;
166         uint8* clientDigProductId;
167         size_t clientDigProductIdLength;
168
169         gcc_write_user_data_header(s, CS_CORE, 216);
170
171         version = settings->rdp_version >= 5 ? RDP_VERSION_5_PLUS : RDP_VERSION_4;
172         clientName = freerdp_uniconv_out(settings->uniconv, settings->client_hostname, &clientNameLength);
173         clientDigProductId = freerdp_uniconv_out(settings->uniconv, settings->client_product_id, &clientDigProductIdLength);
174
175         stream_write_uint32(s, version); /* version */
176         stream_write_uint16(s, settings->width); /* desktopWidth */
177         stream_write_uint16(s, settings->height); /* desktopHeight */
178         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* colorDepth, ignored because of postBeta2ColorDepth */
179         stream_write_uint16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
180         stream_write_uint32(s, settings->kbd_layout); /* keyboardLayout */
181         stream_write_uint32(s, settings->client_build); /* clientBuild */
182
183         /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
184         if (clientNameLength > 30)
185         {
186                 clientNameLength = 30;
187                 clientName[clientNameLength] = 0;
188                 clientName[clientNameLength + 1] = 0;
189         }
190         stream_write(s, clientName, clientNameLength + 2);
191         stream_write_zero(s, 32 - clientNameLength - 2);
192         xfree(clientName);
193
194         stream_write_uint32(s, settings->kbd_type); /* keyboardType */
195         stream_write_uint32(s, settings->kbd_subtype); /* keyboardSubType */
196         stream_write_uint32(s, settings->kbd_fn_keys); /* keyboardFunctionKey */
197
198         stream_write_zero(s, 64); /* imeFileName */
199
200         stream_write_uint16(s, RNS_UD_COLOR_8BPP); /* postBeta2ColorDepth */
201         stream_write_uint16(s, 1); /* clientProductID */
202         stream_write_uint32(s, 0); /* serialNumber (should be initialized to 0) */
203
204         highColorDepth = MIN(settings->color_depth, 24);
205         supportedColorDepths = RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT;
206
207         connectionType = 0;
208         earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
209
210         if (settings->performance_flags == PERF_FLAG_NONE)
211         {
212                 earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
213                 connectionType = CONNECTION_TYPE_LAN;
214         }
215
216         if (settings->color_depth == 32)
217         {
218                 supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
219                 earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
220         }
221
222         stream_write_uint16(s, highColorDepth); /* highColorDepth */
223         stream_write_uint16(s, supportedColorDepths); /* supportedColorDepths */
224
225         stream_write_uint16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
226
227         /* clientDigProductId (64 bytes, null-terminated unicode, truncated to 30 characters) */
228         if (clientDigProductIdLength > 62)
229         {
230                 clientDigProductIdLength = 62;
231                 clientDigProductId[clientDigProductIdLength] = 0;
232                 clientDigProductId[clientDigProductIdLength + 1] = 0;
233         }
234         stream_write(s, clientDigProductId, clientDigProductIdLength + 2);
235         stream_write_zero(s, 64 - clientDigProductIdLength - 2);
236         xfree(clientDigProductId);
237
238         stream_write_uint8(s, connectionType); /* connectionType */
239         stream_write_uint8(s, 0); /* pad1octet */
240
241         stream_write_uint32(s, settings->selected_protocol); /* serverSelectedProtocol */
242 }
243
244 /**
245  * Write a client security data block (TS_UD_CS_SEC).\n
246  * @msdn{cc240511}
247  * @param s stream
248  * @param settings rdp settings
249  */
250
251 void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
252 {
253         uint16 encryptionMethods;
254
255         gcc_write_user_data_header(s, CS_SECURITY, 12);
256
257         encryptionMethods =
258                         ENCRYPTION_40BIT_FLAG |
259                         ENCRYPTION_56BIT_FLAG |
260                         ENCRYPTION_128BIT_FLAG |
261                         ENCRYPTION_FIPS_FLAG;
262
263         if (settings->encryption > 0)
264         {
265                 stream_write_uint32(s, encryptionMethods); /* encryptionMethods */
266                 stream_write_uint32(s, 0); /* extEncryptionMethods */
267         }
268         else
269         {
270                 /* French locale, disable encryption */
271                 stream_write_uint32(s, 0); /* encryptionMethods */
272                 stream_write_uint32(s, encryptionMethods); /* extEncryptionMethods */
273         }
274 }
275
276 /**
277  * Write a client network data block (TS_UD_CS_NET).\n
278  * @msdn{cc240512}
279  * @param s stream
280  * @param settings rdp settings
281  */
282
283 void gcc_write_client_network_data(STREAM* s, rdpSettings *settings)
284 {
285         int i;
286         uint16 length;
287
288         if (settings->num_channels > 0)
289         {
290                 length = settings->num_channels * 12 + 8;
291                 gcc_write_user_data_header(s, CS_NET, length);
292
293                 stream_write_uint32(s, settings->num_channels); /* channelCount */
294
295                 /* channelDefArray */
296                 for (i = 0; i < settings->num_channels; i++)
297                 {
298                         /* CHANNEL_DEF */
299                         stream_write(s, settings->channels[i].name, 8); /* name (8 bytes) */
300                         stream_write_uint32(s, settings->channels[i].options); /* options (4 bytes) */
301                 }
302         }
303 }
304
305 /**
306  * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
307  * @msdn{cc240514}
308  * @param s stream
309  * @param settings rdp settings
310  */
311
312 void gcc_write_client_cluster_data(STREAM* s, rdpSettings *settings)
313 {
314         uint32 flags;
315
316         gcc_write_user_data_header(s, CS_CLUSTER, 12);
317
318         flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
319
320         if (settings->console_session || settings->redirected_session_id)
321                 flags |= REDIRECTED_SESSIONID_FIELD_VALID;
322
323         stream_write_uint32(s, flags); /* flags */
324         stream_write_uint32(s, settings->redirected_session_id); /* redirectedSessionID */
325 }
326
327 /**
328  * Write a client monitor data block (TS_UD_CS_MONITOR).\n
329  * @msdn{dd305336}
330  * @param s stream
331  * @param settings rdp settings
332  */
333
334 void gcc_write_client_monitor_data(STREAM* s, rdpSettings *settings)
335 {
336         int i;
337         uint16 length;
338         uint32 left, top, right, bottom, flags;
339
340         if (settings->num_monitors > 1)
341         {
342                 length = (20 * settings->num_monitors) + 12;
343                 gcc_write_user_data_header(s, CS_MONITOR, length);
344
345                 stream_write_uint32(s, 0); /* flags */
346                 stream_write_uint32(s, settings->num_monitors); /* monitorCount */
347
348                 for (i = 0; i < settings->num_monitors; i++)
349                 {
350                         left = settings->monitors[i].x;
351                         top = settings->monitors[i].y;
352                         right = settings->monitors[i].x + settings->monitors[i].width - 1;
353                         bottom = settings->monitors[i].y + settings->monitors[i].height - 1;
354                         flags = settings->monitors[i].is_primary ? MONITOR_PRIMARY : 0;
355
356                         stream_write_uint32(s, left); /* left */
357                         stream_write_uint32(s, top); /* top */
358                         stream_write_uint32(s, right); /* right */
359                         stream_write_uint32(s, bottom); /* bottom */
360                         stream_write_uint32(s, flags); /* flags */
361                 }
362         }
363 }