/[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 388 - (hide annotations)
Fri Jun 6 09:26:11 2003 UTC (21 years ago) by forsberg
File MIME type: text/plain
File size: 13788 byte(s)
Use last button or keypress, either up or down, as event time when aquiring
PRIMARY (and CLIPBOARD).

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     20+nitems);
202     out_uint32_le(out, 12+nitems);
203     out_uint32_le(out, 0x13);
204     out_uint16_le(out, 5);
205     out_uint16_le(out, 1);
206     out_uint32_le(out, nitems);
207     out_uint8p(out, data, nitems);
208     /* 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     uint32 length, flags;
492     uint16 ptype0, ptype1;
493     DEBUG_CLIPBOARD(("cliprdr_callback called, clipboard data:\n"));
494     #ifdef WITH_DEBUG_CLIPBOARD
495     hexdump(s->p, s->end - s->p);
496     #endif
497     in_uint32_le(s, length);
498     in_uint32_le(s, flags);
499    
500     DEBUG_CLIPBOARD(("length is %d, flags are %d\n", length, flags));
501    
502     if (flags & 0x03 || flags & 0x01) /* Single-write op or first-packet-of-several op */
503     {
504     in_uint16_le(s, ptype0);
505     in_uint16_le(s, ptype1);
506     DEBUG_CLIPBOARD(("ptype0 is %d, ptype1 is %d\n", ptype0, ptype1));
507     if (1 == ptype0 && 0 == ptype1) {
508     cliprdr_handle_first_handshake(s);
509     return;
510     } else if (3 == ptype0 && 1 == ptype1)
511     {
512     // Acknowledgment on our format announce. Do we care? Not right now.
513     // There is a strange pad in this packet that we might need some time,
514     // but probably not.
515     DEBUG_CLIPBOARD(("Received format announce ACK\n"));
516     return;
517 forsberg 384
518 forsberg 383 } else if (2 == ptype0 && 0 == ptype1)
519     {
520     cliprdr_register_server_formats(s);
521     cliprdr_select_X_clipboards();
522 forsberg 384 cliprdr_ack_format_list();
523 forsberg 383 return;
524 forsberg 384 } else if (5 == ptype0 && 1 == ptype1)
525     {
526     cliprdr_handle_server_data(length, s);
527 forsberg 385 } else if (4 == ptype0 && 0 == ptype1)
528     {
529     cliprdr_handle_server_data_request(s);
530 forsberg 383 }
531 forsberg 385
532 forsberg 383
533     }
534     }
535    
536 forsberg 384
537 forsberg 383 void cliprdr_init(void)
538     {
539     primary_atom = XInternAtom(display, "PRIMARY", False);
540     clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
541 forsberg 386 targets_atom = XInternAtom(display, "TARGETS", False);
542     timestamp_atom = XInternAtom(display, "TIMESTAMP", False);
543     rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False);
544 forsberg 383 }

  ViewVC Help
Powered by ViewVC 1.1.26