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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 383 by forsberg, Fri Jun 6 09:20:53 2003 UTC revision 390 by forsberg, Fri Jun 6 09:28:21 2003 UTC
# Line 25  Line 25 
25  extern BOOL encryption;  extern BOOL encryption;
26  extern Display *display;  extern Display *display;
27  extern Window wnd;  extern Window wnd;
28  extern Time last_keyrelease;  extern Time last_gesturetime;
29    
30    // static Time selection_timestamp;
31  static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;  static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom;
32    static Atom rdesktop_clipboard_target_atom;
33  static cliprdr_dataformat *server_formats = NULL;  static cliprdr_dataformat *server_formats = NULL;
34  static uint16 num_server_formats = 0;  static uint16 num_server_formats = 0;
35    static XSelectionEvent selection_event;
36    static uint16 clipboard_channelno;
37    
38  static void  static void
39  cliprdr_print_server_formats(void)  cliprdr_print_server_formats(void)
# Line 45  cliprdr_print_server_formats(void) Line 49  cliprdr_print_server_formats(void)
49                  i++;                  i++;
50                  this = this->next;                  this = this->next;
51          }          }
52          DEBUG_CLIPBOARD(("There was %d server formats.\n", i));          DEBUG_CLIPBOARD(("There were %d server formats.\n", i));
53  #endif  #endif
54  }  }
55    /*
56    static void
57    cliprdr_set_selection_timestamp(void)
58    {
59            XEvent xev;
60            DEBUG_CLIPBOARD(("Changing a property in order to get a timestamp\n"));
61            fflush(stdout);
62            XChangeProperty(display, wnd, rdesktop_clipboard_target_atom,
63                            XA_ATOM, 32, PropModeAppend, 0, 0);
64            DEBUG_CLIPBOARD(("Waiting for PropertyChange on wnd\n"));
65            fflush(stdout);
66            XWindowEvent(display, wnd,
67                         PropertyChangeMask, &xev);
68            DEBUG_CLIPBOARD(("Setting selection_timestamp\n"));
69            fflush(stdout);
70            selection_timestamp = xev.xproperty.time;
71    }      
72    */      
73    
74    static void
75    cliprdr_send_format_announce(void)
76    {
77            DEBUG_CLIPBOARD(("Sending format announce\n"));
78    
79            STREAM s;
80            int number_of_formats = 1;
81            s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4);
82            out_uint32_le(s, number_of_formats*36+12);
83            out_uint32_le(s, 0x13);
84            out_uint16_le(s, 2);
85            out_uint16_le(s, 0);
86            out_uint32_le(s, number_of_formats*36);
87            
88            //      out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description..
89            //      rdp_out_unistr(s, "", 16);
90            //      out_uint8s(s, 32);
91    
92    
93            out_uint32_le(s, 1); // FIXME: This is a rather bogus text description..
94            out_uint8s(s, 32);
95    
96            out_uint32_le(s, 0);
97    
98            s_mark_end(s);
99            sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
100                                clipboard_channelno);
101    }
102    
103    
104    static void
105    cliprdr_send_empty_datapacket(void)
106    {
107            STREAM out;
108            out =  sec_init(encryption ? SEC_ENCRYPT : 0,
109                            20);
110            out_uint32_le(out, 12);
111            out_uint32_le(out, 0x13);
112            out_uint16_le(out, 5);
113            out_uint16_le(out, 1);
114            out_uint32_le(out, 0);
115            /* Insert null string here? */
116            out_uint32_le(out, 0);
117            s_mark_end(out);
118            
119            sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0,
120                                clipboard_channelno);
121    }
122    
123    
124  void  void
125  cliprdr_handle_SelectionNotify(void)  cliprdr_handle_SelectionNotify(XSelectionEvent *event)
126  {  {
127    
128            unsigned char   *data;
129            unsigned long   nitems, bytes_left;
130            int res;
131    
132            int format;
133            Atom type_return;
134            Atom best_target;
135    
136            STREAM out;
137            
138          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n"));
139    
140            if (None == event->property) {
141                    cliprdr_send_empty_datapacket();
142                    return; /* Selection failed */
143            }
144    
145            DEBUG_CLIPBOARD(("selection: %s, target: %s, property: %s\n",
146                             XGetAtomName(display, event->selection),
147                             XGetAtomName(display, event->target),
148                             XGetAtomName(display, event->property)));
149    
150            if (targets_atom == event->target) {
151                    /* Response to TARGETS request. Let's find the target
152                       we want and request that */
153                    res = XGetWindowProperty(display, wnd,
154                                             rdesktop_clipboard_target_atom,
155                                             0L, 4096L, False, AnyPropertyType,
156                                             &type_return,
157                                             &format, &nitems, &bytes_left, &data);
158    
159                    if (Success != res)
160                    {
161                            DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
162                            cliprdr_send_empty_datapacket();
163                            return;
164                    }
165    
166                    if (None == type_return)
167                            /* The owner might no support TARGETS. Just try
168                               STRING */
169                            best_target = XA_STRING;
170                    else
171                    {
172                            /* FIXME: We should choose format here based
173                               on what the server wanted */
174                            best_target = XInternAtom(display, "TEXT", False);
175                            
176                            
177                    }
178    
179                    XConvertSelection(display, primary_atom,
180                                      best_target,
181                                      rdesktop_clipboard_target_atom,
182                                      wnd, event->time);
183    
184            }
185            else  /* Other clipboard data */
186            {
187                    
188                    res = XGetWindowProperty(display, wnd,
189                                             rdesktop_clipboard_target_atom,
190                                             0L, 4096L, False, AnyPropertyType,
191                                             &type_return,
192                                             &format, &nitems, &bytes_left, &data);
193    
194                    if (Success != res)
195                    {
196                            DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
197                            cliprdr_send_empty_datapacket();
198                            return;
199                    }
200    
201                    /* We need to handle INCR as well */
202    
203                    out =  sec_init(encryption ? SEC_ENCRYPT : 0,
204                                    20+nitems+1);
205                    out_uint32_le(out, 12+nitems+1);
206                    out_uint32_le(out, 0x13);
207                    out_uint16_le(out, 5);
208                    out_uint16_le(out, 1);
209                    out_uint32_le(out, nitems+1);
210                    out_uint8p(out, data, nitems+1);
211                    /* Insert null string here? */
212                    out_uint32_le(out, 0);
213                    s_mark_end(out);
214            
215                    sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0,
216                                        clipboard_channelno);
217    
218                    cliprdr_send_format_announce();
219                    
220            }
221            
222            
223  }  }
224    
225  void  void
226  cliprdr_handle_SelectionClear(void)  cliprdr_handle_SelectionClear(void)
227  {  {
228          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n"));
229            cliprdr_send_format_announce();
230  }  }
231    
232  void print_X_error(int res)  
233    static void
234    cliprdr_request_clipboard_data(uint32 formatcode)
235  {  {
236          switch(res) {          STREAM s;
237          case Success:          s = sec_init(encryption ? SEC_ENCRYPT : 0, 24);
238                  DEBUG_CLIPBOARD(("Success\n"));          out_uint32_le(s, 16);
239                  break;          out_uint32_le(s, 0x13);
240            out_uint16_le(s, 4);
241          case BadAtom:          out_uint16_le(s, 0);
242                  DEBUG_CLIPBOARD(("BadAtom\n"));          out_uint32_le(s, 4); // Remaining length
243                  break;          out_uint32_le(s, formatcode);
244            out_uint32_le(s, 0); // Unknown. Garbage pad?
         case BadRequest:  
                 DEBUG_CLIPBOARD(("BadRequest\n"));  
                 break;  
   
         case BadAlloc:  
                 DEBUG_CLIPBOARD(("BadAlloc\n"));  
                 break;  
   
         case BadMatch:  
                 DEBUG_CLIPBOARD(("BadMatch\n"));  
                 break;  
   
         case BadValue:  
                 DEBUG_CLIPBOARD(("BadValue\n"));  
                 break;  
   
         case BadWindow:  
                 DEBUG_CLIPBOARD(("BadWindo\n"));  
                 break;  
245    
246          default:          s_mark_end(s);
247                  DEBUG_CLIPBOARD(("Unknown X error code %d\n", res));  
248          }          sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
249                                clipboard_channelno);
250  }  }
251    
252    
253  void  void
254  cliprdr_handle_SelectionRequest(XSelectionRequestEvent *xevent)  cliprdr_handle_SelectionRequest(XSelectionRequestEvent *xevent)
255  {  {
256    
         Atom type_return;  
257          Atom *targets;          Atom *targets;
         int format_return;  
         long nitems_return;  
         long bytes_after_return;  
         char **prop_return;  
258          int res;          int res;
259    
260          XSelectionEvent xev;          XSelectionEvent xev;
261          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n"));          DEBUG_CLIPBOARD(("cliprdr_handle_SelectionRequest\n"));
262          DEBUG_CLIPBOARD(("Requestor window id 0x%x ", xevent->requestor));          DEBUG_CLIPBOARD(("Requestor window id 0x%x ",
263                             (unsigned)xevent->requestor));
264          if (clipboard_atom == xevent->selection) {          if (clipboard_atom == xevent->selection) {
265                  DEBUG_CLIPBOARD(("wants CLIPBOARD\n"));                  DEBUG_CLIPBOARD(("wants CLIPBOARD\n"));
266          }          }
# Line 120  cliprdr_handle_SelectionRequest(XSelecti Line 269  cliprdr_handle_SelectionRequest(XSelecti
269          }            }  
270          DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n",          DEBUG_CLIPBOARD(("Target is %s (0x%x), property is %s (0x%x)\n",
271                           XGetAtomName(display, xevent->target),                           XGetAtomName(display, xevent->target),
272                           xevent->target,                           (unsigned)xevent->target,
273                           XGetAtomName(display, xevent->property),                           XGetAtomName(display, xevent->property),
274                           xevent->property));                           (unsigned)xevent->property));
275    
276          xev.type = SelectionNotify;          xev.type = SelectionNotify;
277          xev.serial = 0;          xev.serial = 0;
# Line 149  cliprdr_handle_SelectionRequest(XSelecti Line 298  cliprdr_handle_SelectionRequest(XSelecti
298                                        PropModeAppend,                                        PropModeAppend,
299                                        (unsigned char *)targets,                                        (unsigned char *)targets,
300                                        3);                                        3);
                 DEBUG_CLIPBOARD(("res after XChangeProperty is "));  
                 print_X_error(res);      
