VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.4/seamless.c@ 95284

Last change on this file since 95284 was 76779, checked in by vboxsync, 6 years ago

RDP: add client-1.8.4.
bugref:9356: Update rdesktop-vrdp to 1.8.4
client-1.8.4 is a Subversion copy of 1.8.3 with the upstream 1.8.3 to 1.8.4
patch applied and a couple of fixes and changes after review, namely:

  • Stopped disabling the new pointer data format for our build, as this is no

longer needed.

  • Adjusted some snprintf buffers to make GCC happy.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Seamless Windows support
4 Copyright 2005-2008 Peter Astrand <[email protected]> for Cendio AB
5 Copyright 2007-2008 Pierre Ossman <[email protected]> for Cendio AB
6 Copyright 2013-2014 Henrik Andersson <[email protected]> for Cendio AB
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22/*
23 * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
24 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
25 * the General Public License version 2 (GPLv2) at this time for any software where
26 * a choice of GPL license versions is made available with the language indicating
27 * that GPLv2 or any later version may be used, or where a choice of which version
28 * of the GPL is applied is otherwise unspecified.
29 */
30
31#include "rdesktop.h"
32#include <stdarg.h>
33#include <assert.h>
34
35#ifdef WITH_DEBUG_SEAMLESS
36#define DEBUG_SEAMLESS(args) printf args;
37#else
38#define DEBUG_SEAMLESS(args)
39#endif
40
41extern RD_BOOL g_seamless_rdp;
42static VCHANNEL *seamless_channel;
43static unsigned int seamless_serial;
44static char *seamless_rest = NULL;
45static char icon_buf[1024];
46
47static char *
48seamless_get_token(char **s)
49{
50 char *comma, *head;
51 head = *s;
52
53 if (!head)
54 return NULL;
55
56 comma = strchr(head, ',');
57 if (comma)
58 {
59 *comma = '\0';
60 *s = comma + 1;
61 }
62 else
63 {
64 *s = NULL;
65 }
66
67 return head;
68}
69
70
71static RD_BOOL
72seamless_process_line(const char *line, void *data)
73{
74 char *p, *l;
75 char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
76 unsigned long id, flags;
77 char *endptr;
78
79 l = xstrdup(line);
80 p = l;
81
82 DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p));
83
84 tok1 = seamless_get_token(&p);
85 tok2 = seamless_get_token(&p);
86 tok3 = seamless_get_token(&p);
87 tok4 = seamless_get_token(&p);
88 tok5 = seamless_get_token(&p);
89 tok6 = seamless_get_token(&p);
90 tok7 = seamless_get_token(&p);
91 tok8 = seamless_get_token(&p);
92
93 if (!strcmp("CREATE", tok1))
94 {
95 unsigned long group, parent;
96 if (!tok6)
97 return False;
98
99 id = strtoul(tok3, &endptr, 0);
100 if (*endptr)
101 return False;
102
103 group = strtoul(tok4, &endptr, 0);
104 if (*endptr)
105 return False;
106
107 parent = strtoul(tok5, &endptr, 0);
108 if (*endptr)
109 return False;
110
111 flags = strtoul(tok6, &endptr, 0);
112 if (*endptr)
113 return False;
114
115 ui_seamless_create_window(id, group, parent, flags);
116 }
117 else if (!strcmp("DESTROY", tok1))
118 {
119 if (!tok4)
120 return False;
121
122 id = strtoul(tok3, &endptr, 0);
123 if (*endptr)
124 return False;
125
126 flags = strtoul(tok4, &endptr, 0);
127 if (*endptr)
128 return False;
129
130 ui_seamless_destroy_window(id, flags);
131
132 }
133 else if (!strcmp("DESTROYGRP", tok1))
134 {
135 if (!tok4)
136 return False;
137
138 id = strtoul(tok3, &endptr, 0);
139 if (*endptr)
140 return False;
141
142 flags = strtoul(tok4, &endptr, 0);
143 if (*endptr)
144 return False;
145
146 ui_seamless_destroy_group(id, flags);
147 }
148 else if (!strcmp("SETICON", tok1))
149 {
150 int chunk, width, height, len;
151 char byte[3];
152
153 if (!tok8)
154 return False;
155
156 id = strtoul(tok3, &endptr, 0);
157 if (*endptr)
158 return False;
159
160 chunk = strtoul(tok4, &endptr, 0);
161 if (*endptr)
162 return False;
163
164 width = strtoul(tok6, &endptr, 0);
165 if (*endptr)
166 return False;
167
168 height = strtoul(tok7, &endptr, 0);
169 if (*endptr)
170 return False;
171
172 byte[2] = '\0';
173 len = 0;
174 while (*tok8 != '\0')
175 {
176 byte[0] = *tok8;
177 tok8++;
178 if (*tok8 == '\0')
179 return False;
180 byte[1] = *tok8;
181 tok8++;
182
183 icon_buf[len] = strtol(byte, NULL, 16);
184 len++;
185
186 if ((size_t)len >= sizeof(icon_buf))
187 {
188 warning("seamless_process_line(), icon data would overrun icon_buf");
189 break;
190 }
191 }
192
193 ui_seamless_seticon(id, tok5, width, height, chunk, icon_buf, len);
194 }
195 else if (!strcmp("DELICON", tok1))
196 {
197 int width, height;
198
199 if (!tok6)
200 return False;
201
202 id = strtoul(tok3, &endptr, 0);
203 if (*endptr)
204 return False;
205
206 width = strtoul(tok5, &endptr, 0);
207 if (*endptr)
208 return False;
209
210 height = strtoul(tok6, &endptr, 0);
211 if (*endptr)
212 return False;
213
214 ui_seamless_delicon(id, tok4, width, height);
215 }
216 else if (!strcmp("POSITION", tok1))
217 {
218 int x, y, width, height;
219
220 if (!tok8)
221 return False;
222
223 id = strtoul(tok3, &endptr, 0);
224 if (*endptr)
225 return False;
226
227 x = strtol(tok4, &endptr, 0);
228 if (*endptr)
229 return False;
230 y = strtol(tok5, &endptr, 0);
231 if (*endptr)
232 return False;
233
234 width = strtol(tok6, &endptr, 0);
235 if (*endptr)
236 return False;
237 height = strtol(tok7, &endptr, 0);
238 if (*endptr)
239 return False;
240
241 flags = strtoul(tok8, &endptr, 0);
242 if (*endptr)
243 return False;
244
245 ui_seamless_move_window(id, x, y, width, height, flags);
246 }
247 else if (!strcmp("ZCHANGE", tok1))
248 {
249 unsigned long behind;
250
251 id = strtoul(tok3, &endptr, 0);
252 if (*endptr)
253 return False;
254
255 behind = strtoul(tok4, &endptr, 0);
256 if (*endptr)
257 return False;
258
259 flags = strtoul(tok5, &endptr, 0);
260 if (*endptr)
261 return False;
262
263 ui_seamless_restack_window(id, behind, flags);
264 }
265 else if (!strcmp("TITLE", tok1))
266 {
267 if (!tok5)
268 return False;
269
270 id = strtoul(tok3, &endptr, 0);
271 if (*endptr)
272 return False;
273
274 flags = strtoul(tok5, &endptr, 0);
275 if (*endptr)
276 return False;
277
278 ui_seamless_settitle(id, tok4, flags);
279 }
280 else if (!strcmp("STATE", tok1))
281 {
282 unsigned int state;
283
284 if (!tok5)
285 return False;
286
287 id = strtoul(tok3, &endptr, 0);
288 if (*endptr)
289 return False;
290
291 state = strtoul(tok4, &endptr, 0);
292 if (*endptr)
293 return False;
294
295 flags = strtoul(tok5, &endptr, 0);
296 if (*endptr)
297 return False;
298
299 ui_seamless_setstate(id, state, flags);
300 }
301 else if (!strcmp("DEBUG", tok1))
302 {
303 DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line));
304 }
305 else if (!strcmp("SYNCBEGIN", tok1))
306 {
307 if (!tok3)
308 return False;
309
310 flags = strtoul(tok3, &endptr, 0);
311 if (*endptr)
312 return False;
313
314 ui_seamless_syncbegin(flags);
315 }
316 else if (!strcmp("SYNCEND", tok1))
317 {
318 if (!tok3)
319 return False;
320
321 flags = strtoul(tok3, &endptr, 0);
322 if (*endptr)
323 return False;
324
325 /* do nothing, currently */
326 }
327 else if (!strcmp("HELLO", tok1))
328 {
329 if (!tok3)
330 return False;
331
332 flags = strtoul(tok3, &endptr, 0);
333 if (*endptr)
334 return False;
335
336 ui_seamless_begin(! !(flags & SEAMLESSRDP_HELLO_HIDDEN));
337 }
338 else if (!strcmp("ACK", tok1))
339 {
340 unsigned int serial;
341
342 serial = strtoul(tok3, &endptr, 0);
343 if (*endptr)
344 return False;
345
346 ui_seamless_ack(serial);
347 }
348 else if (!strcmp("HIDE", tok1))
349 {
350 if (!tok3)
351 return False;
352
353 flags = strtoul(tok3, &endptr, 0);
354 if (*endptr)
355 return False;
356
357 ui_seamless_hide_desktop();
358 }
359 else if (!strcmp("UNHIDE", tok1))
360 {
361 if (!tok3)
362 return False;
363
364 flags = strtoul(tok3, &endptr, 0);
365 if (*endptr)
366 return False;
367
368 ui_seamless_unhide_desktop();
369 }
370
371
372 xfree(l);
373 return True;
374}
375
376
377static RD_BOOL
378seamless_line_handler(const char *line, void *data)
379{
380 if (!seamless_process_line(line, data))
381 {
382 warning("SeamlessRDP: Invalid request:%s\n", line);
383 }
384 return True;
385}
386
387
388static void
389seamless_process(STREAM s)
390{
391 unsigned int pkglen;
392 char *buf;
393 struct stream packet = *s;
394
395 if (!s_check(s))
396 {
397 rdp_protocol_error("seamless_process(), stream is in unstable state", &packet);
398 }
399
400 pkglen = s->end - s->p;
401 /* str_handle_lines requires null terminated strings */
402 buf = xmalloc(pkglen + 1);
403 STRNCPY(buf, (char *) s->p, pkglen + 1);
404#if 0
405 printf("seamless recv:\n");
406 hexdump(s->p, pkglen);
407#endif
408
409 str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL);
410
411 xfree(buf);
412}
413
414
415RD_BOOL
416seamless_init(void)
417{
418 if (!g_seamless_rdp)
419 return False;
420
421 seamless_serial = 0;
422
423 seamless_channel =
424 channel_register("seamrdp", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
425 seamless_process);
426 return (seamless_channel != NULL);
427}
428
429void
430seamless_reset_state(void)
431{
432 if (seamless_rest != NULL)
433 {
434 xfree(seamless_rest);
435 seamless_rest = NULL;
436 }
437}
438
439static unsigned int
440seamless_send(const char *command, const char *format, ...)
441{
442 STREAM s;
443 size_t len;
444 va_list argp;
445 char *escaped, buf[1025];
446
447 len = snprintf(buf, sizeof(buf) - 1, "%s,%u,", command, seamless_serial);
448
449 assert(len < (sizeof(buf) - 1));
450
451 va_start(argp, format);
452 len += vsnprintf(buf + len, sizeof(buf) - len - 1, format, argp);
453 va_end(argp);
454
455 assert(len < (sizeof(buf) - 1));
456
457 escaped = utils_string_escape(buf);
458 len = snprintf(buf, sizeof(buf), "%s", escaped);
459 free(escaped);
460 assert(len < (sizeof(buf) - 1));
461
462 buf[len] = '\n';
463 buf[len + 1] = '\0';
464
465 len++;
466
467 s = channel_init(seamless_channel, len);
468 out_uint8p(s, buf, len) s_mark_end(s);
469
470 DEBUG_SEAMLESS(("seamlessrdp sending:%s", buf));
471
472#if 0
473 printf("seamless send:\n");
474 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
475#endif
476
477 channel_send(s, seamless_channel);
478
479 return seamless_serial++;
480}
481
482
483unsigned int
484seamless_send_sync()
485{
486 if (!g_seamless_rdp)
487 return (unsigned int) -1;
488
489 return seamless_send("SYNC", "");
490}
491
492
493unsigned int
494seamless_send_state(unsigned long id, unsigned int state, unsigned long flags)
495{
496 if (!g_seamless_rdp)
497 return (unsigned int) -1;
498
499 return seamless_send("STATE", "0x%08lx,0x%x,0x%lx", id, state, flags);
500}
501
502
503unsigned int
504seamless_send_position(unsigned long id, int x, int y, int width, int height, unsigned long flags)
505{
506 return seamless_send("POSITION", "0x%08lx,%d,%d,%d,%d,0x%lx", id, x, y, width, height,
507 flags);
508}
509
510
511/* Update select timeout */
512void
513seamless_select_timeout(struct timeval *tv)
514{
515 struct timeval ourtimeout = { 0, SEAMLESSRDP_POSITION_TIMER };
516
517 if (g_seamless_rdp)
518 {
519 if (timercmp(&ourtimeout, tv, <))
520 {
521 tv->tv_sec = ourtimeout.tv_sec;
522 tv->tv_usec = ourtimeout.tv_usec;
523 }
524 }
525}
526
527
528unsigned int
529seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags)
530{
531 if (!g_seamless_rdp)
532 return (unsigned int) -1;
533
534 return seamless_send("ZCHANGE", "0x%08lx,0x%08lx,0x%lx", id, below, flags);
535}
536
537
538
539unsigned int
540seamless_send_focus(unsigned long id, unsigned long flags)
541{
542 if (!g_seamless_rdp)
543 return (unsigned int) -1;
544
545 return seamless_send("FOCUS", "0x%08lx,0x%lx", id, flags);
546}
547
548/* Send client-to-server message to destroy process on the server. */
549unsigned int
550seamless_send_destroy(unsigned long id)
551{
552 return seamless_send("DESTROY", "0x%08lx", id);
553}
554
555unsigned int
556seamless_send_spawn(char *cmdline)
557{
558 unsigned int res;
559 if (!g_seamless_rdp)
560 return (unsigned int) -1;
561
562 res = seamless_send("SPAWN", cmdline);
563
564 return res;
565}
566
567unsigned int
568seamless_send_persistent(RD_BOOL enable)
569{
570 unsigned int res;
571 if (!g_seamless_rdp)
572 return (unsigned int) -1;
573 printf("%s persistent seamless mode.\n", enable?"Enable":"Disable");
574 res = seamless_send("PERSISTENT", "%d", enable);
575
576 return res;
577}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette