/[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 384 - (show annotations)
Fri Jun 6 09:22:25 2003 UTC (21 years ago) by forsberg
File MIME type: text/plain
File size: 10095 byte(s)
Proof-of-concept, clipboard transfer server->client works!
A lot of stuff remains for a full implementation.

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 cliprdr_dataformat *server_formats = NULL;
32 static uint16 num_server_formats = 0;
33 static XSelectionEvent selection_event;
34
35 static void
36 cliprdr_print_server_formats(void)
37 {
38 #ifdef WITH_DEBUG_CLIPBOARD
39 cliprdr_dataformat *this;
40 uint16 i = 0;
41 this = server_formats;
42 DEBUG_CLIPBOARD(("There should be %d server formats.\n", num_server_formats));
43 while (NULL != this)
44 {
45 DEBUG_CLIPBOARD(("Format code %d\n", this->identifier));
46 i++;
47 this = this->next;
48 }
49 DEBUG_CLIPBOARD(("There were %d server formats.\n", i));
50 #endif
51 }
52
53 void
54 cliprdr_handle_SelectionNotify(void)
55 {
56 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));
57 }
58
59 void
60 cliprdr_handle_SelectionClear(void)
61 {
62 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));
63 }
64
65 void print_X_error(int res)
66 {
67 switch(res) {
68 case Success:
69 DEBUG_CLIPBOARD(("Success\n"));
70 break;
71
72 case BadAtom:
73 DEBUG_CLIPBOARD(("BadAtom\n"));
74 break;
75
76 case BadRequest:
77 DEBUG_CLIPBOARD(("BadRequest\n"));
78 break;
79
80 case BadAlloc:
81 DEBUG_CLIPBOARD(("BadAlloc\n"));
82 break;
83
84 case BadMatch:
85 DEBUG_CLIPBOARD(("BadMatch\n"));
86 break;
87
88 case BadValue:
89 DEBUG_CLIPBOARD(("BadValue\n"));
90 break;
91
92 case BadWindow:
93 DEBUG_CLIPBOARD(("BadWindow\n"));
94 break;
95
96 default:
97 DEBUG_CLIPBOARD(("Unknown X error code %d\n", res));
98 }
99 }
100
101 static void
102 cliprdr_request_clipboard_data(uint32 formatcode)
103 {
104 STREAM s;
105 s = sec_init(encryption ? SEC_ENCRYPT : 0, 24);
106 out_uint32_le(s, 16);
107 out_uint32_le(s, 0x13);
108 out_uint16_le(s, 4);
109 out_uint16_le(s, 0);
110 out_uint32_le(s, 4); // Remaining length
111 out_uint32_le(s, formatcode);
112 out_uint32_le(s, 0); // Unknown. Garbage pad?
113
114 s_mark_end(s);
115
116 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel!
117 }
118
119
120 void
121 cliprdr_handle_SelectionRequest(XSelectionRequestEvent *xevent)
122 {
123
124 Atom *targets;
125 int res;
126
127 XSelectionEvent xev;
128 DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n"));
129 DEBUG_CLIPBOARD(("Requestor window id 0x%x ",
130 (unsigned)xevent->requestor));
131 if (clipboard_atom == xevent->selection) {
132 DEBUG_CLIPBOARD(("wants CLIPBOARD\n"));
133 }
134 if (primary_atom == xevent->selection) {
135 DEBUG_CLIPBOARD(("wants PRIMARY\n"));
136 }
137 DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n",
138 XGetAtomName(display, xevent->target),
139 (unsigned)xevent->target,
140 XGetAtomName(display, xevent->property),
141 (unsigned)xevent->property));
142
143 xev.type = SelectionNotify;
144 xev.serial = 0;
145 xev.send_event = True;
146 xev.requestor = xevent->requestor;
147 xev.selection = xevent->selection;
148 xev.target = xevent->target;
149 xev.property = xevent->property;
150 xev.time = xevent->time;
151
152 if (targets_atom == xevent->target)
153 {
154 DEBUG_CLIPBOARD(("TARGETS requested, sending list..\n"));
155 targets = xmalloc(4*sizeof(Atom));
156 targets[0] = xevent->target;
157 targets[1] = XInternAtom(display, "TEXT", True);
158 targets[2] = XInternAtom(display, "UTF8_STRING", True);
159 targets[3] = XInternAtom(display, "TIMESTAMP", True);
160 res = XChangeProperty(display,
161 xevent->requestor,
162 xevent->property,
163 XA_ATOM,
164 32,
165 PropModeAppend,
166 (unsigned char *)targets,
167 3);
168 DEBUG_CLIPBOARD(("res after XChangeProperty is "));
169 print_X_error(res);
170
171 res = XSendEvent(display,
172 xevent->requestor,
173 False,
174 NoEventMask,
175 (XEvent *)&xev);
176 return;
177 } else if (timestamp_atom == xevent->target)
178 {
179 DEBUG_CLIPBOARD(("TIMESTAMP requested... sending 0x%x\n",
180 (unsigned)last_keyrelease));
181 res = XChangeProperty(display,
182 xevent->requestor,
183 xevent->property,
184 XA_INTEGER,
185 32,
186 PropModeAppend,
187 (unsigned char *)&last_keyrelease,
188 1);
189 res = XSendEvent(display,
190 xevent->requestor,
191 False,
192 NoEventMask,
193 (XEvent *)&xev);
194 } else /* Some other target */
195 {
196 cliprdr_request_clipboard_data(CF_TEXT);
197 memcpy(&selection_event, &xev, sizeof(xev));
198 /* Return and wait for data, handled by
199 cliprdr_handle_server_data */
200 }
201 }
202
203
204 static void
205 cliprdr_ack_format_list(void)
206 {
207 STREAM s;
208 s = sec_init(encryption ? SEC_ENCRYPT : 0, 20);
209 out_uint32_le(s, 12);
210 out_uint32_le(s, 0x13);
211 out_uint16_le(s, 3);
212 out_uint16_le(s, 1);
213 out_uint32_le(s, 0);
214 out_uint32_le(s, 0x0000c0da);
215
216 s_mark_end(s);
217
218 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel!
219 }
220
221
222
223
224
225 static void
226 cliprdr_register_server_formats(STREAM s)
227 {
228 uint32 remaining_length, pad;
229 uint16 num_formats;
230 cliprdr_dataformat *this, *next;
231
232 DEBUG_CLIPBOARD(("cliprdr_register_server_formats\n"));
233 in_uint32_le(s, remaining_length);
234
235 num_formats = remaining_length / 36;
236 if (NULL != server_formats) {
237 this = server_formats;
238 next = this->next;
239 while (NULL != next) {
240 xfree(this);
241 this = NULL;
242 this = next;
243 next = this->next;
244 }
245 }
246 this = xmalloc(sizeof(cliprdr_dataformat));
247 this->next = NULL;
248 server_formats = this;
249 num_server_formats = num_formats;
250 while (1 < num_formats) {
251 in_uint32_le(s, this->identifier);
252 in_uint8a(s, this->textual_description, 32);
253 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n",
254 this->identifier));
255 this-> next = xmalloc(sizeof(cliprdr_dataformat));
256 this = this->next;
257 num_formats--;
258 }
259 in_uint32_le(s, this->identifier);
260 DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", this->identifier));
261 in_uint8a(s, this->textual_description, 32);
262 this -> next = NULL;
263 in_uint32_le(s, pad);
264 cliprdr_print_server_formats();
265 }
266
267 static void
268 cliprdr_select_X_clipboards(void)
269 {
270 XSetSelectionOwner(display, primary_atom, wnd, last_keyrelease);
271 if (wnd != XGetSelectionOwner(display, primary_atom))
272 {
273 warning("Failed to aquire ownership of PRIMARY clipboard\n");
274 }
275 XSetSelectionOwner(display, clipboard_atom, wnd, CurrentTime);
276 if (wnd != XGetSelectionOwner(display, clipboard_atom))
277 {
278 warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
279 }
280
281 }
282
283
284
285 static void
286 cliprdr_send_format_announce(void)
287 {
288 STREAM s;
289 int number_of_formats = 1;
290 s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4);
291 out_uint32_le(s, number_of_formats*36+12);
292 out_uint32_le(s, 0x13);
293 out_uint16_le(s, 2);
294 out_uint16_le(s, 0);
295 out_uint32_le(s, number_of_formats*36);
296
297 out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description..
298 // rdp_out_unistr(s, "", 16);
299 out_uint8s(s, 32);
300
301 out_uint32_le(s, 0);
302
303 s_mark_end(s);
304 sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel!
305 }
306
307
308 static void
309 cliprdr_handle_first_handshake(STREAM s)
310 {
311 uint32 remaining_length, pad;
312 in_uint32_le(s, remaining_length);
313 in_uint32_le(s, pad);
314 DEBUG_CLIPBOARD(("Remaining length in first handshake frm server is %d, pad is %d\n",
315 remaining_length, pad));
316 cliprdr_send_format_announce();
317 }
318
319 void cliprdr_handle_server_data(uint32 length, STREAM s)
320 {
321 uint32 remaining_length;
322 char *data;
323 int res;
324 in_uint32_le(s, remaining_length);
325 data = s->p;
326 res = XChangeProperty(display,
327 selection_event.requestor,
328 selection_event.property,
329 XInternAtom(display, "STRING", False),
330 8,
331 PropModeAppend,
332 data,
333 remaining_length);
334
335 DEBUG_CLIPBOARD(("res after XChangeProperty is "));
336 print_X_error(res);
337
338 res = XSendEvent(display,
339 selection_event.requestor,
340 False,
341 NoEventMask,
342 (XEvent *)&selection_event);
343
344 DEBUG_CLIPBOARD(("res after XSendEvent is "));
345 print_X_error(res);
346
347 }
348
349 void cliprdr_callback(STREAM s)
350 {
351 uint32 length, flags;
352 uint16 ptype0, ptype1;
353 DEBUG_CLIPBOARD(("cliprdr_callback called, clipboard data:\n"));
354 #ifdef WITH_DEBUG_CLIPBOARD
355 hexdump(s->p, s->end - s->p);
356 #endif
357 in_uint32_le(s, length);
358 in_uint32_le(s, flags);
359
360 DEBUG_CLIPBOARD(("length is %d, flags are %d\n", length, flags));
361
362 if (flags & 0x03 || flags & 0x01) /* Single-write op or first-packet-of-several op */
363 {
364 in_uint16_le(s, ptype0);
365 in_uint16_le(s, ptype1);
366 DEBUG_CLIPBOARD(("ptype0 is %d, ptype1 is %d\n", ptype0, ptype1));
367 if (1 == ptype0 && 0 == ptype1) {
368 cliprdr_handle_first_handshake(s);
369 return;
370 } else if (3 == ptype0 && 1 == ptype1)
371 {
372 // Acknowledgment on our format announce. Do we care? Not right now.
373 // There is a strange pad in this packet that we might need some time,
374 // but probably not.
375 DEBUG_CLIPBOARD(("Received format announce ACK\n"));
376 return;
377
378 } else if (2 == ptype0 && 0 == ptype1)
379 {
380 cliprdr_register_server_formats(s);
381 cliprdr_select_X_clipboards();
382 cliprdr_ack_format_list();
383 return;
384 } else if (5 == ptype0 && 1 == ptype1)
385 {
386 cliprdr_handle_server_data(length, s);
387 }
388
389 }
390 }
391
392
393 void cliprdr_init(void)
394 {
395 primary_atom = XInternAtom(display, "PRIMARY", False);
396 clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
397 targets_atom = XInternAtom(display, "TARGETS", True);
398 timestamp_atom = XInternAtom(display, "TIMESTAMP", True);
399 }

  ViewVC Help
Powered by ViewVC 1.1.26