/[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 386 - (hide annotations)
Fri Jun 6 09:24:15 2003 UTC (21 years ago) by forsberg
File MIME type: text/plain
File size: 13929 byte(s)
Rudimentary client->server clipboard transfer.

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

  ViewVC Help
Powered by ViewVC 1.1.26