/[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 389 - (hide annotations)
Fri Jun 6 09:26:49 2003 UTC (20 years, 11 months ago) by forsberg
File MIME type: text/plain
File size: 14498 byte(s)
Added one to the length of sent data, since XGetProperty is not reporting the
null byte (although space is allocated for it as it seems).

Resend format announces if they fail, with a small delay. Ugly hack, but
it works..

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

  ViewVC Help
Powered by ViewVC 1.1.26