/[rdesktop]/sourceforge.net/trunk/rdesktop/cliprdr.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 /sourceforge.net/trunk/rdesktop/cliprdr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 422 - (show annotations)
Mon Jun 16 09:03:55 2003 UTC (20 years, 11 months ago) by forsberg
File MIME type: text/plain
File size: 21031 byte(s)
Try using STRING instead of TEXT if TEXT doesn't exist in the targets list.

This might solve trouble cutting in X, pasting to Windows when source OS is
(FJK-)IRIX.

There is still a need for better code when selecting format. This is a quick
hack.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - Clipboard functions
4 Copyright (C) Erik Forsberg <forsberg@cendio.se> 2003
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 <X11/Xlib.h>
22 #include <X11/Xatom.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include "rdesktop.h"
27
28 extern BOOL encryption;
29 extern Display *display;
30 extern Window wnd;
31 extern Time last_gesturetime;
32 extern Atom ipc_atom;
33
34 // static Time selection_timestamp;
35 static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;
36 static Atom rdesktop_clipboard_target_atom, incr_atom;
37 static cliprdr_dataformat *server_formats = NULL;
38 static uint16 num_server_formats = 0;
39 static XSelectionEvent selection_event;
40 static uint16 clipboard_channelno;
41 static Atom targets[NUM_TARGETS];
42 static int have_primary = 0;
43 static int rdesktop_is_selection_owner = 0;
44
45 static void
46 cliprdr_print_server_formats(void)
47 {
48 #ifdef WITH_DEBUG_CLIPBOARD
49 cliprdr_dataformat *this;
50 uint16 i = 0;
51 this = server_formats;
52 DEBUG_CLIPBOARD(("There should be %d server formats.\n", num_server_formats));
53 while (NULL != this)
54 {
55 DEBUG_CLIPBOARD(("Format code %d\n", this->identifier));
56 i++;
57 this = this->next;
58 }
59 DEBUG_CLIPBOARD(("There were %d server formats.\n", i));
60 #endif
61 }
62
63 /*
64 static void
65 cliprdr_set_selection_timestamp(void)
66 {
67 XEvent xev;
68 DEBUG_CLIPBOARD(("Changing a property in order to get a timestamp\n"));
69 fflush(stdout);
70 XChangeProperty(display, wnd, rdesktop_clipboard_target_atom,
71 XA_ATOM, 32, PropModeAppend, 0, 0);
72 DEBUG_CLIPBOARD(("Waiting for PropertyChange on wnd\n"));
73 fflush(stdout);
74 XWindowEvent(display, wnd,
75 PropertyChangeMask, &xev);
76 DEBUG_CLIPBOARD(("Setting selection_timestamp\n"));
77 fflush(stdout);
78 selection_timestamp = xev.xproperty.time;
79 }
80 */
81
82 static void
83 cliprdr_send_format_announce(void)
84 {
85 STREAM s;
86 int number_of_formats = 1;
87 DEBUG_CLIPBOARD(("Sending (empty) format announce\n"));
88 s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats * 36 + 12 + 4 + 4);
89 out_uint32_le(s, number_of_formats * 36 + 12);
90 out_uint32_le(s, 0x13);
91 out_uint16_le(s, 2);
92 out_uint16_le(s, 0);
93 out_uint32_le(s, number_of_formats * 36);
94
95 // out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description..
96 // rdp_out_unistr(s, "", 16);
97 // out_uint8s(s, 32);
98
99
100 out_uint32_le(s, 1); // FIXME: This is a rather bogus text description..
101 out_uint8s(s, 32);
102
103 out_uint32_le(s, 0);
104
105 s_mark_end(s);
106 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
107 }
108
109 void
110 cliprdr_ipc_format_announce(unsigned char *data, uint16 length)
111 {
112 STREAM s;
113 rdesktop_is_selection_owner = 1;
114 DEBUG_CLIPBOARD(("cliprdr_ipc_format_announce called, length is %d, data is %s, sending native format announce\n", length, data));
115
116 s = sec_init(encryption ? SEC_ENCRYPT : 0, length + 12 + 4 + 4);
117 out_uint32_le(s, length + 12);
118 out_uint32_le(s, 0x13);
119 out_uint16_le(s, 2);
120 out_uint16_le(s, 0);
121 out_uint32_le(s, length);
122 out_uint8p(s, data, length);
123 out_uint32_le(s, 0); // Pad
124 s_mark_end(s);
125
126 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
127 }
128
129
130
131
132 static void
133 cliprdr_send_empty_datapacket(void)
134 {
135 STREAM out;
136 out = sec_init(encryption ? SEC_ENCRYPT : 0, 20);
137 out_uint32_le(out, 12);
138 out_uint32_le(out, 0x13);
139 out_uint16_le(out, 5);
140 out_uint16_le(out, 1);
141 out_uint32_le(out, 0);
142 /* Insert null string here? */
143 out_uint32_le(out, 0);
144 s_mark_end(out);
145
146 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
147 }
148
149
150 void
151 cliprdr_handle_SelectionNotify(XSelectionEvent * event)
152 {
153
154 unsigned char *data, *datap;
155 unsigned long nitems, bytes_left;
156
157 unsigned long bytes_left_to_transfer;
158 int res, i;
159
160 int format;
161 Atom type_return;
162 Atom best_target, text_target;
163 Atom *supported_targets;
164
165 STREAM out;
166
167 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));
168
169 if (None == event->property)
170 {
171 cliprdr_send_empty_datapacket();
172 return; /* Selection failed */
173 }
174
175 DEBUG_CLIPBOARD(("selection: %s, target: %s, property: %s\n",
176 XGetAtomName(display, event->selection),
177 XGetAtomName(display, event->target),
178 XGetAtomName(display, event->property)));
179
180 if (targets_atom == event->target)
181 {
182 /* Response to TARGETS request. Let's find the target
183 we want and request that */
184 res = XGetWindowProperty(display, wnd,
185 rdesktop_clipboard_target_atom,
186 0L, 4096L, False, AnyPropertyType,
187 &type_return, &format, &nitems, &bytes_left, &data);
188
189 if (Success != res)
190 {
191 DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
192 cliprdr_send_empty_datapacket();
193 return;
194 }
195
196 if (None == type_return)
197 /* The owner might no support TARGETS. Just try
198 STRING */
199 best_target = XA_STRING;
200 else
201 {
202 /* FIXME: We should choose format here based
203 on what the server wanted */
204 supported_targets = (Atom *) data;
205 best_target = XInternAtom(display, "STRING", False);
206 text_target = XInternAtom(display, "TEXT", False);
207 for (i = 0; i < nitems; i++)
208 {
209 DEBUG_CLIPBOARD(("Target %d: %s\n",
210 i, XGetAtomName(display, supported_targets[i])));
211 if (text_target == supported_targets[i])
212 {
213 DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n"));
214 best_target = supported_targets[i];
215 }
216 }
217
218
219
220 }
221
222 XConvertSelection(display, primary_atom,
223 best_target, rdesktop_clipboard_target_atom, wnd, event->time);
224
225 }
226
227 else /* Other clipboard data */
228 {
229
230 res = XGetWindowProperty(display, wnd,
231 rdesktop_clipboard_target_atom,
232 0L, 0x1FFFFFF,
233 True, AnyPropertyType,
234 &type_return, &format, &nitems, &bytes_left, &data);
235
236
237 /* FIXME: We need to handle INCR as well,
238 this is a temporary solution. */
239
240 if (incr_atom == type_return)
241 {
242 warning("We don't support INCR transfers at this time. Try cutting less data\n");
243 cliprdr_send_empty_datapacket();
244 }
245
246
247 if (Success != res)
248 {
249 DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
250 cliprdr_send_empty_datapacket();
251 return;
252 }
253
254 datap = data;
255
256 if (nitems + 1 <= MAX_CLIPRDR_STANDALONE_DATASIZE)
257 {
258 out = sec_init(encryption ? SEC_ENCRYPT : 0, 20 + nitems + 1);
259 out_uint32_le(out, 12 + nitems + 1);
260 out_uint32_le(out, 0x13);
261 out_uint16_le(out, 5);
262 out_uint16_le(out, 1);
263 out_uint32_le(out, nitems + 1);
264 out_uint8p(out, datap, nitems + 1);
265 out_uint32_le(out, 0);
266 s_mark_end(out);
267
268 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
269
270 }
271 else
272 {
273 DEBUG_CLIPBOARD(("Sending %d bytes of data\n",
274 16 + MAX_CLIPRDR_STANDALONE_DATASIZE));
275 out = sec_init(encryption ? SEC_ENCRYPT : 0,
276 16 + MAX_CLIPRDR_STANDALONE_DATASIZE);
277 out_uint32_le(out, nitems + 12);
278 out_uint32_le(out, 0x11);
279 out_uint16_le(out, 5);
280 out_uint16_le(out, 1);
281 out_uint32_le(out, nitems);
282 out_uint8p(out, datap, MAX_CLIPRDR_STANDALONE_DATASIZE);
283 s_mark_end(out);
284
285 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
286
287 bytes_left_to_transfer = nitems - MAX_CLIPRDR_STANDALONE_DATASIZE;
288 datap += MAX_CLIPRDR_STANDALONE_DATASIZE;
289
290 while (bytes_left_to_transfer > MAX_CLIPRDR_STANDALONE_DATASIZE)
291 {
292 DEBUG_CLIPBOARD(("Sending %d bytes of data\n",
293 16 + MAX_CLIPRDR_CONTINUATION_DATASIZE));
294 out = sec_init(encryption ? SEC_ENCRYPT : 0,
295 8 + MAX_CLIPRDR_CONTINUATION_DATASIZE);
296 out_uint32_le(out, nitems);
297 out_uint32_le(out, 0x10);
298 out_uint8p(out, datap, MAX_CLIPRDR_CONTINUATION_DATASIZE);
299 s_mark_end(out);
300
301 sec_send_to_channel(out,
302 encryption ? SEC_ENCRYPT : 0,
303 clipboard_channelno);
304 bytes_left_to_transfer -= MAX_CLIPRDR_CONTINUATION_DATASIZE;
305 datap += MAX_CLIPRDR_CONTINUATION_DATASIZE;
306
307 }
308 DEBUG_CLIPBOARD(("Sending %u bytes of data\n",
309 12 + bytes_left_to_transfer));
310 out = sec_init(encryption ? SEC_ENCRYPT : 0, 12 + bytes_left_to_transfer);
311 out_uint32_le(out, nitems);
312 out_uint32_le(out, 0x12);
313 out_uint8p(out, datap, bytes_left_to_transfer);
314 out_uint32_le(out, 0x0);
315 s_mark_end(out);
316
317 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
318
319 }
320
321
322 XFree(data);
323 if (!rdesktop_is_selection_owner)
324 cliprdr_send_format_announce();
325
326 }
327
328
329 }
330
331 void
332 cliprdr_handle_SelectionClear(void)
333 {
334 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));
335 have_primary = 0;
336 ipc_send_message(RDESKTOP_IPC_CLIPRDR_PRIMARY_LOST, "", 0);
337 cliprdr_send_format_announce();
338 }
339
340
341 static void
342 cliprdr_request_clipboard_data(uint32 formatcode)
343 {
344 STREAM s;
345 s = sec_init(encryption ? SEC_ENCRYPT : 0, 24);
346 out_uint32_le(s, 16);
347 out_uint32_le(s, 0x13);
348 out_uint16_le(s, 4);
349 out_uint16_le(s, 0);
350 out_uint32_le(s, 4); // Remaining length
351 out_uint32_le(s, formatcode);
352 out_uint32_le(s, 0); // Unknown. Garbage pad?
353
354 s_mark_end(s);
355
356 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
357 }
358
359
360 void
361 cliprdr_handle_SelectionRequest(XSelectionRequestEvent * xevent)
362 {
363
364 XSelectionEvent xev;
365 unsigned long nitems, bytes_left;
366 Atom type_return;
367 uint32 *wanted_formatcode;
368 int format;
369
370 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n"));
371 DEBUG_CLIPBOARD(("Requestor window id 0x%x ", (unsigned) xevent->requestor));
372 if (clipboard_atom == xevent->selection)
373 {
374 DEBUG_CLIPBOARD(("wants CLIPBOARD\n"));
375 }
376 if (primary_atom == xevent->selection)
377 {
378 DEBUG_CLIPBOARD(("wants PRIMARY\n"));
379 }
380 DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n",
381 XGetAtomName(display, xevent->target),
382 (unsigned) xevent->target,
383 XGetAtomName(display, xevent->property), (unsigned) xevent->property));
384
385 xev.type = SelectionNotify;
386 xev.serial = 0;
387 xev.send_event = True;
388 xev.requestor = xevent->requestor;
389 xev.selection = xevent->selection;
390 xev.target = xevent->target;
391 xev.property = xevent->property;
392 xev.time = xevent->time;
393
394 memcpy(&selection_event, &xev, sizeof(xev));
395
396 if (ipc_atom == xevent->target)
397 {
398 DEBUG_CLIPBOARD(("Target atom is ipc_atom, getting INTEGER from requestor\n"));
399 XGetWindowProperty(display, xevent->requestor,
400 rdesktop_clipboard_target_atom,
401 0,
402 1,
403 True, XA_INTEGER,
404 &type_return,
405 &format,
406 &nitems, &bytes_left, (unsigned char **) &wanted_formatcode);
407 DEBUG_CLIPBOARD(("Got wanted formatcode %d, format is %d\n", *wanted_formatcode,
408 format));
409 cliprdr_request_clipboard_data(*wanted_formatcode);
410 }
411
412 else if (targets_atom == xevent->target)
413 {
414 DEBUG_CLIPBOARD(("TARGETS requested, sending list..\n"));
415 XChangeProperty(display,
416 xevent->requestor,
417 xevent->property,
418 XA_ATOM,
419 32, PropModeAppend, (unsigned char *) &targets, NUM_TARGETS);
420
421 XSendEvent(display, xevent->requestor, False, NoEventMask, (XEvent *) & xev);
422 return;
423 }
424 else if (timestamp_atom == xevent->target)
425 {
426 DEBUG_CLIPBOARD(("Sending TIMESTAMP\n"));
427 XChangeProperty(display,
428 xevent->requestor,
429 xevent->property,
430 XA_INTEGER,
431 32, PropModeAppend, (unsigned char *) &last_gesturetime, 1);
432 XSendEvent(display, xevent->requestor, False, NoEventMask, (XEvent *) & xev);
433 }
434 else /* Some other target */
435 {
436 cliprdr_request_clipboard_data(CF_TEXT);
437 /* Return and wait for data, handled by
438 cliprdr_handle_server_data */
439 }
440 }
441
442
443 static void
444 cliprdr_ack_format_list(void)
445 {
446 STREAM s;
447 s = sec_init(encryption ? SEC_ENCRYPT : 0, 20);
448 out_uint32_le(s, 12);
449 out_uint32_le(s, 0x13);
450 out_uint16_le(s, 3);
451 out_uint16_le(s, 1);
452 out_uint32_le(s, 0);
453 out_uint32_le(s, 0x0000c0da);
454
455 s_mark_end(s);
456
457 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, clipboard_channelno);
458 }
459
460
461
462
463
464 static void
465 cliprdr_register_server_formats(STREAM s)
466 {
467 uint32 remaining_length, pad;
468 uint16 num_formats;
469 cliprdr_dataformat *this, *next;
470
471 in_uint32_le(s, remaining_length);
472 DEBUG_CLIPBOARD(("cliprdr_register_server_formats, remaining_length is %d\n",
473 remaining_length));
474
475
476 num_formats = remaining_length / 36;
477
478 ipc_send_message(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, s->p, remaining_length);
479 if (NULL != server_formats)
480 {
481 this = server_formats;
482 next = this->next;
483 while (NULL != next)
484 {
485 xfree(this);
486 this = NULL;
487 this = next;
488 next = this->next;
489 }
490 }
491 this = xmalloc(sizeof(cliprdr_dataformat));
492 this->next = NULL;
493 server_formats = this;
494 num_server_formats = num_formats;
495 while (1 < num_formats)
496 {
497 in_uint32_le(s, this->identifier);
498 in_uint8a(s, this->textual_description, 32);
499 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n",
500 this->identifier));
501 this->next = xmalloc(sizeof(cliprdr_dataformat));
502 this = this->next;
503 num_formats--;
504 }
505 in_uint32_le(s, this->identifier);
506 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", this->identifier));
507 in_uint8a(s, this->textual_description, 32);
508 this->next = NULL;
509 in_uint32_le(s, pad);
510 cliprdr_print_server_formats();
511 }
512
513 static void
514 cliprdr_select_X_clipboards(void)
515 {
516 XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime);
517 if (wnd != XGetSelectionOwner(display, primary_atom))
518 {
519 warning("Failed to aquire ownership of PRIMARY clipboard\n");
520 }
521 else
522 {
523 have_primary = 1;
524 }
525 XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime);
526 if (wnd != XGetSelectionOwner(display, clipboard_atom))
527 {
528 warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
529 }
530
531 }
532
533
534
535 static void
536 cliprdr_handle_first_handshake(STREAM s)
537 {
538 uint32 remaining_length, pad;
539 in_uint32_le(s, remaining_length);
540 in_uint32_le(s, pad);
541 DEBUG_CLIPBOARD(("Remaining length in first handshake frm server is %d, pad is %d\n",
542 remaining_length, pad));
543 cliprdr_send_format_announce();
544 }
545
546 void
547 cliprdr_handle_server_data(uint32 length, uint32 flags, STREAM s)
548 {
549 static uint32 remaining_length;
550 static char *data, *datap;
551 static uint32 bytes_left_to_read;
552 DEBUG_CLIPBOARD(("In cliprdr_handle_server_data, flags is %d\n", flags));
553 if (3 == flags) /* One-op write, no packets follows */
554 {
555 in_uint32_le(s, remaining_length);
556 data = s->p;
557 }
558 else if (1 == flags) /* First of several packets */
559 {
560 in_uint32_le(s, remaining_length);
561 DEBUG_CLIPBOARD(("Remaining length is %d\n", remaining_length));
562 data = xmalloc(remaining_length);
563 datap = data;
564 DEBUG_CLIPBOARD(("Copying first %d bytes\n", MAX_CLIPRDR_STANDALONE_DATASIZE));
565 memcpy(datap, s->p, MAX_CLIPRDR_STANDALONE_DATASIZE);
566
567 datap += MAX_CLIPRDR_STANDALONE_DATASIZE;
568 bytes_left_to_read = remaining_length - MAX_CLIPRDR_STANDALONE_DATASIZE;
569 return;
570 }
571 else if (0 == flags)
572 {
573 DEBUG_CLIPBOARD(("Copying %d middle bytes", MAX_CLIPRDR_CONTINUATION_DATASIZE));
574 memcpy(datap, s->p, MAX_CLIPRDR_CONTINUATION_DATASIZE);
575
576 datap += MAX_CLIPRDR_CONTINUATION_DATASIZE;
577 bytes_left_to_read -= MAX_CLIPRDR_CONTINUATION_DATASIZE;
578 return;
579 }
580 else if (2 == flags)
581 {
582 DEBUG_CLIPBOARD(("Copying last %d bytes\n", bytes_left_to_read));
583 memcpy(datap, s->p, bytes_left_to_read);
584 }
585 DEBUG_CLIPBOARD(("Setting target atom (%s) on %d\n",
586 XGetAtomName(display, selection_event.property),
587 selection_event.requestor));
588 XChangeProperty(display,
589 selection_event.requestor,
590 selection_event.property,
591 XInternAtom(display, "STRING", False),
592 8, PropModeAppend, data, remaining_length - 1);
593
594 XSendEvent(display,
595 selection_event.requestor, False, NoEventMask, (XEvent *) & selection_event);
596
597 if (2 == flags)
598 xfree(data);
599
600 }
601
602 void
603 cliprdr_handle_server_data_request(STREAM s)
604 {
605 Window selectionowner;
606 uint32 remaining_length;
607 uint32 wanted_formatcode, pad;
608
609 in_uint32_le(s, remaining_length);
610 in_uint32_le(s, wanted_formatcode);
611 in_uint32_le(s, pad);
612
613 /* FIXME: Check that we support this formatcode */
614
615 DEBUG_CLIPBOARD(("Request from server for format %d\n", wanted_formatcode));
616
617 selectionowner = XGetSelectionOwner(display, primary_atom);
618
619 if (rdesktop_is_selection_owner)
620 {
621 DEBUG_CLIPBOARD(("XChangeProperty, rdesktop_is_selection_owner\n"));
622 XChangeProperty(display, wnd, rdesktop_clipboard_target_atom,
623 XA_INTEGER, 32, PropModeReplace,
624 (unsigned char *) &wanted_formatcode, 1);
625
626 XConvertSelection(display, primary_atom,
627 ipc_atom, rdesktop_clipboard_target_atom, wnd, CurrentTime);
628 return;
629 }
630
631
632 if (None != selectionowner)
633 {
634
635 /* FIXME: Perhaps we should check if we are the owner? */
636
637 XConvertSelection(display, primary_atom,
638 targets_atom, rdesktop_clipboard_target_atom, wnd, CurrentTime);
639
640 /* The rest of the transfer is handled in
641 cliprdr_handle_SelectionNotify */
642
643 }
644 else
645 {
646
647 selectionowner = XGetSelectionOwner(display, clipboard_atom);
648 if (None != selectionowner)
649 {
650 XConvertSelection(display, clipboard_atom,
651 targets_atom,
652 rdesktop_clipboard_target_atom, wnd, CurrentTime);
653
654 /* The rest of the transfer is handled in
655 cliprdr_handle_SelectionNotify */
656
657 }
658 else
659 {
660
661 DEBUG_CLIPBOARD(("There were no owner for PRIMARY nor CLIPBOARD, sending empty string\n")); // FIXME: Should we always send an empty string?
662
663 cliprdr_send_empty_datapacket();
664 }
665 }
666
667
668 }
669
670
671 void
672 cliprdr_callback(STREAM s, uint16 channelno)
673 {
674 static int failed_clipboard_acks = 0;
675 struct timeval timeval;
676 uint32 length, flags;
677 uint16 ptype0, ptype1;
678 clipboard_channelno = channelno;
679 DEBUG_CLIPBOARD(("cliprdr_callback called with channelno %d, clipboard data:\n",
680 channelno));
681 #ifdef WITH_DEBUG_CLIPBOARD
682 // hexdump(s->p, s->end - s->p);
683 #endif
684 in_uint32_le(s, length);
685 in_uint32_le(s, flags);
686
687 DEBUG_CLIPBOARD(("length is %d, flags are %d\n", length, flags));
688
689 if (3 == flags || 1 == flags) /* Single-write op or first-packet-of-several op */
690 {
691 in_uint16_le(s, ptype0);
692 in_uint16_le(s, ptype1);
693 DEBUG_CLIPBOARD(("ptype0 is %d, ptype1 is %d\n", ptype0, ptype1));
694 if (1 == ptype0 && 0 == ptype1)
695 {
696 cliprdr_handle_first_handshake(s);
697 return;
698 }
699 else if (3 == ptype0 && 1 == ptype1)
700 {
701 // Acknowledgment on our format announce. Do we care? Not right now.
702 // There is a strange pad in this packet that we might need some time,
703 // but probably not.
704 DEBUG_CLIPBOARD(("Received format announce ACK\n"));
705 failed_clipboard_acks = 0;
706 return;
707
708 }
709 else if (3 == ptype0 && 2 == ptype1)
710 {
711 DEBUG_CLIPBOARD(("Received failed clipboard format announce ACK, retrying\n"));
712
713 /* This is a fairly portable way to sleep 1/10 of
714 a second.. */
715 timeval.tv_sec = 0;
716 timeval.tv_usec = 100;
717 select(0, NULL, NULL, NULL, &timeval);
718 if (failed_clipboard_acks < 3)
719 {
720
721 cliprdr_send_format_announce();
722 /* Make sure we don't get stuck in this loop */
723 failed_clipboard_acks++;
724 }
725 else
726 {
727 warning("Reached maximum number of clipboard format announce attempts. Pasting in Windows probably won't work well now.\n");
728 }
729 }
730 else if (2 == ptype0 && 0 == ptype1)
731 {
732 cliprdr_register_server_formats(s);
733 cliprdr_select_X_clipboards();
734 cliprdr_ack_format_list();
735 return;
736 }
737 else if (5 == ptype0 && 1 == ptype1)
738 {
739 cliprdr_handle_server_data(length, flags, s);
740 }
741 else if (4 == ptype0 && 0 == ptype1)
742 {
743 cliprdr_handle_server_data_request(s);
744 }
745
746
747 }
748 else
749 {
750 DEBUG_CLIPBOARD(("Handling middle or last packet\n"));
751 cliprdr_handle_server_data(length, flags, s);
752 }
753 }
754
755 void
756 cliprdr_ipc_primary_lost(unsigned char *data, uint16 length)
757 {
758 DEBUG_CLIPBOARD(("cliprdr_ipc_primary_lost called\n"));
759 if (!have_primary)
760 cliprdr_send_format_announce();
761 rdesktop_is_selection_owner = 0;
762 }
763
764
765 void
766 cliprdr_init(void)
767 {
768 primary_atom = XInternAtom(display, "PRIMARY", False);
769 clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
770 targets_atom = XInternAtom(display, "TARGETS", False);
771 timestamp_atom = XInternAtom(display, "TIMESTAMP", False);
772 rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False);
773 incr_atom = XInternAtom(display, "INCR", False);
774 targets[0] = targets_atom;
775 targets[1] = XInternAtom(display, "TEXT", False);
776 targets[2] = XInternAtom(display, "UTF8_STRING", False);
777 targets[3] = XInternAtom(display, "text/unicode", False);
778 targets[4] = XInternAtom(display, "TIMESTAMP", False);
779 targets[5] = XInternAtom(display, "STRING", False);
780 ipc_register_ipcnotify(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, cliprdr_ipc_format_announce);
781 ipc_register_ipcnotify(RDESKTOP_IPC_CLIPRDR_FORMAT_ANNOUNCE, cliprdr_ipc_primary_lost);
782
783
784 }

  ViewVC Help
Powered by ViewVC 1.1.26