/[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

Annotation of /sourceforge.net/trunk/rdesktop/cliprdr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 390 - (hide annotations)
Fri Jun 6 09:28:21 2003 UTC (21 years ago) by forsberg
File MIME type: text/plain
File size: 14559 byte(s)
Don't hardcode clipboard channel.

1 forsberg 383 /* -*- 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 "rdesktop.h"
24    
25     extern BOOL encryption;
26     extern Display *display;
27     extern Window wnd;
28 forsberg 388 extern Time last_gesturetime;
29 forsberg 383
30 forsberg 388 // static Time selection_timestamp;
31 forsberg 383 static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;
32 forsberg 386 static Atom rdesktop_clipboard_target_atom;
33 forsberg 383 static cliprdr_dataformat *server_formats = NULL;
34     static uint16 num_server_formats = 0;
35 forsberg 384 static XSelectionEvent selection_event;
36 forsberg 390 static uint16 clipboard_channelno;
37 forsberg 383
38     static void
39     cliprdr_print_server_formats(void)
40     {
41     #ifdef WITH_DEBUG_CLIPBOARD
42     cliprdr_dataformat *this;
43     uint16 i = 0;
44     this = server_formats;
45     DEBUG_CLIPBOARD(("There should be %d server formats.\n", num_server_formats));
46     while (NULL != this)
47     {
48     DEBUG_CLIPBOARD(("Format code %d\n", this->identifier));
49     i++;
50     this = this->next;
51     }
52 forsberg 384 DEBUG_CLIPBOARD(("There were %d server formats.\n", i));
53 forsberg 383 #endif
54     }
55 forsberg 388 /*
56     static void
57     cliprdr_set_selection_timestamp(void)
58     {
59     XEvent xev;
60     DEBUG_CLIPBOARD(("Changing a property in order to get a timestamp\n"));
61     fflush(stdout);
62     XChangeProperty(display, wnd, rdesktop_clipboard_target_atom,
63     XA_ATOM, 32, PropModeAppend, 0, 0);
64     DEBUG_CLIPBOARD(("Waiting for PropertyChange on wnd\n"));
65     fflush(stdout);
66     XWindowEvent(display, wnd,
67     PropertyChangeMask, &xev);
68     DEBUG_CLIPBOARD(("Setting selection_timestamp\n"));
69     fflush(stdout);
70     selection_timestamp = xev.xproperty.time;
71     }
72     */
73 forsberg 383
74 forsberg 386 static void
75 forsberg 387 cliprdr_send_format_announce(void)
76     {
77 forsberg 388 DEBUG_CLIPBOARD(("Sending format announce\n"));
78    
79 forsberg 387 STREAM s;
80     int number_of_formats = 1;
81     s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4);
82     out_uint32_le(s, number_of_formats*36+12);
83     out_uint32_le(s, 0x13);
84     out_uint16_le(s, 2);
85     out_uint16_le(s, 0);
86     out_uint32_le(s, number_of_formats*36);
87    
88     // out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description..
89     // rdp_out_unistr(s, "", 16);
90     // out_uint8s(s, 32);
91    
92    
93     out_uint32_le(s, 1); // FIXME: This is a rather bogus text description..
94     out_uint8s(s, 32);
95    
96     out_uint32_le(s, 0);
97    
98     s_mark_end(s);
99 forsberg 390 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
100     clipboard_channelno);
101 forsberg 387 }
102    
103    
104     static void
105 forsberg 386 cliprdr_send_empty_datapacket(void)
106     {
107     STREAM out;
108     out = sec_init(encryption ? SEC_ENCRYPT : 0,
109     20);
110     out_uint32_le(out, 12);
111     out_uint32_le(out, 0x13);
112     out_uint16_le(out, 5);
113     out_uint16_le(out, 1);
114     out_uint32_le(out, 0);
115     /* Insert null string here? */
116     out_uint32_le(out, 0);
117     s_mark_end(out);
118    
119 forsberg 390 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0,
120     clipboard_channelno);
121 forsberg 386 }
122    
123    
124 forsberg 383 void
125 forsberg 386 cliprdr_handle_SelectionNotify(XSelectionEvent *event)
126 forsberg 383 {
127 forsberg 386
128     unsigned char *data;
129     unsigned long nitems, bytes_left;
130     int res;
131    
132     int format;
133     Atom type_return;
134     Atom best_target;
135    
136     STREAM out;
137    
138 forsberg 383 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));
139 forsberg 386
140     if (None == event->property) {
141     cliprdr_send_empty_datapacket();
142     return; /* Selection failed */
143     }
144    
145     DEBUG_CLIPBOARD(("selection: %s, target: %s, property: %s\n",
146     XGetAtomName(display, event->selection),
147     XGetAtomName(display, event->target),
148     XGetAtomName(display, event->property)));
149    
150     if (targets_atom == event->target) {
151     /* Response to TARGETS request. Let's find the target
152     we want and request that */
153     res = XGetWindowProperty(display, wnd,
154     rdesktop_clipboard_target_atom,
155     0L, 4096L, False, AnyPropertyType,
156     &type_return,
157     &format, &nitems, &bytes_left, &data);
158    
159     if (Success != res)
160     {
161     DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
162     cliprdr_send_empty_datapacket();
163     return;
164     }
165    
166     if (None == type_return)
167     /* The owner might no support TARGETS. Just try
168     STRING */
169     best_target = XA_STRING;
170     else
171     {
172     /* FIXME: We should choose format here based
173     on what the server wanted */
174     best_target = XInternAtom(display, "TEXT", False);
175    
176    
177     }
178    
179     XConvertSelection(display, primary_atom,
180     best_target,
181     rdesktop_clipboard_target_atom,
182     wnd, event->time);
183    
184     }
185     else /* Other clipboard data */
186     {
187    
188     res = XGetWindowProperty(display, wnd,
189     rdesktop_clipboard_target_atom,
190     0L, 4096L, False, AnyPropertyType,
191     &type_return,
192     &format, &nitems, &bytes_left, &data);
193    
194     if (Success != res)
195     {
196     DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
197     cliprdr_send_empty_datapacket();
198     return;
199     }
200    
201     /* We need to handle INCR as well */
202    
203     out = sec_init(encryption ? SEC_ENCRYPT : 0,
204 forsberg 389 20+nitems+1);
205     out_uint32_le(out, 12+nitems+1);
206 forsberg 386 out_uint32_le(out, 0x13);
207     out_uint16_le(out, 5);
208     out_uint16_le(out, 1);
209 forsberg 389 out_uint32_le(out, nitems+1);
210     out_uint8p(out, data, nitems+1);
211 forsberg 386 /* Insert null string here? */
212     out_uint32_le(out, 0);
213     s_mark_end(out);
214    
215 forsberg 390 sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0,
216     clipboard_channelno);
217 forsberg 388
218     cliprdr_send_format_announce();
219 forsberg 386
220     }
221    
222    
223 forsberg 383 }
224    
225     void
226     cliprdr_handle_SelectionClear(void)
227     {
228     DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));
229 forsberg 387 cliprdr_send_format_announce();
230 forsberg 383 }
231    
232    
233 forsberg 384 static void
234     cliprdr_request_clipboard_data(uint32 formatcode)
235     {
236     STREAM s;
237     s = sec_init(encryption ? SEC_ENCRYPT : 0, 24);
238     out_uint32_le(s, 16);
239     out_uint32_le(s, 0x13);
240     out_uint16_le(s, 4);
241     out_uint16_le(s, 0);
242     out_uint32_le(s, 4); // Remaining length
243     out_uint32_le(s, formatcode);
244     out_uint32_le(s, 0); // Unknown. Garbage pad?
245    
246     s_mark_end(s);
247    
248 forsberg 390 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
249     clipboard_channelno);
250 forsberg 384 }
251    
252    
253 forsberg 383 void
254     cliprdr_handle_SelectionRequest(XSelectionRequestEvent *xevent)
255     {
256    
257     Atom *targets;
258     int res;
259    
260     XSelectionEvent xev;
261     DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n"));
262 forsberg 384 DEBUG_CLIPBOARD(("Requestor window id 0x%x ",
263     (unsigned)xevent->requestor));
264 forsberg 383 if (clipboard_atom == xevent->selection) {
265     DEBUG_CLIPBOARD(("wants CLIPBOARD\n"));
266     }
267     if (primary_atom == xevent->selection) {
268     DEBUG_CLIPBOARD(("wants PRIMARY\n"));
269     }
270     DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n",
271     XGetAtomName(display, xevent->target),
272 forsberg 384 (unsigned)xevent->target,
273 forsberg 383 XGetAtomName(display, xevent->property),
274 forsberg 384 (unsigned)xevent->property));
275 forsberg 383
276     xev.type = SelectionNotify;
277     xev.serial = 0;
278     xev.send_event = True;
279     xev.requestor = xevent->requestor;
280     xev.selection = xevent->selection;
281     xev.target = xevent->target;
282     xev.property = xevent->property;
283     xev.time = xevent->time;
284    
285     if (targets_atom == xevent->target)
286     {
287     DEBUG_CLIPBOARD(("TARGETS requested, sending list..\n"));
288     targets = xmalloc(4*sizeof(Atom));
289     targets[0] = xevent->target;
290     targets[1] = XInternAtom(display, "TEXT", True);
291     targets[2] = XInternAtom(display, "UTF8_STRING", True);
292     targets[3] = XInternAtom(display, "TIMESTAMP", True);
293     res = XChangeProperty(display,
294     xevent->requestor,
295     xevent->property,
296     XA_ATOM,
297     32,
298     PropModeAppend,
299     (unsigned char *)targets,
300     3);
301    
302     res = XSendEvent(display,
303     xevent->requestor,
304     False,
305     NoEventMask,
306     (XEvent *)&xev);
307     return;
308     } else if (timestamp_atom == xevent->target)
309     {
310     DEBUG_CLIPBOARD(("TIMESTAMP requested... sending 0x%x\n",
311 forsberg 388 (unsigned)last_gesturetime));
312 forsberg 383 res = XChangeProperty(display,
313     xevent->requestor,
314     xevent->property,
315     XA_INTEGER,
316     32,
317     PropModeAppend,
318 forsberg 388 (unsigned char *)&last_gesturetime,
319 forsberg 383 1);
320     res = XSendEvent(display,
321     xevent->requestor,
322     False,
323     NoEventMask,
324     (XEvent *)&xev);
325     } else /* Some other target */
326     {
327 forsberg 384 cliprdr_request_clipboard_data(CF_TEXT);
328     memcpy(&selection_event, &xev, sizeof(xev));
329     /* Return and wait for data, handled by
330     cliprdr_handle_server_data */
331     }
332     }
333 forsberg 383
334    
335 forsberg 384 static void
336     cliprdr_ack_format_list(void)
337     {
338     STREAM s;
339     s = sec_init(encryption ? SEC_ENCRYPT : 0, 20);
340     out_uint32_le(s, 12);
341     out_uint32_le(s, 0x13);
342     out_uint16_le(s, 3);
343     out_uint16_le(s, 1);
344     out_uint32_le(s, 0);
345     out_uint32_le(s, 0x0000c0da);
346    
347     s_mark_end(s);
348    
349 forsberg 390 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
350     clipboard_channelno);
351 forsberg 383 }
352    
353 forsberg 384
354 forsberg 383
355 forsberg 384
356    
357 forsberg 383 static void
358     cliprdr_register_server_formats(STREAM s)
359     {
360     uint32 remaining_length, pad;
361     uint16 num_formats;
362     cliprdr_dataformat *this, *next;
363    
364     DEBUG_CLIPBOARD(("cliprdr_register_server_formats\n"));
365     in_uint32_le(s, remaining_length);
366    
367     num_formats = remaining_length / 36;
368     if (NULL != server_formats) {
369     this = server_formats;
370     next = this->next;
371     while (NULL != next) {
372     xfree(this);
373     this = NULL;
374     this = next;
375     next = this->next;
376     }
377     }
378     this = xmalloc(sizeof(cliprdr_dataformat));
379     this->next = NULL;
380     server_formats = this;
381     num_server_formats = num_formats;
382     while (1 < num_formats) {
383     in_uint32_le(s, this->identifier);
384     in_uint8a(s, this->textual_description, 32);
385 forsberg 384 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n",
386     this->identifier));
387 forsberg 383 this-> next = xmalloc(sizeof(cliprdr_dataformat));
388     this = this->next;
389     num_formats--;
390     }
391     in_uint32_le(s, this->identifier);
392     DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", this->identifier));
393     in_uint8a(s, this->textual_description, 32);
394     this -> next = NULL;
395     in_uint32_le(s, pad);
396     cliprdr_print_server_formats();
397     }
398    
399     static void
400     cliprdr_select_X_clipboards(void)
401     {
402 forsberg 388 XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime);
403 forsberg 383 if (wnd != XGetSelectionOwner(display, primary_atom))
404     {
405     warning("Failed to aquire ownership of PRIMARY clipboard\n");
406     }
407 forsberg 388 XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime);
408 forsberg 383 if (wnd != XGetSelectionOwner(display, clipboard_atom))
409     {
410     warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
411     }
412    
413     }
414    
415 forsberg 384
416    
417 forsberg 385
418    
419 forsberg 383 static void
420     cliprdr_handle_first_handshake(STREAM s)
421     {
422     uint32 remaining_length, pad;
423     in_uint32_le(s, remaining_length);
424     in_uint32_le(s, pad);
425     DEBUG_CLIPBOARD(("Remaining length in first handshake frm server is %d, pad is %d\n",
426     remaining_length, pad));
427     cliprdr_send_format_announce();
428     }
429    
430 forsberg 384 void cliprdr_handle_server_data(uint32 length, STREAM s)
431     {
432     uint32 remaining_length;
433     char *data;
434     in_uint32_le(s, remaining_length);
435     data = s->p;
436 forsberg 388 XChangeProperty(display,
437     selection_event.requestor,
438     selection_event.property,
439     XInternAtom(display, "STRING", False),
440     8,
441     PropModeAppend,
442     data,
443     remaining_length);
444 forsberg 384
445 forsberg 388 XSendEvent(display,
446     selection_event.requestor,
447     False,
448     NoEventMask,
449     (XEvent *)&selection_event);
450 forsberg 384
451    
452     }
453    
454 forsberg 385 void cliprdr_handle_server_data_request(STREAM s)
455     {
456 forsberg 386 Window selectionowner;
457 forsberg 385 uint32 remaining_length;
458     uint32 wanted_formatcode, pad;
459    
460     in_uint32_le(s, remaining_length);
461     in_uint32_le(s, wanted_formatcode);
462     in_uint32_le(s, pad);
463    
464     /* FIXME: Check that we support this formatcode */
465    
466     DEBUG_CLIPBOARD(("Request from server for format %d\n",
467     wanted_formatcode));
468    
469 forsberg 386 selectionowner = XGetSelectionOwner(display, primary_atom);
470 forsberg 385
471 forsberg 386 if (None != selectionowner)
472     {
473 forsberg 385
474 forsberg 386 /* FIXME: Perhaps we should check if we are the owner? */
475 forsberg 385
476 forsberg 386 XConvertSelection(display, primary_atom,
477     targets_atom,
478     rdesktop_clipboard_target_atom,
479     wnd, CurrentTime);
480    
481     /* The rest of the transfer is handled in
482     cliprdr_handle_SelectionNotify */
483    
484     } else
485 forsberg 385 {
486 forsberg 386 DEBUG_CLIPBOARD(("There were no owner for PRIMARY, sending empty string\n")); // FIXME: Should we always send an empty string?
487    
488     cliprdr_send_empty_datapacket();
489 forsberg 385 }
490 forsberg 386
491    
492 forsberg 385 }
493    
494    
495 forsberg 390 void cliprdr_callback(STREAM s, uint16 channelno)
496 forsberg 383 {
497 forsberg 389 static int failed_clipboard_acks = 0;
498     struct timeval timeval;
499 forsberg 383 uint32 length, flags;
500     uint16 ptype0, ptype1;
501 forsberg 390 clipboard_channelno = channelno;
502     DEBUG_CLIPBOARD(("cliprdr_callback called with channelno %d, clipboard data:\n", channelno));
503 forsberg 383 #ifdef WITH_DEBUG_CLIPBOARD
504     hexdump(s->p, s->end - s->p);
505     #endif
506     in_uint32_le(s, length);
507     in_uint32_le(s, flags);
508    
509     DEBUG_CLIPBOARD(("length is %d, flags are %d\n", length, flags));
510    
511     if (flags & 0x03 || flags & 0x01) /* Single-write op or first-packet-of-several op */
512     {
513     in_uint16_le(s, ptype0);
514     in_uint16_le(s, ptype1);
515     DEBUG_CLIPBOARD(("ptype0 is %d, ptype1 is %d\n", ptype0, ptype1));
516     if (1 == ptype0 && 0 == ptype1) {
517     cliprdr_handle_first_handshake(s);
518     return;
519     } else if (3 == ptype0 && 1 == ptype1)
520     {
521     // Acknowledgment on our format announce. Do we care? Not right now.
522     // There is a strange pad in this packet that we might need some time,
523     // but probably not.
524     DEBUG_CLIPBOARD(("Received format announce ACK\n"));
525 forsberg 389 failed_clipboard_acks = 0;
526 forsberg 383 return;
527 forsberg 384
528 forsberg 389 } else if (3 == ptype0 && 2 == ptype1)
529     {
530     DEBUG_CLIPBOARD(("Received failed clipboard format announce ACK, retrying\n"));
531    
532     /* This is a fairly portable way to sleep 1/10 of
533     a second.. */
534     timeval.tv_sec = 0;
535     timeval.tv_usec = 100;
536     select(0, NULL, NULL, NULL, &timeval);
537     if (failed_clipboard_acks < 3)
538     {
539    
540     cliprdr_send_format_announce();
541     /* Make sure we don't get stuck in this loop */
542     failed_clipboard_acks++;
543     }
544     else
545     {
546     warning("Reached maximum number of clipboard format announce attempts. Pasting in Windows probably won't work well now.\n");
547     }
548 forsberg 383 } else if (2 == ptype0 && 0 == ptype1)
549     {
550     cliprdr_register_server_formats(s);
551     cliprdr_select_X_clipboards();
552 forsberg 384 cliprdr_ack_format_list();
553 forsberg 383 return;
554 forsberg 384 } else if (5 == ptype0 && 1 == ptype1)
555     {
556     cliprdr_handle_server_data(length, s);
557 forsberg 385 } else if (4 == ptype0 && 0 == ptype1)
558     {
559     cliprdr_handle_server_data_request(s);
560 forsberg 383 }
561 forsberg 385
562 forsberg 383
563     }
564     }
565    
566 forsberg 384
567 forsberg 383 void cliprdr_init(void)
568     {
569     primary_atom = XInternAtom(display, "PRIMARY", False);
570     clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
571 forsberg 386 targets_atom = XInternAtom(display, "TARGETS", False);
572     timestamp_atom = XInternAtom(display, "TIMESTAMP", False);
573     rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False);
574 forsberg 383 }

  ViewVC Help
Powered by ViewVC 1.1.26