301    
302                  res = XSendEvent(display,                  res = XSendEvent(display,
303                                   xevent->requestor,                                   xevent->requestor,
# Line 161  cliprdr_handle_SelectionRequest(XSelecti Line 308  cliprdr_handle_SelectionRequest(XSelecti
308          } else if (timestamp_atom == xevent->target)          } else if (timestamp_atom == xevent->target)
309          {          {
310                  DEBUG_CLIPBOARD(("TIMESTAMP requested... sending 0x%x\n",                  DEBUG_CLIPBOARD(("TIMESTAMP requested... sending 0x%x\n",
311                                   last_keyrelease));                                   (unsigned)last_gesturetime));
312                  res = XChangeProperty(display,                  res = XChangeProperty(display,
313                                        xevent->requestor,                                        xevent->requestor,
314                                        xevent->property,                                        xevent->property,
315                                        XA_INTEGER,                                        XA_INTEGER,
316                                        32,                                        32,
317                                        PropModeAppend,                                        PropModeAppend,
318                                        (unsigned char *)&last_keyrelease,                                        (unsigned char *)&last_gesturetime,
319                                        1);                                        1);
320                  res = XSendEvent(display,                  res = XSendEvent(display,
321                                   xevent->requestor,                                   xevent->requestor,
# Line 177  cliprdr_handle_SelectionRequest(XSelecti Line 324  cliprdr_handle_SelectionRequest(XSelecti
324                                   (XEvent *)&xev);                                   (XEvent *)&xev);
325          } else /* Some other target */          } else /* Some other target */
326          {          {
327                  res = XChangeProperty(display,                  cliprdr_request_clipboard_data(CF_TEXT);
328                                        xevent->requestor,                  memcpy(&selection_event, &xev, sizeof(xev));
329                                        xevent->property,                  /* Return and wait for data, handled by
330                                        XInternAtom(display, "STRING", False),                     cliprdr_handle_server_data */
331                                        8,          }
332                                        PropModeAppend,  }
                                       "krattoflabkat",  
                                       13);  
