/[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 387 - (hide annotations)
Fri Jun 6 09:25:30 2003 UTC (21 years ago) by forsberg
File MIME type: text/plain
File size: 13964 byte(s)
Send a format announce when we loose ownership of PRIMARY.

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

  ViewVC Help
Powered by ViewVC 1.1.26