/[rdesktop]/jpeg/rdesktop/trunk/rdp.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /jpeg/rdesktop/trunk/rdp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1508 - (show annotations)
Mon Jul 20 16:47:49 2009 UTC (14 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 38413 byte(s)
Date: Sun, 19 Jul 2009 14:00:30 -0400
From: Daniel Jarboe <daniel.jarboe(at)gmail.com>
To: Dobrica Pavlinusic <dpavlin(at)rot13.org>
Subject: Re: rdesktop diff

On Sun, Jul 19, 2009 at 8:01 AM, Dobrica Pavlinusic <dpavlin(at)rot13.org>wrote:
>
> I'm looking forward for your patch, and will keep you informed what I
> did with it :-)

This diff was an earlier one with some debug printfs in so you can see how
the tuning knobs work.  I was only keeping an eye on a young computer user's
activities so ignored small screen changes and wrote out the stills to lossy
jpegs with libjpeg.  If you plan on saving screens no matter if there are
changes or not then I'd throw away all the g_bitmap_data_last_write stuff.

diff is against rdesktop-1.6 with whatever patches are in ubuntu 9.04
jaunty.  Added libjpeg62-dev in addition to the regular rdesktop build
dependencies.  Have fun and thanks for letting me know what you end up with.

~ Daniel

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - RDP layer
4 Copyright (C) Matthew Chapman 1999-2008
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <time.h>
22 #ifndef _WIN32
23 #include <errno.h>
24 #include <unistd.h>
25 #endif
26 #include "rdesktop.h"
27
28 #ifdef HAVE_ICONV
29 #ifdef HAVE_ICONV_H
30 #include <iconv.h>
31 #endif
32
33 #ifndef ICONV_CONST
34 #define ICONV_CONST ""
35 #endif
36 #endif
37
38 #include <jpeglib.h>
39 /* DJ globals begin */
40 extern unsigned long long g_time_last_write;
41 extern unsigned long long g_time_last_change;
42 extern uint32 g_pixels_changed;
43 extern uint8 * g_bitmap_data;
44 extern uint8 * g_bitmap_data_last_write;
45 /* DJ globals end */
46 /* DJ tuning knobs begin */
47 const uint32 PIXELS_CHANGED_THRESHOLD = 8192; /* this many pixel changes */
48 const uint32 PIXELS_STABILIZE_DELAY = 100000; /* no change for .1 sec */
49 const uint32 PIXELS_RESET_INTERVAL = 10000000; /* within 10 second interval */
50 const uint32 MINIMUM_WRITE_INTERVAL = 1000000; /* and 1 sec from last write */
51 /* DJ tuning knobs end */
52
53 extern uint16 g_mcs_userid;
54 extern char *g_username;
55 extern char g_codepage[16];
56 extern RD_BOOL g_bitmap_compression;
57 extern RD_BOOL g_orders;
58 extern RD_BOOL g_encryption;
59 extern RD_BOOL g_desktop_save;
60 extern RD_BOOL g_polygon_ellipse_orders;
61 extern RD_BOOL g_use_rdp5;
62 extern uint16 g_server_rdp_version;
63 extern uint32 g_rdp5_performanceflags;
64 extern int g_server_depth;
65 extern int g_width;
66 extern int g_height;
67 extern RD_BOOL g_bitmap_cache;
68 extern RD_BOOL g_bitmap_cache_persist_enable;
69 extern RD_BOOL g_numlock_sync;
70
71 uint8 *g_next_packet;
72 uint32 g_rdp_shareid;
73
74 extern RDPCOMP g_mppc_dict;
75
76 /* Session Directory support */
77 extern RD_BOOL g_redirect;
78 extern char g_redirect_server[64];
79 extern char g_redirect_domain[16];
80 extern char g_redirect_password[64];
81 extern char *g_redirect_username;
82 extern char g_redirect_cookie[128];
83 extern uint32 g_redirect_flags;
84 /* END Session Directory support */
85
86 #if WITH_DEBUG
87 static uint32 g_packetno;
88 #endif
89
90 #ifdef HAVE_ICONV
91 static RD_BOOL g_iconv_works = True;
92 #endif
93
94 unsigned long long
95 tod(void)
96 {
97 struct timeval tim;
98 unsigned long long ret;
99 gettimeofday(&tim, NULL);
100 ret=tim.tv_sec;
101 ret*=1000000;
102 ret+=tim.tv_usec;
103 return ret;
104 }
105
106 /* Receive an RDP packet */
107 static STREAM
108 rdp_recv(uint8 * type)
109 {
110 static STREAM rdp_s;
111 uint16 length, pdu_type;
112 uint8 rdpver;
113 unsigned long long current_time;
114
115 if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL))
116 {
117 rdp_s = sec_recv(&rdpver);
118 current_time = tod();
119
120 if (g_pixels_changed >= PIXELS_CHANGED_THRESHOLD)
121 {
122 if ((current_time - g_time_last_change) < PIXELS_STABILIZE_DELAY)
123 {
124 printf("%llu still unstable\n", current_time);
125 }
126 else if ((current_time - g_time_last_write) < MINIMUM_WRITE_INTERVAL)
127 {
128 printf("%llu too close to last write\n", current_time);
129 }
130 else
131 write_file();
132 }
133 else if ((current_time - g_time_last_write) > PIXELS_RESET_INTERVAL && g_bitmap_data)
134 {
135 memcpy(g_bitmap_data_last_write, g_bitmap_data, g_width * g_height * 3);
136 printf("reset at g_pixels_changed=%d\n",g_pixels_changed);
137 g_pixels_changed=0;
138 g_time_last_write = current_time;
139 }
140
141 if (rdp_s == NULL)
142 return NULL;
143 if (rdpver == 0xff)
144 {
145 g_next_packet = rdp_s->end;
146 *type = 0;
147 return rdp_s;
148 }
149 else if (rdpver != 3)
150 {
151 /* rdp5_process should move g_next_packet ok */
152 rdp5_process(rdp_s);
153 *type = 0;
154 return rdp_s;
155 }
156
157 g_next_packet = rdp_s->p;
158 }
159 else
160 {
161 rdp_s->p = g_next_packet;
162 }
163
164 in_uint16_le(rdp_s, length);
165 /* 32k packets are really 8, keepalive fix */
166 if (length == 0x8000)
167 {
168 g_next_packet += 8;
169 *type = 0;
170 return rdp_s;
171 }
172 in_uint16_le(rdp_s, pdu_type);
173 in_uint8s(rdp_s, 2); /* userid */
174 *type = pdu_type & 0xf;
175
176 #if WITH_DEBUG
177 DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type));
178 hexdump(g_next_packet, length);
179 #endif /* */
180
181 g_next_packet += length;
182 return rdp_s;
183 }
184
185 /* Initialise an RDP data packet */
186 static STREAM
187 rdp_init_data(int maxlen)
188 {
189 STREAM s;
190
191 s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18);
192 s_push_layer(s, rdp_hdr, 18);
193
194 return s;
195 }
196
197 /* Send an RDP data packet */
198 static void
199 rdp_send_data(STREAM s, uint8 data_pdu_type)
200 {
201 uint16 length;
202
203 s_pop_layer(s, rdp_hdr);
204 length = s->end - s->p;
205
206 out_uint16_le(s, length);
207 out_uint16_le(s, (RDP_PDU_DATA | 0x10));
208 out_uint16_le(s, (g_mcs_userid + 1001));
209
210 out_uint32_le(s, g_rdp_shareid);
211 out_uint8(s, 0); /* pad */
212 out_uint8(s, 1); /* streamid */
213 out_uint16_le(s, (length - 14));
214 out_uint8(s, data_pdu_type);
215 out_uint8(s, 0); /* compress_type */
216 out_uint16(s, 0); /* compress_len */
217
218 sec_send(s, g_encryption ? SEC_ENCRYPT : 0);
219 }
220
221 /* Output a string in Unicode */
222 void
223 rdp_out_unistr(STREAM s, char *string, int len)
224 {
225 #ifdef HAVE_ICONV
226 size_t ibl = strlen(string), obl = len + 2;
227 static iconv_t iconv_h = (iconv_t) - 1;
228 char *pin = string, *pout = (char *) s->p;
229
230 memset(pout, 0, len + 4);
231
232 if (g_iconv_works)
233 {
234 if (iconv_h == (iconv_t) - 1)
235 {
236 size_t i = 1, o = 4;
237 if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1)
238 {
239 warning("rdp_out_unistr: iconv_open[%s -> %s] fail %p\n",
240 g_codepage, WINDOWS_CODEPAGE, iconv_h);
241
242 g_iconv_works = False;
243 rdp_out_unistr(s, string, len);
244 return;
245 }
246 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) ==
247 (size_t) - 1)
248 {
249 iconv_close(iconv_h);
250 iconv_h = (iconv_t) - 1;
251 warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno);
252
253 g_iconv_works = False;
254 rdp_out_unistr(s, string, len);
255 return;
256 }
257 pin = string;
258 pout = (char *) s->p;
259 }
260
261 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
262 {
263 iconv_close(iconv_h);
264 iconv_h = (iconv_t) - 1;
265 warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno);
266
267 g_iconv_works = False;
268 rdp_out_unistr(s, string, len);
269 return;
270 }
271
272 s->p += len + 2;
273
274 }
275 else
276 #endif
277 {
278 int i = 0, j = 0;
279
280 len += 2;
281
282 while (i < len)
283 {
284 s->p[i++] = string[j++];
285 s->p[i++] = 0;
286 }
287
288 s->p += len;
289 }
290 }
291
292 /* Input a string in Unicode
293 *
294 * Returns str_len of string
295 */
296 int
297 rdp_in_unistr(STREAM s, char *string, int str_size, int in_len)
298 {
299 #ifdef HAVE_ICONV
300 size_t ibl = in_len, obl = str_size - 1;
301 char *pin = (char *) s->p, *pout = string;
302 static iconv_t iconv_h = (iconv_t) - 1;
303
304 if (g_iconv_works)
305 {
306 if (iconv_h == (iconv_t) - 1)
307 {
308 if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1)
309 {
310 warning("rdp_in_unistr: iconv_open[%s -> %s] fail %p\n",
311 WINDOWS_CODEPAGE, g_codepage, iconv_h);
312
313 g_iconv_works = False;
314 return rdp_in_unistr(s, string, str_size, in_len);
315 }
316 }
317
318 if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
319 {
320 if (errno == E2BIG)
321 {
322 warning("server sent an unexpectedly long string, truncating\n");
323 }
324 else
325 {
326 iconv_close(iconv_h);
327 iconv_h = (iconv_t) - 1;
328 warning("rdp_in_unistr: iconv fail, errno %d\n", errno);
329
330 g_iconv_works = False;
331 return rdp_in_unistr(s, string, str_size, in_len);
332 }
333 }
334
335 /* we must update the location of the current STREAM for future reads of s->p */
336 s->p += in_len;
337
338 *pout = 0;
339 return pout - string;
340 }
341 else
342 #endif
343 {
344 int i = 0;
345 int len = in_len / 2;
346 int rem = 0;
347
348 if (len > str_size - 1)
349 {
350 warning("server sent an unexpectedly long string, truncating\n");
351 len = str_size - 1;
352 rem = in_len - 2 * len;
353 }
354
355 while (i < len)
356 {
357 in_uint8a(s, &string[i++], 1);
358 in_uint8s(s, 1);
359 }
360
361 in_uint8s(s, rem);
362 string[len] = 0;
363 return len;
364 }
365 }
366
367
368 /* Parse a logon info packet */
369 static void
370 rdp_send_logon_info(uint32 flags, char *domain, char *user,
371 char *password, char *program, char *directory)
372 {
373 char *ipaddr = tcp_get_address();
374 int len_domain = 2 * strlen(domain);
375 int len_user = 2 * strlen(user);
376 int len_password = 2 * strlen(password);
377 int len_program = 2 * strlen(program);
378 int len_directory = 2 * strlen(directory);
379 int len_ip = 2 * strlen(ipaddr);
380 int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll");
381 int packetlen = 0;
382 uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO;
383 STREAM s;
384 time_t t = time(NULL);
385 time_t tzone;
386
387 if (!g_use_rdp5 || 1 == g_server_rdp_version)
388 {
389 DEBUG_RDP5(("Sending RDP4-style Logon packet\n"));
390
391 s = sec_init(sec_flags, 18 + len_domain + len_user + len_password
392 + len_program + len_directory + 10);
393
394 out_uint32(s, 0);
395 out_uint32_le(s, flags);
396 out_uint16_le(s, len_domain);
397 out_uint16_le(s, len_user);
398 out_uint16_le(s, len_password);
399 out_uint16_le(s, len_program);
400 out_uint16_le(s, len_directory);
401 rdp_out_unistr(s, domain, len_domain);
402 rdp_out_unistr(s, user, len_user);
403 rdp_out_unistr(s, password, len_password);
404 rdp_out_unistr(s, program, len_program);
405 rdp_out_unistr(s, directory, len_directory);
406 }
407 else
408 {
409
410 flags |= RDP_LOGON_BLOB;
411 DEBUG_RDP5(("Sending RDP5-style Logon packet\n"));
412 packetlen = 4 + /* Unknown uint32 */
413 4 + /* flags */
414 2 + /* len_domain */
415 2 + /* len_user */
416 (flags & RDP_LOGON_AUTO ? 2 : 0) + /* len_password */
417 (flags & RDP_LOGON_BLOB ? 2 : 0) + /* Length of BLOB */
418 2 + /* len_program */
419 2 + /* len_directory */
420 (0 < len_domain ? len_domain : 2) + /* domain */
421 len_user + (flags & RDP_LOGON_AUTO ? len_password : 0) + 0 + /* We have no 512 byte BLOB. Perhaps we must? */
422 (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO) ? 2 : 0) + /* After the BLOB is a unknown int16. If there is a BLOB, that is. */
423 (0 < len_program ? len_program : 2) + (0 < len_directory ? len_directory : 2) + 2 + /* Unknown (2) */
424 2 + /* Client ip length */
425 len_ip + /* Client ip */
426 2 + /* DLL string length */
427 len_dll + /* DLL string */
428 2 + /* Unknown */
429 2 + /* Unknown */
430 64 + /* Time zone #0 */
431 2 + /* Unknown */
432 64 + /* Time zone #1 */
433 32; /* Unknown */
434
435 s = sec_init(sec_flags, packetlen);
436 DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen));
437
438 out_uint32(s, 0); /* Unknown */
439 out_uint32_le(s, flags);
440 out_uint16_le(s, len_domain);
441 out_uint16_le(s, len_user);
442 if (flags & RDP_LOGON_AUTO)
443 {
444 out_uint16_le(s, len_password);
445
446 }
447 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
448 {
449 out_uint16_le(s, 0);
450 }
451 out_uint16_le(s, len_program);
452 out_uint16_le(s, len_directory);
453 if (0 < len_domain)
454 rdp_out_unistr(s, domain, len_domain);
455 else
456 out_uint16_le(s, 0);
457 rdp_out_unistr(s, user, len_user);
458 if (flags & RDP_LOGON_AUTO)
459 {
460 rdp_out_unistr(s, password, len_password);
461 }
462 if (flags & RDP_LOGON_BLOB && !(flags & RDP_LOGON_AUTO))
463 {
464 out_uint16_le(s, 0);
465 }
466 if (0 < len_program)
467 {
468 rdp_out_unistr(s, program, len_program);
469
470 }
471 else
472 {
473 out_uint16_le(s, 0);
474 }
475 if (0 < len_directory)
476 {
477 rdp_out_unistr(s, directory, len_directory);
478 }
479 else
480 {
481 out_uint16_le(s, 0);
482 }
483 out_uint16_le(s, 2);
484 out_uint16_le(s, len_ip + 2); /* Length of client ip */
485 rdp_out_unistr(s, ipaddr, len_ip);
486 out_uint16_le(s, len_dll + 2);
487 rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll);
488
489 tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60;
490 out_uint32_le(s, tzone);
491
492 rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid"));
493 out_uint8s(s, 62 - 2 * strlen("GTB, normaltid"));
494
495 out_uint32_le(s, 0x0a0000);
496 out_uint32_le(s, 0x050000);
497 out_uint32_le(s, 3);
498 out_uint32_le(s, 0);
499 out_uint32_le(s, 0);
500
501 rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid"));
502 out_uint8s(s, 62 - 2 * strlen("GTB, sommartid"));
503
504 out_uint32_le(s, 0x30000);
505 out_uint32_le(s, 0x050000);
506 out_uint32_le(s, 2);
507 out_uint32(s, 0);
508 out_uint32_le(s, 0xffffffc4);
509 out_uint32_le(s, 0xfffffffe);
510 out_uint32_le(s, g_rdp5_performanceflags);
511 out_uint16(s, 0);
512
513
514 }
515 s_mark_end(s);
516 sec_send(s, sec_flags);
517 }
518
519 /* Send a control PDU */
520 static void
521 rdp_send_control(uint16 action)
522 {
523 STREAM s;
524
525 s = rdp_init_data(8);
526
527 out_uint16_le(s, action);
528 out_uint16(s, 0); /* userid */
529 out_uint32(s, 0); /* control id */
530
531 s_mark_end(s);
532 rdp_send_data(s, RDP_DATA_PDU_CONTROL);
533 }
534
535 /* Send a synchronisation PDU */
536 static void
537 rdp_send_synchronise(void)
538 {
539 STREAM s;
540
541 s = rdp_init_data(4);
542
543 out_uint16_le(s, 1); /* type */
544 out_uint16_le(s, 1002);
545
546 s_mark_end(s);
547 rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE);
548 }
549
550 /* Send a single input event */
551 void
552 rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2)
553 {
554 STREAM s;
555
556 s = rdp_init_data(16);
557
558 out_uint16_le(s, 1); /* number of events */
559 out_uint16(s, 0); /* pad */
560
561 out_uint32_le(s, time);
562 out_uint16_le(s, message_type);
563 out_uint16_le(s, device_flags);
564 out_uint16_le(s, param1);
565 out_uint16_le(s, param2);
566
567 s_mark_end(s);
568 rdp_send_data(s, RDP_DATA_PDU_INPUT);
569 }
570
571 /* Send a client window information PDU */
572 void
573 rdp_send_client_window_status(int status)
574 {
575 STREAM s;
576 static int current_status = 1;
577
578 if (current_status == status)
579 return;
580
581 s = rdp_init_data(12);
582
583 out_uint32_le(s, status);
584
585 switch (status)
586 {
587 case 0: /* shut the server up */
588 break;
589
590 case 1: /* receive data again */
591 out_uint32_le(s, 0); /* unknown */
592 out_uint16_le(s, g_width);
593 out_uint16_le(s, g_height);
594 break;
595 }
596
597 s_mark_end(s);
598 rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS);
599 current_status = status;
600 }
601
602 /* Send persistent bitmap cache enumeration PDU's */
603 static void
604 rdp_enum_bmpcache2(void)
605 {
606 STREAM s;
607 HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS];
608 uint32 num_keys, offset, count, flags;
609
610 offset = 0;
611 num_keys = pstcache_enumerate(2, keylist);
612
613 while (offset < num_keys)
614 {
615 count = MIN(num_keys - offset, 169);
616
617 s = rdp_init_data(24 + count * sizeof(HASH_KEY));
618
619 flags = 0;
620 if (offset == 0)
621 flags |= PDU_FLAG_FIRST;
622 if (num_keys - offset <= 169)
623 flags |= PDU_FLAG_LAST;
624
625 /* header */
626 out_uint32_le(s, 0);
627 out_uint16_le(s, count);
628 out_uint16_le(s, 0);
629 out_uint16_le(s, 0);
630 out_uint16_le(s, 0);
631 out_uint16_le(s, 0);
632 out_uint16_le(s, num_keys);
633 out_uint32_le(s, 0);
634 out_uint32_le(s, flags);
635
636 /* list */
637 out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY));
638
639 s_mark_end(s);
640 rdp_send_data(s, 0x2b);
641
642 offset += 169;
643 }
644 }
645
646 /* Send an (empty) font information PDU */
647 static void
648 rdp_send_fonts(uint16 seq)
649 {
650 STREAM s;
651
652 s = rdp_init_data(8);
653
654 out_uint16(s, 0); /* number of fonts */
655 out_uint16_le(s, 0); /* pad? */
656 out_uint16_le(s, seq); /* unknown */
657 out_uint16_le(s, 0x32); /* entry size */
658
659 s_mark_end(s);
660 rdp_send_data(s, RDP_DATA_PDU_FONT2);
661 }
662
663 /* Output general capability set */
664 static void
665 rdp_out_general_caps(STREAM s)
666 {
667 out_uint16_le(s, RDP_CAPSET_GENERAL);
668 out_uint16_le(s, RDP_CAPLEN_GENERAL);
669
670 out_uint16_le(s, 1); /* OS major type */
671 out_uint16_le(s, 3); /* OS minor type */
672 out_uint16_le(s, 0x200); /* Protocol version */
673 out_uint16(s, 0); /* Pad */
674 out_uint16(s, 0); /* Compression types */
675 out_uint16_le(s, g_use_rdp5 ? 0x40d : 0);
676 /* Pad, according to T.128. 0x40d seems to
677 trigger
678 the server to start sending RDP5 packets.
679 However, the value is 0x1d04 with W2KTSK and
680 NT4MS. Hmm.. Anyway, thankyou, Microsoft,
681 for sending such information in a padding
682 field.. */
683 out_uint16(s, 0); /* Update capability */
684 out_uint16(s, 0); /* Remote unshare capability */
685 out_uint16(s, 0); /* Compression level */
686 out_uint16(s, 0); /* Pad */
687 }
688
689 /* Output bitmap capability set */
690 static void
691 rdp_out_bitmap_caps(STREAM s)
692 {
693 out_uint16_le(s, RDP_CAPSET_BITMAP);
694 out_uint16_le(s, RDP_CAPLEN_BITMAP);
695
696 out_uint16_le(s, g_server_depth); /* Preferred colour depth */
697 out_uint16_le(s, 1); /* Receive 1 BPP */
698 out_uint16_le(s, 1); /* Receive 4 BPP */
699 out_uint16_le(s, 1); /* Receive 8 BPP */
700 out_uint16_le(s, 800); /* Desktop width */
701 out_uint16_le(s, 600); /* Desktop height */
702 out_uint16(s, 0); /* Pad */
703 out_uint16(s, 1); /* Allow resize */
704 out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */
705 out_uint16(s, 0); /* Unknown */
706 out_uint16_le(s, 1); /* Unknown */
707 out_uint16(s, 0); /* Pad */
708 }
709
710 /* Output order capability set */
711 static void
712 rdp_out_order_caps(STREAM s)
713 {
714 uint8 order_caps[32];
715
716 memset(order_caps, 0, 32);
717 order_caps[0] = 1; /* dest blt */
718 order_caps[1] = 1; /* pat blt */
719 order_caps[2] = 1; /* screen blt */
720 order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */
721 order_caps[4] = 0; /* triblt */
722 order_caps[8] = 1; /* line */
723 order_caps[9] = 1; /* line */
724 order_caps[10] = 1; /* rect */
725 order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */
726 order_caps[13] = 1; /* memblt */
727 order_caps[14] = 1; /* triblt */
728 order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */
729 order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */
730 order_caps[22] = 1; /* polyline */
731 order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */
732 order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */
733 order_caps[27] = 1; /* text2 */
734 out_uint16_le(s, RDP_CAPSET_ORDER);
735 out_uint16_le(s, RDP_CAPLEN_ORDER);
736
737 out_uint8s(s, 20); /* Terminal desc, pad */
738 out_uint16_le(s, 1); /* Cache X granularity */
739 out_uint16_le(s, 20); /* Cache Y granularity */
740 out_uint16(s, 0); /* Pad */
741 out_uint16_le(s, 1); /* Max order level */
742 out_uint16_le(s, 0x147); /* Number of fonts */
743 out_uint16_le(s, 0x2a); /* Capability flags */
744 out_uint8p(s, order_caps, 32); /* Orders supported */
745 out_uint16_le(s, 0x6a1); /* Text capability flags */
746 out_uint8s(s, 6); /* Pad */
747 out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */
748 out_uint32(s, 0); /* Unknown */
749 out_uint32_le(s, 0x4e4); /* Unknown */
750 }
751
752 /* Output bitmap cache capability set */
753 static void
754 rdp_out_bmpcache_caps(STREAM s)
755 {
756 int Bpp;
757 out_uint16_le(s, RDP_CAPSET_BMPCACHE);
758 out_uint16_le(s, RDP_CAPLEN_BMPCACHE);
759
760 Bpp = (g_server_depth + 7) / 8; /* bytes per pixel */
761 out_uint8s(s, 24); /* unused */
762 out_uint16_le(s, 0x258); /* entries */
763 out_uint16_le(s, 0x100 * Bpp); /* max cell size */
764 out_uint16_le(s, 0x12c); /* entries */
765 out_uint16_le(s, 0x400 * Bpp); /* max cell size */
766 out_uint16_le(s, 0x106); /* entries */
767 out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
768 }
769
770 /* Output bitmap cache v2 capability set */
771 static void
772 rdp_out_bmpcache2_caps(STREAM s)
773 {
774 out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
775 out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
776
777 out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */
778
779 out_uint16_be(s, 3); /* number of caches in this set */
780
781 /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */
782 out_uint32_le(s, BMPCACHE2_C0_CELLS);
783 out_uint32_le(s, BMPCACHE2_C1_CELLS);
784 if (pstcache_init(2))
785 {
786 out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
787 }
788 else
789 {
790 out_uint32_le(s, BMPCACHE2_C2_CELLS);
791 }
792 out_uint8s(s, 20); /* other bitmap caches not used */
793 }
794
795 /* Output control capability set */
796 static void
797 rdp_out_control_caps(STREAM s)
798 {
799 out_uint16_le(s, RDP_CAPSET_CONTROL);
800 out_uint16_le(s, RDP_CAPLEN_CONTROL);
801
802 out_uint16(s, 0); /* Control capabilities */
803 out_uint16(s, 0); /* Remote detach */
804 out_uint16_le(s, 2); /* Control interest */
805 out_uint16_le(s, 2); /* Detach interest */
806 }
807
808 /* Output activation capability set */
809 static void
810 rdp_out_activate_caps(STREAM s)
811 {
812 out_uint16_le(s, RDP_CAPSET_ACTIVATE);
813 out_uint16_le(s, RDP_CAPLEN_ACTIVATE);
814
815 out_uint16(s, 0); /* Help key */
816 out_uint16(s, 0); /* Help index key */
817 out_uint16(s, 0); /* Extended help key */
818 out_uint16(s, 0); /* Window activate */
819 }
820
821 /* Output pointer capability set */
822 static void
823 rdp_out_pointer_caps(STREAM s)
824 {
825 out_uint16_le(s, RDP_CAPSET_POINTER);
826 out_uint16_le(s, RDP_CAPLEN_POINTER);
827
828 out_uint16(s, 0); /* Colour pointer */
829 out_uint16_le(s, 20); /* Cache size */
830 }
831
832 /* Output share capability set */
833 static void
834 rdp_out_share_caps(STREAM s)
835 {
836 out_uint16_le(s, RDP_CAPSET_SHARE);
837 out_uint16_le(s, RDP_CAPLEN_SHARE);
838
839 out_uint16(s, 0); /* userid */
840 out_uint16(s, 0); /* pad */
841 }
842
843 /* Output colour cache capability set */
844 static void
845 rdp_out_colcache_caps(STREAM s)
846 {
847 out_uint16_le(s, RDP_CAPSET_COLCACHE);
848 out_uint16_le(s, RDP_CAPLEN_COLCACHE);
849
850 out_uint16_le(s, 6); /* cache size */
851 out_uint16(s, 0); /* pad */
852 }
853
854 /* Output brush cache capability set */
855 static void
856 rdp_out_brushcache_caps(STREAM s)
857 {
858 out_uint16_le(s, RDP_CAPSET_BRUSHCACHE);
859 out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE);
860 out_uint32_le(s, 1); /* cache type */
861 }
862
863 static uint8 caps_0x0d[] = {
864 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
865 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
874 0x00, 0x00, 0x00, 0x00
875 };
876
877 static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
878
879 static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
880
881 static uint8 caps_0x10[] = {
882 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
883 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
884 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
885 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
886 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
887 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
888 };
889
890 /* Output unknown capability sets */
891 static void
892 rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps)
893 {
894 out_uint16_le(s, id);
895 out_uint16_le(s, length);
896
897 out_uint8p(s, caps, length - 4);
898 }
899
900 #define RDP5_FLAG 0x0030
901 /* Send a confirm active PDU */
902 static void
903 rdp_send_confirm_active(void)
904 {
905 STREAM s;
906 uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG;
907 uint16 caplen =
908 RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
909 RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
910 RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
911 RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
912 RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
913 4 /* w2k fix, why? */ ;
914
915 s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
916
917 out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE));
918 out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */
919 out_uint16_le(s, (g_mcs_userid + 1001));
920
921 out_uint32_le(s, g_rdp_shareid);
922 out_uint16_le(s, 0x3ea); /* userid */
923 out_uint16_le(s, sizeof(RDP_SOURCE));
924 out_uint16_le(s, caplen);
925
926 out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE));
927 out_uint16_le(s, 0xd); /* num_caps */
928 out_uint8s(s, 2); /* pad */
929
930 rdp_out_general_caps(s);
931 rdp_out_bitmap_caps(s);
932 rdp_out_order_caps(s);
933 g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s);
934 rdp_out_colcache_caps(s);
935 rdp_out_activate_caps(s);
936 rdp_out_control_caps(s);
937 rdp_out_pointer_caps(s);
938 rdp_out_share_caps(s);
939 rdp_out_brushcache_caps(s);
940
941 rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */
942 rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
943 rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
944 rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
945
946 s_mark_end(s);
947 sec_send(s, sec_flags);
948 }
949
950 /* Process a general capability set */
951 static void
952 rdp_process_general_caps(STREAM s)
953 {
954 uint16 pad2octetsB; /* rdp5 flags? */
955
956 in_uint8s(s, 10);
957 in_uint16_le(s, pad2octetsB);
958
959 if (!pad2octetsB)
960 g_use_rdp5 = False;
961 }
962
963
964 void
965 write_file(void)
966 {
967 struct tm time_info;
968 time_t time_seconds;
969 char fname[4096];
970 uint32 divisor = 1000000000;
971 char *c = fname + 25;
972
973 /* as found in libjpeg sample */
974 struct jpeg_compress_struct cinfo;
975 struct jpeg_error_mgr jerr;
976 JSAMPROW row_pointer[1];
977 FILE *outfile;
978
979 if (!g_pixels_changed) /* no change, no write */
980 return;
981
982 time_seconds = (time_t) (g_time_last_change / 1000000);
983 localtime_r(&time_seconds, &time_info);
984 strftime((char *) fname, 4096, "/tmp/%Y-%m-%d %H:%M:%S ", &time_info);
985
986 while (!((g_pixels_changed / divisor) % 10) && (divisor/=10) >1 );
987
988 do
989 {
990 *c++ = '0' + (char) ((g_pixels_changed / divisor) % 10);
991 }
992 while ((divisor/=10) >= 1);
993
994 *c = 0;
995
996 strncat(fname, ".jpg", 4096);
997
998 outfile = fopen(fname, "wb");
999 if (!outfile)
1000 {
1001 error("can\'t open file %s for write\n", fname);
1002 exit(1);
1003 }
1004 cinfo.err = jpeg_std_error(&jerr);
1005 jpeg_create_compress(&cinfo);
1006 jpeg_stdio_dest(&cinfo, outfile);
1007 cinfo.image_width = g_width;
1008 cinfo.image_height = g_height;
1009 cinfo.input_components = 3; /* 3 bytes per pixel, R G B */
1010 cinfo.in_color_space = JCS_RGB;
1011 jpeg_set_defaults(&cinfo);
1012 jpeg_start_compress(&cinfo, TRUE);
1013 while (cinfo.next_scanline < cinfo.image_height)
1014 {
1015 row_pointer[0] = &g_bitmap_data[cinfo.next_scanline * cinfo.image_width * 3];
1016 jpeg_write_scanlines(&cinfo, row_pointer, 1);
1017 }
1018 jpeg_finish_compress(&cinfo);
1019 jpeg_destroy_compress(&cinfo);
1020 fclose(outfile);
1021
1022 g_time_last_write = tod();
1023 printf("%llu (%u) write_file %s\n", g_time_last_write, g_pixels_changed, fname);
1024 memcpy(g_bitmap_data_last_write, g_bitmap_data, g_width * g_height * 3);
1025 g_pixels_changed = 0;
1026 }
1027
1028 /* Process a bitmap capability set */
1029 static void
1030 rdp_process_bitmap_caps(STREAM s)
1031 {
1032 uint16 width, height, depth;
1033
1034 in_uint16_le(s, depth);
1035 in_uint8s(s, 6);
1036
1037 in_uint16_le(s, width);
1038 in_uint16_le(s, height);
1039
1040 DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth));
1041
1042 if (g_bitmap_data)
1043 {
1044 /* resolution change, force write of old screen
1045 g_time_last_change = tod();
1046 write_file();
1047 */
1048 xfree(g_bitmap_data);
1049 xfree(g_bitmap_data_last_write);
1050 }
1051 g_bitmap_data = (uint8 *) xmalloc(width * height * 3);
1052 g_bitmap_data_last_write = (uint8 *) xmalloc(width * height * 3);
1053 bzero(g_bitmap_data, width * height * 3);
1054 bzero(g_bitmap_data_last_write, width * height * 3);
1055 g_pixels_changed = 0;
1056
1057 /*
1058 * The server may limit depth and change the size of the desktop (for
1059 * example when shadowing another session).
1060 */
1061 if (g_server_depth != depth)
1062 {
1063 warning("Remote desktop does not support colour depth %d; falling back to %d\n",
1064 g_server_depth, depth);
1065 g_server_depth = depth;
1066 }
1067 if (g_width != width || g_height != height)
1068 {
1069 warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height,
1070 width, height);
1071 g_width = width;
1072 g_height = height;
1073 ui_resize_window();
1074 }
1075 }
1076
1077 /* Process server capabilities */
1078 static void
1079 rdp_process_server_caps(STREAM s, uint16 length)
1080 {
1081 int n;
1082 uint8 *next, *start;
1083 uint16 ncapsets, capset_type, capset_length;
1084
1085 start = s->p;
1086
1087 in_uint16_le(s, ncapsets);
1088 in_uint8s(s, 2); /* pad */
1089
1090 for (n = 0; n < ncapsets; n++)
1091 {
1092 if (s->p > start + length)
1093 return;
1094
1095 in_uint16_le(s, capset_type);
1096 in_uint16_le(s, capset_length);
1097
1098 next = s->p + capset_length - 4;
1099
1100 switch (capset_type)
1101 {
1102 case RDP_CAPSET_GENERAL:
1103 rdp_process_general_caps(s);
1104 break;
1105
1106 case RDP_CAPSET_BITMAP:
1107 rdp_process_bitmap_caps(s);
1108 break;
1109 }
1110
1111 s->p = next;
1112 }
1113 }
1114
1115 /* Respond to a demand active PDU */
1116 static void
1117 process_demand_active(STREAM s)
1118 {
1119 uint8 type;
1120 uint16 len_src_descriptor, len_combined_caps;
1121
1122 in_uint32_le(s, g_rdp_shareid);
1123 in_uint16_le(s, len_src_descriptor);
1124 in_uint16_le(s, len_combined_caps);
1125 in_uint8s(s, len_src_descriptor);
1126
1127 DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
1128 rdp_process_server_caps(s, len_combined_caps);
1129
1130 rdp_send_confirm_active();
1131 rdp_send_synchronise();
1132 rdp_send_control(RDP_CTL_COOPERATE);
1133 rdp_send_control(RDP_CTL_REQUEST_CONTROL);
1134 rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */
1135 rdp_recv(&type); /* RDP_CTL_COOPERATE */
1136 rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */
1137 rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0,
1138 g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0);
1139
1140 if (g_use_rdp5)
1141 {
1142 rdp_enum_bmpcache2();
1143 rdp_send_fonts(3);
1144 }
1145 else
1146 {
1147 rdp_send_fonts(1);
1148 rdp_send_fonts(2);
1149 }
1150
1151 rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */
1152 reset_order_state();
1153 }
1154
1155 /* Process a colour pointer PDU */
1156 void
1157 process_colour_pointer_pdu(STREAM s)
1158 {
1159 uint16 x, y, width, height, cache_idx, masklen, datalen;
1160 uint8 *mask, *data;
1161 RD_HCURSOR cursor;
1162
1163 in_uint16_le(s, cache_idx);
1164 in_uint16_le(s, x);
1165 in_uint16_le(s, y);
1166 in_uint16_le(s, width);
1167 in_uint16_le(s, height);
1168 in_uint16_le(s, masklen);
1169 in_uint16_le(s, datalen);
1170 in_uint8p(s, data, datalen);
1171 in_uint8p(s, mask, masklen);
1172 cursor = ui_create_cursor(x, y, width, height, mask, data);
1173 ui_set_cursor(cursor);
1174 cache_put_cursor(cache_idx, cursor);
1175 }
1176
1177 /* Process a cached pointer PDU */
1178 void
1179 process_cached_pointer_pdu(STREAM s)
1180 {
1181 uint16 cache_idx;
1182
1183 in_uint16_le(s, cache_idx);
1184 ui_set_cursor(cache_get_cursor(cache_idx));
1185 }
1186
1187 /* Process a system pointer PDU */
1188 void
1189 process_system_pointer_pdu(STREAM s)
1190 {
1191 uint16 system_pointer_type;
1192
1193 in_uint16_le(s, system_pointer_type);
1194 switch (system_pointer_type)
1195 {
1196 case RDP_NULL_POINTER:
1197 ui_set_null_cursor();
1198 break;
1199
1200 default:
1201 unimpl("System pointer message 0x%x\n", system_pointer_type);
1202 }
1203 }
1204
1205 /* Process a pointer PDU */
1206 static void
1207 process_pointer_pdu(STREAM s)
1208 {
1209 uint16 message_type;
1210 uint16 x, y;
1211
1212 in_uint16_le(s, message_type);
1213 in_uint8s(s, 2); /* pad */
1214
1215 switch (message_type)
1216 {
1217 case RDP_POINTER_MOVE:
1218 in_uint16_le(s, x);
1219 in_uint16_le(s, y);
1220 if (s_check(s))
1221 ui_move_pointer(x, y);
1222 break;
1223
1224 case RDP_POINTER_COLOR:
1225 process_colour_pointer_pdu(s);
1226 break;
1227
1228 case RDP_POINTER_CACHED:
1229 process_cached_pointer_pdu(s);
1230 break;
1231
1232 case RDP_POINTER_SYSTEM:
1233 process_system_pointer_pdu(s);
1234 break;
1235
1236 default:
1237 unimpl("Pointer message 0x%x\n", message_type);
1238 }
1239 }
1240
1241 /* Process bitmap updates */
1242 void
1243 process_bitmap_updates(STREAM s)
1244 {
1245 uint16 num_updates;
1246 uint16 left, top, right, bottom, width, height;
1247 uint16 cx, cy, bpp, Bpp, compress, bufsize, size;
1248 uint8 *data, *bmpdata;
1249 int i;
1250
1251 in_uint16_le(s, num_updates);
1252
1253 for (i = 0; i < num_updates; i++)
1254 {
1255 in_uint16_le(s, left);
1256 in_uint16_le(s, top);
1257 in_uint16_le(s, right);
1258 in_uint16_le(s, bottom);
1259 in_uint16_le(s, width);
1260 in_uint16_le(s, height);
1261 in_uint16_le(s, bpp);
1262 Bpp = (bpp + 7) / 8;
1263 in_uint16_le(s, compress);
1264 in_uint16_le(s, bufsize);
1265
1266 cx = right - left + 1;
1267 cy = bottom - top + 1;
1268
1269 DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n",
1270 left, top, right, bottom, width, height, Bpp, compress));
1271
1272 if (!compress)
1273 {
1274 int y;
1275 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1276 for (y = 0; y < height; y++)
1277 {
1278 in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)],
1279 width * Bpp);
1280 }
1281 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1282 xfree(bmpdata);
1283 continue;
1284 }
1285
1286
1287 if (compress & 0x400)
1288 {
1289 size = bufsize;
1290 }
1291 else
1292 {
1293 in_uint8s(s, 2); /* pad */
1294 in_uint16_le(s, size);
1295 in_uint8s(s, 4); /* line_size, final_size */
1296 }
1297 in_uint8p(s, data, size);
1298 bmpdata = (uint8 *) xmalloc(width * height * Bpp);
1299 if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1300 {
1301 ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata);
1302 }
1303 else
1304 {
1305 DEBUG_RDP5(("Failed to decompress data\n"));
1306 }
1307
1308 xfree(bmpdata);
1309 }
1310 }
1311
1312 /* Process a palette update */
1313 void
1314 process_palette(STREAM s)
1315 {
1316 COLOURENTRY *entry;
1317 COLOURMAP map;
1318 RD_HCOLOURMAP hmap;
1319 int i;
1320
1321 in_uint8s(s, 2); /* pad */
1322 in_uint16_le(s, map.ncolours);
1323 in_uint8s(s, 2); /* pad */
1324
1325 map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
1326
1327 DEBUG(("PALETTE(c=%d)\n", map.ncolours));
1328
1329 for (i = 0; i < map.ncolours; i++)
1330 {
1331 entry = &map.colours[i];
1332 in_uint8(s, entry->red);
1333 in_uint8(s, entry->green);
1334 in_uint8(s, entry->blue);
1335 }
1336
1337 hmap = ui_create_colourmap(&map);
1338 ui_set_colourmap(hmap);
1339
1340 xfree(map.colours);
1341 }
1342
1343 /* Process an update PDU */
1344 static void
1345 process_update_pdu(STREAM s)
1346 {
1347 uint16 update_type, count;
1348
1349 in_uint16_le(s, update_type);
1350
1351 ui_begin_update();
1352 switch (update_type)
1353 {
1354 case RDP_UPDATE_ORDERS:
1355 in_uint8s(s, 2); /* pad */
1356 in_uint16_le(s, count);
1357 in_uint8s(s, 2); /* pad */
1358 process_orders(s, count);
1359 break;
1360
1361 case RDP_UPDATE_BITMAP:
1362 process_bitmap_updates(s);
1363 break;
1364
1365 case RDP_UPDATE_PALETTE:
1366 process_palette(s);
1367 break;
1368
1369 case RDP_UPDATE_SYNCHRONIZE:
1370 break;
1371
1372 default:
1373 unimpl("update %d\n", update_type);
1374 }
1375 ui_end_update();
1376 }
1377
1378 /* Process a disconnect PDU */
1379 void
1380 process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason)
1381 {
1382 in_uint32_le(s, *ext_disc_reason);
1383
1384 DEBUG(("Received disconnect PDU\n"));
1385 }
1386
1387 /* Process data PDU */
1388 static RD_BOOL
1389 process_data_pdu(STREAM s, uint32 * ext_disc_reason)
1390 {
1391 uint8 data_pdu_type;
1392 uint8 ctype;
1393 uint16 clen;
1394 uint32 len;
1395
1396 uint32 roff, rlen;
1397
1398 struct stream *ns = &(g_mppc_dict.ns);
1399
1400 in_uint8s(s, 6); /* shareid, pad, streamid */
1401 in_uint16_le(s, len);
1402 in_uint8(s, data_pdu_type);
1403 in_uint8(s, ctype);
1404 in_uint16_le(s, clen);
1405 clen -= 18;
1406
1407 if (ctype & RDP_MPPC_COMPRESSED)
1408 {
1409 if (len > RDP_MPPC_DICT_SIZE)
1410 error("error decompressed packet size exceeds max\n");
1411 if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1)
1412 error("error while decompressing packet\n");
1413
1414 /* len -= 18; */
1415
1416 /* allocate memory and copy the uncompressed data into the temporary stream */
1417 ns->data = (uint8 *) xrealloc(ns->data, rlen);
1418
1419 memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen);
1420
1421 ns->size = rlen;
1422 ns->end = (ns->data + ns->size);
1423 ns->p = ns->data;
1424 ns->rdp_hdr = ns->p;
1425
1426 s = ns;
1427 }
1428
1429 switch (data_pdu_type)
1430 {
1431 case RDP_DATA_PDU_UPDATE:
1432 process_update_pdu(s);
1433 break;
1434
1435 case RDP_DATA_PDU_CONTROL:
1436 DEBUG(("Received Control PDU\n"));
1437 break;
1438
1439 case RDP_DATA_PDU_SYNCHRONISE:
1440 DEBUG(("Received Sync PDU\n"));
1441 break;
1442
1443 case RDP_DATA_PDU_POINTER:
1444 process_pointer_pdu(s);
1445 break;
1446
1447 case RDP_DATA_PDU_BELL:
1448 ui_bell();
1449 break;
1450
1451 case RDP_DATA_PDU_LOGON:
1452 DEBUG(("Received Logon PDU\n"));
1453 /* User logged on */
1454 break;
1455
1456 case RDP_DATA_PDU_DISCONNECT:
1457 process_disconnect_pdu(s, ext_disc_reason);
1458
1459 /* We used to return true and disconnect immediately here, but
1460 * Windows Vista sends a disconnect PDU with reason 0 when
1461 * reconnecting to a disconnected session, and MSTSC doesn't
1462 * drop the connection. I think we should just save the status.
1463 */
1464 break;
1465
1466 default:
1467 unimpl("data PDU %d\n", data_pdu_type);
1468 }
1469 return False;
1470 }
1471
1472 /* Process redirect PDU from Session Directory */
1473 static RD_BOOL
1474 process_redirect_pdu(STREAM s /*, uint32 * ext_disc_reason */ )
1475 {
1476 uint32 len;
1477
1478 /* these 2 bytes are unknown, seem to be zeros */
1479 in_uint8s(s, 2);
1480
1481 /* read connection flags */
1482 in_uint32_le(s, g_redirect_flags);
1483
1484 /* read length of ip string */
1485 in_uint32_le(s, len);
1486
1487 /* read ip string */
1488 rdp_in_unistr(s, g_redirect_server, sizeof(g_redirect_server), len);
1489
1490 /* read length of cookie string */
1491 in_uint32_le(s, len);
1492
1493 /* read cookie string (plain ASCII) */
1494 if (len > sizeof(g_redirect_cookie) - 1)
1495 {
1496 uint32 rem = len - (sizeof(g_redirect_cookie) - 1);
1497 len = sizeof(g_redirect_cookie) - 1;
1498
1499 warning("Unexpectedly large redirection cookie\n");
1500 in_uint8a(s, g_redirect_cookie, len);
1501 in_uint8s(s, rem);
1502 }
1503 else
1504 {
1505 in_uint8a(s, g_redirect_cookie, len);
1506 }
1507 g_redirect_cookie[len] = 0;
1508
1509 /* read length of username string */
1510 in_uint32_le(s, len);
1511
1512 /* read username string */
1513 g_redirect_username = (char *) xmalloc(len + 1);
1514 rdp_in_unistr(s, g_redirect_username, strlen(g_redirect_username), len);
1515
1516 /* read length of domain string */
1517 in_uint32_le(s, len);
1518
1519 /* read domain string */
1520 rdp_in_unistr(s, g_redirect_domain, sizeof(g_redirect_domain), len);
1521
1522 /* read length of password string */
1523 in_uint32_le(s, len);
1524
1525 /* read password string */
1526 rdp_in_unistr(s, g_redirect_password, sizeof(g_redirect_password), len);
1527
1528 g_redirect = True;
1529
1530 return True;
1531 }
1532
1533 /* Process incoming packets */
1534 /* nevers gets out of here till app is done */
1535 void
1536 rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1537 {
1538 while (rdp_loop(deactivated, ext_disc_reason))
1539 ;
1540 }
1541
1542 /* used in uiports and rdp_main_loop, processes the rdp packets waiting */
1543 RD_BOOL
1544 rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason)
1545 {
1546 uint8 type;
1547 RD_BOOL disc = False; /* True when a disconnect PDU was received */
1548 RD_BOOL cont = True;
1549 STREAM s;
1550
1551 while (cont)
1552 {
1553 s = rdp_recv(&type);
1554 if (s == NULL)
1555 return False;
1556 switch (type)
1557 {
1558 case RDP_PDU_DEMAND_ACTIVE:
1559 process_demand_active(s);
1560 *deactivated = False;
1561 break;
1562 case RDP_PDU_DEACTIVATE:
1563 DEBUG(("RDP_PDU_DEACTIVATE\n"));
1564 *deactivated = True;
1565 break;
1566 case RDP_PDU_REDIRECT:
1567 return process_redirect_pdu(s);
1568 break;
1569 case RDP_PDU_DATA:
1570 disc = process_data_pdu(s, ext_disc_reason);
1571 break;
1572 case 0:
1573 break;
1574 default:
1575 unimpl("PDU %d\n", type);
1576 }
1577 if (disc)
1578 return False;
1579 cont = g_next_packet < s->end;
1580 }
1581 return True;
1582 }
1583
1584 /* Establish a connection up to the RDP layer */
1585 RD_BOOL
1586 rdp_connect(char *server, uint32 flags, char *domain, char *password,
1587 char *command, char *directory)
1588 {
1589 if (!sec_connect(server, g_username))
1590 return False;
1591
1592 rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1593 return True;
1594 }
1595
1596 /* Establish a reconnection up to the RDP layer */
1597 RD_BOOL
1598 rdp_reconnect(char *server, uint32 flags, char *domain, char *password,
1599 char *command, char *directory, char *cookie)
1600 {
1601 if (!sec_reconnect(server))
1602 return False;
1603
1604 rdp_send_logon_info(flags, domain, g_username, password, command, directory);
1605 return True;
1606 }
1607
1608 /* Called during redirection to reset the state to support redirection */
1609 void
1610 rdp_reset_state(void)
1611 {
1612 g_next_packet = NULL; /* reset the packet information */
1613 g_rdp_shareid = 0;
1614 sec_reset_state();
1615 }
1616
1617 /* Disconnect from the RDP layer */
1618 void
1619 rdp_disconnect(void)
1620 {
1621 sec_disconnect();
1622 }

  ViewVC Help
Powered by ViewVC 1.1.26