333    
                 DEBUG_CLIPBOARD(("res after XChangeProperty is "));  
                 print_X_error(res);      
           
                 xev.type = SelectionNotify;  
                 xev.serial = 0;  
                 xev.send_event = True;  
                 xev.requestor = xevent->requestor;  
                 xev.selection = xevent->selection;  
                 xev.target = xevent->target;  
                 xev.property = xevent->property;  
                 xev.time = xevent->time;  
334    
335                  res = XSendEvent(display,  static void
336                                   xevent->requestor,  cliprdr_ack_format_list(void)
337                                   False,  {
338                                   NoEventMask,          STREAM s;
339                                   (XEvent *)&xev);          s = sec_init(encryption ? SEC_ENCRYPT : 0, 20);
340                    out_uint32_le(s, 12);
341                  DEBUG_CLIPBOARD(("res after XSendEvent is "));          out_uint32_le(s, 0x13);
342                  print_X_error(res);          out_uint16_le(s, 3);
343          }          out_uint16_le(s, 1);
344            out_uint32_le(s, 0);
345            out_uint32_le(s, 0x0000c0da);
346    
347            s_mark_end(s);
348    
349            sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0,
350                                clipboard_channelno);
351  }  }
352    
353                    
354    
355    
356    
357  static void  static void
358  cliprdr_register_server_formats(STREAM s)  cliprdr_register_server_formats(STREAM s)
# Line 238  cliprdr_register_server_formats(STREAM s Line 382  cliprdr_register_server_formats(STREAM s
382          while (1 < num_formats) {          while (1 < num_formats) {
383                  in_uint32_le(s, this->identifier);                  in_uint32_le(s, this->identifier);
384                  in_uint8a(s, this->textual_description, 32);                  in_uint8a(s, this->textual_description, 32);
385                  DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n", this->identifier));                  DEBUG_CLIPBOARD(("Stored format description with numeric id %d\n",
386                                     this->identifier));
387                  this-> next = xmalloc(sizeof(cliprdr_dataformat));                  this-> next = xmalloc(sizeof(cliprdr_dataformat));
388                  this = this->next;                  this = this->next;
389                  num_formats--;                  num_formats--;
# Line 254  cliprdr_register_server_formats(STREAM s Line 399  cliprdr_register_server_formats(STREAM s
399  static void  static void
400  cliprdr_select_X_clipboards(void)  cliprdr_select_X_clipboards(void)
401  {  {
402          XSetSelectionOwner(display, primary_atom, wnd, last_keyrelease);          XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime);
403          if (wnd != XGetSelectionOwner(display, primary_atom))          if (wnd != XGetSelectionOwner(display, primary_atom))
404          {          {
405                  warning("Failed to aquire ownership of PRIMARY clipboard\n");                  warning("Failed to aquire ownership of PRIMARY clipboard\n");
406          }          }
407          XSetSelectionOwner(display, clipboard_atom, wnd, CurrentTime);          XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime);
408          if (wnd != XGetSelectionOwner(display, clipboard_atom))          if (wnd != XGetSelectionOwner(display, clipboard_atom))
409          {          {
410                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");                  warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
# Line 267  cliprdr_select_X_clipboards(void) Line 412  cliprdr_select_X_clipboards(void)
412                    
413  }  }
414    
 static void  
 cliprdr_send_format_announce(void)  
 {  
         STREAM s;  
         int number_of_formats = 1;  
         s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4);  
         out_uint32_le(s, number_of_formats*36+12);  
         out_uint32_le(s, 0x13);  
         out_uint16_le(s, 2);  
         out_uint16_le(s, 0);  
         out_uint32_le(s, number_of_formats*36);  
