1 /*
2  * barrier -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2002 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "client/ServerProxy.h"
20 
21 #include "client/Client.h"
22 #include "barrier/FileChunk.h"
23 #include "barrier/ClipboardChunk.h"
24 #include "barrier/StreamChunker.h"
25 #include "barrier/Clipboard.h"
26 #include "barrier/ProtocolUtil.h"
27 #include "barrier/option_types.h"
28 #include "barrier/protocol_types.h"
29 #include "io/IStream.h"
30 #include "base/Log.h"
31 #include "base/IEventQueue.h"
32 #include "base/TMethodEventJob.h"
33 #include "base/XBase.h"
34 
35 #include <memory>
36 
37 //
38 // ServerProxy
39 //
40 
ServerProxy(Client * client,barrier::IStream * stream,IEventQueue * events)41 ServerProxy::ServerProxy(Client* client, barrier::IStream* stream, IEventQueue* events) :
42     m_client(client),
43     m_stream(stream),
44     m_seqNum(0),
45     m_compressMouse(false),
46     m_compressMouseRelative(false),
47     m_xMouse(0),
48     m_yMouse(0),
49     m_dxMouse(0),
50     m_dyMouse(0),
51     m_ignoreMouse(false),
52     m_keepAliveAlarm(0.0),
53     m_keepAliveAlarmTimer(NULL),
54     m_parser(&ServerProxy::parseHandshakeMessage),
55     m_events(events)
56 {
57     assert(m_client != NULL);
58     assert(m_stream != NULL);
59 
60     // initialize modifier translation table
61     for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id)
62         m_modifierTranslationTable[id] = id;
63 
64     // handle data on stream
65     m_events->adoptHandler(m_events->forIStream().inputReady(),
66                             m_stream->getEventTarget(),
67                             new TMethodEventJob<ServerProxy>(this,
68                                 &ServerProxy::handleData));
69 
70     m_events->adoptHandler(m_events->forClipboard().clipboardSending(),
71                             this,
72                             new TMethodEventJob<ServerProxy>(this,
73                                 &ServerProxy::handleClipboardSendingEvent));
74 
75     // send heartbeat
76     setKeepAliveRate(kKeepAliveRate);
77 }
78 
~ServerProxy()79 ServerProxy::~ServerProxy()
80 {
81     setKeepAliveRate(-1.0);
82     m_events->removeHandler(m_events->forIStream().inputReady(),
83                             m_stream->getEventTarget());
84     m_events->removeHandler(m_events->forClipboard().clipboardSending(), this);
85 }
86 
87 void
resetKeepAliveAlarm()88 ServerProxy::resetKeepAliveAlarm()
89 {
90     if (m_keepAliveAlarmTimer != NULL) {
91         m_events->removeHandler(Event::kTimer, m_keepAliveAlarmTimer);
92         m_events->deleteTimer(m_keepAliveAlarmTimer);
93         m_keepAliveAlarmTimer = NULL;
94     }
95     if (m_keepAliveAlarm > 0.0) {
96         m_keepAliveAlarmTimer =
97             m_events->newOneShotTimer(m_keepAliveAlarm, NULL);
98         m_events->adoptHandler(Event::kTimer, m_keepAliveAlarmTimer,
99                             new TMethodEventJob<ServerProxy>(this,
100                                 &ServerProxy::handleKeepAliveAlarm));
101     }
102 }
103 
104 void
setKeepAliveRate(double rate)105 ServerProxy::setKeepAliveRate(double rate)
106 {
107     m_keepAliveAlarm = rate * kKeepAlivesUntilDeath;
108     resetKeepAliveAlarm();
109 }
110 
111 void
handleData(const Event &,void *)112 ServerProxy::handleData(const Event&, void*)
113 {
114     // handle messages until there are no more.  first read message code.
115     UInt8 code[4];
116     UInt32 n = m_stream->read(code, 4);
117     while (n != 0) {
118         // verify we got an entire code
119         if (n != 4) {
120             LOG((CLOG_ERR "incomplete message from server: %d bytes", n));
121             m_client->disconnect("incomplete message from server");
122             return;
123         }
124 
125         // parse message
126         LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
127         switch ((this->*m_parser)(code)) {
128         case kOkay:
129             break;
130 
131         case kUnknown:
132             LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
133             m_client->disconnect("invalid message from server");
134             return;
135 
136         case kDisconnect:
137             return;
138         }
139 
140         // next message
141         n = m_stream->read(code, 4);
142     }
143 
144     flushCompressedMouse();
145 }
146 
147 ServerProxy::EResult
parseHandshakeMessage(const UInt8 * code)148 ServerProxy::parseHandshakeMessage(const UInt8* code)
149 {
150     if (memcmp(code, kMsgQInfo, 4) == 0) {
151         queryInfo();
152     }
153 
154     else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
155         infoAcknowledgment();
156     }
157 
158     else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
159         setOptions();
160 
161         // handshake is complete
162         m_parser = &ServerProxy::parseMessage;
163         m_client->handshakeComplete();
164     }
165 
166     else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
167         resetOptions();
168     }
169 
170     else if (memcmp(code, kMsgCKeepAlive, 4) == 0) {
171         // echo keep alives and reset alarm
172         ProtocolUtil::writef(m_stream, kMsgCKeepAlive);
173         resetKeepAliveAlarm();
174     }
175 
176     else if (memcmp(code, kMsgCNoop, 4) == 0) {
177         // accept and discard no-op
178     }
179 
180     else if (memcmp(code, kMsgCClose, 4) == 0) {
181         // server wants us to hangup
182         LOG((CLOG_DEBUG1 "recv close"));
183         m_client->disconnect(NULL);
184         return kDisconnect;
185     }
186 
187     else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
188         SInt32 major, minor;
189         ProtocolUtil::readf(m_stream,
190                         kMsgEIncompatible + 4, &major, &minor);
191         LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
192         m_client->disconnect("server has incompatible version");
193         return kDisconnect;
194     }
195 
196     else if (memcmp(code, kMsgEBusy, 4) == 0) {
197         LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
198         m_client->disconnect("server already has a connected client with our name");
199         return kDisconnect;
200     }
201 
202     else if (memcmp(code, kMsgEUnknown, 4) == 0) {
203         LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
204         m_client->disconnect("server refused client with our name");
205         return kDisconnect;
206     }
207 
208     else if (memcmp(code, kMsgEBad, 4) == 0) {
209         LOG((CLOG_ERR "server disconnected due to a protocol error"));
210         m_client->disconnect("server reported a protocol error");
211         return kDisconnect;
212     }
213     else {
214         return kUnknown;
215     }
216 
217     return kOkay;
218 }
219 
220 ServerProxy::EResult
parseMessage(const UInt8 * code)221 ServerProxy::parseMessage(const UInt8* code)
222 {
223     if (memcmp(code, kMsgDMouseMove, 4) == 0) {
224         mouseMove();
225     }
226 
227     else if (memcmp(code, kMsgDMouseRelMove, 4) == 0) {
228         mouseRelativeMove();
229     }
230 
231     else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
232         mouseWheel();
233     }
234 
235     else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
236         keyDown();
237     }
238 
239     else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
240         keyUp();
241     }
242 
243     else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
244         mouseDown();
245     }
246 
247     else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
248         mouseUp();
249     }
250 
251     else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
252         keyRepeat();
253     }
254 
255     else if (memcmp(code, kMsgCKeepAlive, 4) == 0) {
256         // echo keep alives and reset alarm
257         ProtocolUtil::writef(m_stream, kMsgCKeepAlive);
258         resetKeepAliveAlarm();
259     }
260 
261     else if (memcmp(code, kMsgCNoop, 4) == 0) {
262         // accept and discard no-op
263     }
264 
265     else if (memcmp(code, kMsgCEnter, 4) == 0) {
266         enter();
267     }
268 
269     else if (memcmp(code, kMsgCLeave, 4) == 0) {
270         leave();
271     }
272 
273     else if (memcmp(code, kMsgCClipboard, 4) == 0) {
274         grabClipboard();
275     }
276 
277     else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
278         screensaver();
279     }
280 
281     else if (memcmp(code, kMsgQInfo, 4) == 0) {
282         queryInfo();
283     }
284 
285     else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
286         infoAcknowledgment();
287     }
288 
289     else if (memcmp(code, kMsgDClipboard, 4) == 0) {
290         setClipboard();
291     }
292 
293     else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
294         resetOptions();
295     }
296 
297     else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
298         setOptions();
299     }
300 
301     else if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
302         fileChunkReceived();
303     }
304     else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
305         dragInfoReceived();
306     }
307 
308     else if (memcmp(code, kMsgCClose, 4) == 0) {
309         // server wants us to hangup
310         LOG((CLOG_DEBUG1 "recv close"));
311         m_client->disconnect(NULL);
312         return kDisconnect;
313     }
314     else if (memcmp(code, kMsgEBad, 4) == 0) {
315         LOG((CLOG_ERR "server disconnected due to a protocol error"));
316         m_client->disconnect("server reported a protocol error");
317         return kDisconnect;
318     }
319     else {
320         return kUnknown;
321     }
322 
323     // send a reply.  this is intended to work around a delay when
324     // running a linux server and an OS X (any BSD?) client.  the
325     // client waits to send an ACK (if the system control flag
326     // net.inet.tcp.delayed_ack is 1) in hopes of piggybacking it
327     // on a data packet.  we provide that packet here.  i don't
328     // know why a delayed ACK should cause the server to wait since
329     // TCP_NODELAY is enabled.
330     ProtocolUtil::writef(m_stream, kMsgCNoop);
331 
332     return kOkay;
333 }
334 
335 void
handleKeepAliveAlarm(const Event &,void *)336 ServerProxy::handleKeepAliveAlarm(const Event&, void*)
337 {
338     LOG((CLOG_NOTE "server is dead"));
339     m_client->disconnect("server is not responding");
340 }
341 
342 void
onInfoChanged()343 ServerProxy::onInfoChanged()
344 {
345     // ignore mouse motion until we receive acknowledgment of our info
346     // change message.
347     m_ignoreMouse = true;
348 
349     // send info update
350     queryInfo();
351 }
352 
353 bool
onGrabClipboard(ClipboardID id)354 ServerProxy::onGrabClipboard(ClipboardID id)
355 {
356     LOG((CLOG_DEBUG1 "sending clipboard %d changed", id));
357     ProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum);
358     return true;
359 }
360 
361 void
onClipboardChanged(ClipboardID id,const IClipboard * clipboard)362 ServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard)
363 {
364     std::string data = IClipboard::marshall(clipboard);
365     LOG((CLOG_DEBUG "sending clipboard %d seqnum=%d", id, m_seqNum));
366 
367     StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this);
368 }
369 
370 void
flushCompressedMouse()371 ServerProxy::flushCompressedMouse()
372 {
373     if (m_compressMouse) {
374         m_compressMouse = false;
375         m_client->mouseMove(m_xMouse, m_yMouse);
376     }
377     if (m_compressMouseRelative) {
378         m_compressMouseRelative = false;
379         m_client->mouseRelativeMove(m_dxMouse, m_dyMouse);
380         m_dxMouse = 0;
381         m_dyMouse = 0;
382     }
383 }
384 
385 void
sendInfo(const ClientInfo & info)386 ServerProxy::sendInfo(const ClientInfo& info)
387 {
388     LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, info.m_w, info.m_h));
389     ProtocolUtil::writef(m_stream, kMsgDInfo,
390                                 info.m_x, info.m_y,
391                                 info.m_w, info.m_h, 0,
392                                 info.m_mx, info.m_my);
393 }
394 
395 KeyID
translateKey(KeyID id) const396 ServerProxy::translateKey(KeyID id) const
397 {
398     static const KeyID s_translationTable[kKeyModifierIDLast][2] = {
399         { kKeyNone,      kKeyNone },
400         { kKeyShift_L,   kKeyShift_R },
401         { kKeyControl_L, kKeyControl_R },
402         { kKeyAlt_L,     kKeyAlt_R },
403         { kKeyMeta_L,    kKeyMeta_R },
404         { kKeySuper_L,   kKeySuper_R },
405         { kKeyAltGr,     kKeyAltGr}
406     };
407 
408     KeyModifierID id2 = kKeyModifierIDNull;
409     UInt32 side      = 0;
410     switch (id) {
411     case kKeyShift_L:
412         id2  = kKeyModifierIDShift;
413         side = 0;
414         break;
415 
416     case kKeyShift_R:
417         id2  = kKeyModifierIDShift;
418         side = 1;
419         break;
420 
421     case kKeyControl_L:
422         id2  = kKeyModifierIDControl;
423         side = 0;
424         break;
425 
426     case kKeyControl_R:
427         id2  = kKeyModifierIDControl;
428         side = 1;
429         break;
430 
431     case kKeyAlt_L:
432         id2  = kKeyModifierIDAlt;
433         side = 0;
434         break;
435 
436     case kKeyAlt_R:
437         id2  = kKeyModifierIDAlt;
438         side = 1;
439         break;
440 
441     case kKeyAltGr:
442         id2 = kKeyModifierIDAltGr;
443         side = 1; // there is only one alt gr key on the right side
444         break;
445 
446     case kKeyMeta_L:
447         id2  = kKeyModifierIDMeta;
448         side = 0;
449         break;
450 
451     case kKeyMeta_R:
452         id2  = kKeyModifierIDMeta;
453         side = 1;
454         break;
455 
456     case kKeySuper_L:
457         id2  = kKeyModifierIDSuper;
458         side = 0;
459         break;
460 
461     case kKeySuper_R:
462         id2  = kKeyModifierIDSuper;
463         side = 1;
464         break;
465     }
466 
467     if (id2 != kKeyModifierIDNull) {
468         return s_translationTable[m_modifierTranslationTable[id2]][side];
469     }
470     else {
471         return id;
472     }
473 }
474 
475 KeyModifierMask
translateModifierMask(KeyModifierMask mask) const476 ServerProxy::translateModifierMask(KeyModifierMask mask) const
477 {
478     static const KeyModifierMask s_masks[kKeyModifierIDLast] = {
479         0x0000,
480         KeyModifierShift,
481         KeyModifierControl,
482         KeyModifierAlt,
483         KeyModifierMeta,
484         KeyModifierSuper,
485         KeyModifierAltGr
486     };
487 
488     KeyModifierMask newMask = mask & ~(KeyModifierShift |
489                                         KeyModifierControl |
490                                         KeyModifierAlt |
491                                         KeyModifierMeta |
492                                         KeyModifierSuper |
493                                         KeyModifierAltGr );
494     if ((mask & KeyModifierShift) != 0) {
495         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDShift]];
496     }
497     if ((mask & KeyModifierControl) != 0) {
498         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDControl]];
499     }
500     if ((mask & KeyModifierAlt) != 0) {
501         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAlt]];
502     }
503     if ((mask & KeyModifierAltGr) != 0) {
504         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAltGr]];
505     }
506     if ((mask & KeyModifierMeta) != 0) {
507         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDMeta]];
508     }
509     if ((mask & KeyModifierSuper) != 0) {
510         newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]];
511     }
512     return newMask;
513 }
514 
515 void
enter()516 ServerProxy::enter()
517 {
518     // parse
519     SInt16 x, y;
520     UInt16 mask;
521     UInt32 seqNum;
522     ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask);
523     LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
524 
525     // discard old compressed mouse motion, if any
526     m_compressMouse         = false;
527     m_compressMouseRelative = false;
528     m_dxMouse               = 0;
529     m_dyMouse               = 0;
530     m_seqNum                = seqNum;
531 
532     // forward
533     m_client->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
534 }
535 
536 void
leave()537 ServerProxy::leave()
538 {
539     // parse
540     LOG((CLOG_DEBUG1 "recv leave"));
541 
542     // send last mouse motion
543     flushCompressedMouse();
544 
545     // forward
546     m_client->leave();
547 }
548 
549 void
setClipboard()550 ServerProxy::setClipboard()
551 {
552     // parse
553     static std::string dataCached;
554     ClipboardID id;
555     UInt32 seq;
556 
557     int r = ClipboardChunk::assemble(m_stream, dataCached, id, seq);
558 
559     if (r == kStart) {
560         size_t size = ClipboardChunk::getExpectedSize();
561         LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size));
562     }
563     else if (r == kFinish) {
564         LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size()));
565 
566         // forward
567         Clipboard clipboard;
568         clipboard.unmarshall(dataCached, 0);
569         m_client->setClipboard(id, &clipboard);
570 
571         LOG((CLOG_INFO "clipboard was updated"));
572     }
573 }
574 
575 void
grabClipboard()576 ServerProxy::grabClipboard()
577 {
578     // parse
579     ClipboardID id;
580     UInt32 seqNum;
581     ProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum);
582     LOG((CLOG_DEBUG "recv grab clipboard %d", id));
583 
584     // validate
585     if (id >= kClipboardEnd) {
586         return;
587     }
588 
589     // forward
590     m_client->grabClipboard(id);
591 }
592 
593 void
keyDown()594 ServerProxy::keyDown()
595 {
596     // get mouse up to date
597     flushCompressedMouse();
598 
599     // parse
600     UInt16 id, mask, button;
601     ProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button);
602     LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button));
603 
604     // translate
605     KeyID id2             = translateKey(static_cast<KeyID>(id));
606     KeyModifierMask mask2 = translateModifierMask(
607                                 static_cast<KeyModifierMask>(mask));
608     if (id2   != static_cast<KeyID>(id) ||
609         mask2 != static_cast<KeyModifierMask>(mask))
610         LOG((CLOG_DEBUG1 "key down translated to id=0x%08x, mask=0x%04x", id2, mask2));
611 
612     // forward
613     m_client->keyDown(id2, mask2, button);
614 }
615 
616 void
keyRepeat()617 ServerProxy::keyRepeat()
618 {
619     // get mouse up to date
620     flushCompressedMouse();
621 
622     // parse
623     UInt16 id, mask, count, button;
624     ProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4,
625                                 &id, &mask, &count, &button);
626     LOG((CLOG_DEBUG1 "recv key repeat id=0x%08x, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button));
627 
628     // translate
629     KeyID id2             = translateKey(static_cast<KeyID>(id));
630     KeyModifierMask mask2 = translateModifierMask(
631                                 static_cast<KeyModifierMask>(mask));
632     if (id2   != static_cast<KeyID>(id) ||
633         mask2 != static_cast<KeyModifierMask>(mask))
634         LOG((CLOG_DEBUG1 "key repeat translated to id=0x%08x, mask=0x%04x", id2, mask2));
635 
636     // forward
637     m_client->keyRepeat(id2, mask2, count, button);
638 }
639 
640 void
keyUp()641 ServerProxy::keyUp()
642 {
643     // get mouse up to date
644     flushCompressedMouse();
645 
646     // parse
647     UInt16 id, mask, button;
648     ProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button);
649     LOG((CLOG_DEBUG1 "recv key up id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button));
650 
651     // translate
652     KeyID id2             = translateKey(static_cast<KeyID>(id));
653     KeyModifierMask mask2 = translateModifierMask(
654                                 static_cast<KeyModifierMask>(mask));
655     if (id2   != static_cast<KeyID>(id) ||
656         mask2 != static_cast<KeyModifierMask>(mask))
657         LOG((CLOG_DEBUG1 "key up translated to id=0x%08x, mask=0x%04x", id2, mask2));
658 
659     // forward
660     m_client->keyUp(id2, mask2, button);
661 }
662 
663 void
mouseDown()664 ServerProxy::mouseDown()
665 {
666     // get mouse up to date
667     flushCompressedMouse();
668 
669     // parse
670     SInt8 id;
671     ProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id);
672     LOG((CLOG_DEBUG1 "recv mouse down id=%d", id));
673 
674     // forward
675     m_client->mouseDown(static_cast<ButtonID>(id));
676 }
677 
678 void
mouseUp()679 ServerProxy::mouseUp()
680 {
681     // get mouse up to date
682     flushCompressedMouse();
683 
684     // parse
685     SInt8 id;
686     ProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id);
687     LOG((CLOG_DEBUG1 "recv mouse up id=%d", id));
688 
689     // forward
690     m_client->mouseUp(static_cast<ButtonID>(id));
691 }
692 
693 void
mouseMove()694 ServerProxy::mouseMove()
695 {
696     // parse
697     bool ignore;
698     SInt16 x, y;
699     ProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y);
700 
701     // note if we should ignore the move
702     ignore = m_ignoreMouse;
703 
704     // compress mouse motion events if more input follows
705     if (!ignore && !m_compressMouse && m_stream->isReady()) {
706         m_compressMouse = true;
707     }
708 
709     // if compressing then ignore the motion but record it
710     if (m_compressMouse) {
711         m_compressMouseRelative = false;
712         ignore    = true;
713         m_xMouse  = x;
714         m_yMouse  = y;
715         m_dxMouse = 0;
716         m_dyMouse = 0;
717     }
718     LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
719 
720     // forward
721     if (!ignore) {
722         m_client->mouseMove(x, y);
723     }
724 }
725 
726 void
mouseRelativeMove()727 ServerProxy::mouseRelativeMove()
728 {
729     // parse
730     bool ignore;
731     SInt16 dx, dy;
732     ProtocolUtil::readf(m_stream, kMsgDMouseRelMove + 4, &dx, &dy);
733 
734     // note if we should ignore the move
735     ignore = m_ignoreMouse;
736 
737     // compress mouse motion events if more input follows
738     if (!ignore && !m_compressMouseRelative && m_stream->isReady()) {
739         m_compressMouseRelative = true;
740     }
741 
742     // if compressing then ignore the motion but record it
743     if (m_compressMouseRelative) {
744         ignore     = true;
745         m_dxMouse += dx;
746         m_dyMouse += dy;
747     }
748     LOG((CLOG_DEBUG2 "recv mouse relative move %d,%d", dx, dy));
749 
750     // forward
751     if (!ignore) {
752         m_client->mouseRelativeMove(dx, dy);
753     }
754 }
755 
756 void
mouseWheel()757 ServerProxy::mouseWheel()
758 {
759     // get mouse up to date
760     flushCompressedMouse();
761 
762     // parse
763     SInt16 xDelta, yDelta;
764     ProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &xDelta, &yDelta);
765     LOG((CLOG_DEBUG2 "recv mouse wheel %+d,%+d", xDelta, yDelta));
766 
767     // forward
768     m_client->mouseWheel(xDelta, yDelta);
769 }
770 
771 void
screensaver()772 ServerProxy::screensaver()
773 {
774     // parse
775     SInt8 on;
776     ProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on);
777     LOG((CLOG_DEBUG1 "recv screen saver on=%d", on));
778 
779     // forward
780     m_client->screensaver(on != 0);
781 }
782 
783 void
resetOptions()784 ServerProxy::resetOptions()
785 {
786     // parse
787     LOG((CLOG_DEBUG1 "recv reset options"));
788 
789     // forward
790     m_client->resetOptions();
791 
792     // reset keep alive
793     setKeepAliveRate(kKeepAliveRate);
794 
795     // reset modifier translation table
796     for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) {
797         m_modifierTranslationTable[id] = id;
798     }
799 }
800 
801 void
setOptions()802 ServerProxy::setOptions()
803 {
804     // parse
805     OptionsList options;
806     ProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options);
807     LOG((CLOG_DEBUG1 "recv set options size=%d", options.size()));
808 
809     // forward
810     m_client->setOptions(options);
811 
812     // update modifier table
813     for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) {
814         KeyModifierID id = kKeyModifierIDNull;
815         if (options[i] == kOptionModifierMapForShift) {
816             id = kKeyModifierIDShift;
817         }
818         else if (options[i] == kOptionModifierMapForControl) {
819             id = kKeyModifierIDControl;
820         }
821         else if (options[i] == kOptionModifierMapForAlt) {
822             id = kKeyModifierIDAlt;
823         }
824         else if (options[i] == kOptionModifierMapForAltGr) {
825             id = kKeyModifierIDAltGr;
826         }
827         else if (options[i] == kOptionModifierMapForMeta) {
828             id = kKeyModifierIDMeta;
829         }
830         else if (options[i] == kOptionModifierMapForSuper) {
831             id = kKeyModifierIDSuper;
832         }
833         else if (options[i] == kOptionHeartbeat) {
834             // update keep alive
835             setKeepAliveRate(1.0e-3 * static_cast<double>(options[i + 1]));
836         }
837 
838         if (id != kKeyModifierIDNull) {
839             m_modifierTranslationTable[id] =
840                 static_cast<KeyModifierID>(options[i + 1]);
841             LOG((CLOG_DEBUG1 "modifier %d mapped to %d", id, m_modifierTranslationTable[id]));
842         }
843     }
844 }
845 
846 void
queryInfo()847 ServerProxy::queryInfo()
848 {
849     ClientInfo info;
850     m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
851     m_client->getCursorPos(info.m_mx, info.m_my);
852     sendInfo(info);
853 }
854 
855 void
infoAcknowledgment()856 ServerProxy::infoAcknowledgment()
857 {
858     LOG((CLOG_DEBUG1 "recv info acknowledgment"));
859     m_ignoreMouse = false;
860 }
861 
862 void
fileChunkReceived()863 ServerProxy::fileChunkReceived()
864 {
865     int result = FileChunk::assemble(
866                     m_stream,
867                     m_client->getReceivedFileData(),
868                     m_client->getExpectedFileSize());
869 
870     if (result == kFinish) {
871         m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), m_client));
872     }
873     else if (result == kStart) {
874         if (m_client->getDragFileList().size() > 0) {
875             std::string filename = m_client->getDragFileList().at(0).getFilename();
876             LOG((CLOG_DEBUG "start receiving %s", filename.c_str()));
877         }
878     }
879 }
880 
881 void
dragInfoReceived()882 ServerProxy::dragInfoReceived()
883 {
884     // parse
885     UInt32 fileNum = 0;
886     std::string content;
887     ProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content);
888 
889     m_client->dragInfoReceived(fileNum, content);
890 }
891 
892 void
handleClipboardSendingEvent(const Event & event,void *)893 ServerProxy::handleClipboardSendingEvent(const Event& event, void*)
894 {
895     ClipboardChunk::send(m_stream, event.getData());
896 }
897 
898 void
fileChunkSending(UInt8 mark,char * data,size_t dataSize)899 ServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
900 {
901     FileChunk::send(m_stream, mark, data, dataSize);
902 }
903 
904 void
sendDragInfo(UInt32 fileCount,const char * info,size_t size)905 ServerProxy::sendDragInfo(UInt32 fileCount, const char* info, size_t size)
906 {
907     std::string data(info, size);
908     ProtocolUtil::writef(m_stream, kMsgDDragInfo, fileCount, &data);
909 }
910