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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 387 - (show 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 /* -*- 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 static Atom rdesktop_clipboard_target_atom;
32 static cliprdr_dataformat *server_formats = NULL;
33 static uint16 num_server_formats = 0;
34 static XSelectionEvent selection_event;
35
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 DEBUG_CLIPBOARD(("There were %d server formats.\n", i));
51 #endif
52 }
53
54 static void
55 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 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 void
101 cliprdr_handle_SelectionNotify(XSelectionEvent *event)
102 {
103
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 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));
115
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 }
197
198 void
199 cliprdr_handle_SelectionClear(void)
200 {
201 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));
202 cliprdr_send_format_announce();
203 }
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 DEBUG_CLIPBOARD(("BadWindow\n"));
234 break;
235
236 default:
237 DEBUG_CLIPBOARD(("Unknown X error code %d\n", res));
238 }
239 }
240
241 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 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 DEBUG_CLIPBOARD(("Requestor window id 0x%x ",
270 (unsigned)xevent->requestor));
271 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 (unsigned)xevent->target,
280 XGetAtomName(display, xevent->property),
281 (unsigned)xevent->property));
282
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 (unsigned)last_keyrelease));
321 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 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
343
344 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 }
360
361
362
363
364
365 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 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n",
394 this->identifier));
395 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
424
425
426
427 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 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 void cliprdr_handle_server_data_request(STREAM s)
469 {
470 Window selectionowner;
471 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 selectionowner = XGetSelectionOwner(display, primary_atom);
484
485 if (None != selectionowner)
486 {
487
488 /* FIXME: Perhaps we should check if we are the owner? */
489
490 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 {
500 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 }
504
505
506 }
507
508
509 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
538 } else if (2 == ptype0 && 0 == ptype1)
539 {
540 cliprdr_register_server_formats(s);
541 cliprdr_select_X_clipboards();
542 cliprdr_ack_format_list();
543 return;
544 } else if (5 == ptype0 && 1 == ptype1)
545 {
546 cliprdr_handle_server_data(length, s);
547 } else if (4 == ptype0 && 0 == ptype1)
548 {
549 cliprdr_handle_server_data_request(s);
550 }
551
552
553 }
554 }
555
556
557 void cliprdr_init(void)
558 {
559 primary_atom = XInternAtom(display, "PRIMARY", False);
560 clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
561 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 }

  ViewVC Help
Powered by ViewVC 1.1.26