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