415                    
         out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description..  
         //      rdp_out_unistr(s, "", 16);  
         out_uint8s(s, 32);  
416    
         out_uint32_le(s, 0);  
417    
         s_mark_end(s);  
         sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel!  
 }  
                   
418    
419  static void  static void
420  cliprdr_handle_first_handshake(STREAM s)  cliprdr_handle_first_handshake(STREAM s)
# Line 301  cliprdr_handle_first_handshake(STREAM s) Line 427  cliprdr_handle_first_handshake(STREAM s)
427          cliprdr_send_format_announce();          cliprdr_send_format_announce();
428  }  }
429    
430  void cliprdr_callback(STREAM s)  void cliprdr_handle_server_data(uint32 length, STREAM s)
431    {
432            uint32 remaining_length;
433            char *data;
434            in_uint32_le(s, remaining_length);
435            data = s->p;
436            XChangeProperty(display,
437                            selection_event.requestor,
438                            selection_event.property,
439                            XInternAtom(display, "STRING", False),
440                            8,
441                            PropModeAppend,
442                            data,
443                            remaining_length);
444    
445            XSendEvent(display,
446                       selection_event.requestor,
447                       False,
448                       NoEventMask,
449                       (XEvent *)&selection_event);
450            
451    
452    }
453    
454    void cliprdr_handle_server_data_request(STREAM s)
455  {  {
456            Window selectionowner;
457            uint32 remaining_length;
458            uint32 wanted_formatcode, pad;
459    
460            in_uint32_le(s, remaining_length);
461            in_uint32_le(s, wanted_formatcode);
462            in_uint32_le(s, pad);
463    
464            /* FIXME: Check that we support this formatcode */
465    
466            DEBUG_CLIPBOARD(("Request from server for format %d\n",
467                             wanted_formatcode));
468    
469            selectionowner = XGetSelectionOwner(display, primary_atom);
470    
471            if (None != selectionowner)
472            {
473            
474                    /* FIXME: Perhaps we should check if we are the owner? */
475    
476                    XConvertSelection(display, primary_atom,
477                                      targets_atom,
478                                      rdesktop_clipboard_target_atom,
479                                      wnd, CurrentTime);
480    
481                    /* The rest of the transfer is handled in
482                       cliprdr_handle_SelectionNotify */
483    
484            } else
485            {
486                    DEBUG_CLIPBOARD(("There were no owner for PRIMARY, sending empty string\n")); // FIXME: Should we always send an empty string?
487    
488                    cliprdr_send_empty_datapacket();
489            }
490    
491    
492    }
493            
494    
495    void cliprdr_callback(STREAM s, uint16 channelno)
496    {
497            static int failed_clipboard_acks = 0;
498            struct timeval timeval;
499          uint32 length, flags;          uint32 length, flags;
500          uint16 ptype0, ptype1;          uint16 ptype0, ptype1;
501          DEBUG_CLIPBOARD(("cliprdr_callback called, clipboard data:\n"));          clipboard_channelno = channelno;
502            DEBUG_CLIPBOARD(("cliprdr_callback called with channelno %d, clipboard data:\n", channelno));
503  #ifdef WITH_DEBUG_CLIPBOARD  #ifdef WITH_DEBUG_CLIPBOARD
504          hexdump(s->p, s->end - s->p);          hexdump(s->p, s->end - s->p);
505  #endif  #endif
# Line 328  void cliprdr_callback(STREAM s) Line 522  void cliprdr_callback(STREAM s)
522                          // There is a strange pad in this packet that we might need some time,                          // There is a strange pad in this packet that we might need some time,
523                          // but probably not.                          // but probably not.
524                          DEBUG_CLIPBOARD(("Received format announce ACK\n"));                          DEBUG_CLIPBOARD(("Received format announce ACK\n"));
525                            failed_clipboard_acks = 0;
526                          return;                          return;
527    
528                    } else if (3 == ptype0 && 2 == ptype1)
529                    {
530                            DEBUG_CLIPBOARD(("Received failed clipboard format announce ACK, retrying\n"));
531    
532                            /* This is a fairly portable way to sleep 1/10 of
533                               a second.. */
534                            timeval.tv_sec = 0;
535                            timeval.tv_usec = 100;
536                            select(0, NULL, NULL, NULL, &timeval);
537                            if (failed_clipboard_acks < 3)
538                            {
539                                    
540                                    cliprdr_send_format_announce();
541                                    /* Make sure we don't get stuck in this loop */
542                                    failed_clipboard_acks++;
543                            }
544                            else
545                            {
546                                    warning("Reached maximum number of clipboard format announce attempts. Pasting in Windows probably won't work well now.\n");
547                            }
548                  } else if (2 == ptype0 && 0 == ptype1)                  } else if (2 == ptype0 && 0 == ptype1)
549                  {                  {
550                          cliprdr_register_server_formats(s);                          cliprdr_register_server_formats(s);
551                          cliprdr_select_X_clipboards();                          cliprdr_select_X_clipboards();
552                            cliprdr_ack_format_list();
553                          return;                          return;
554                    } else if (5 == ptype0 && 1 == ptype1)
555                    {
556                            cliprdr_handle_server_data(length, s);
557                    } else if (4 == ptype0 && 0 == ptype1)
558                    {
559                            cliprdr_handle_server_data_request(s);
560                  }                  }
561    
562                                    
563          }          }
564  }  }
565    
566    
567  void cliprdr_init(void)  void cliprdr_init(void)
568  {  {
569          primary_atom = XInternAtom(display, "PRIMARY", False);          primary_atom = XInternAtom(display, "PRIMARY", False);
570          clipboard_atom = XInternAtom(display, "CLIPBOARD", False);          clipboard_atom = XInternAtom(display, "CLIPBOARD", False);
571          targets_atom = XInternAtom(display, "TARGETS", True);          targets_atom = XInternAtom(display, "TARGETS", False);
572          timestamp_atom = XInternAtom(display, "TIMESTAMP", True);          timestamp_atom = XInternAtom(display, "TIMESTAMP", False);
573            rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False);
574  }  }

Legend:
Removed from v.383  
changed lines
  Added in v.390

  ViewVC Help
Powered by ViewVC 1.1.26