blob: e7bc09f0f8ef8d76c09eae926b9ee0203b7b7991 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <rfb/VNCSConnectionST.h>
20#include <rfb/LogWriter.h>
21#include <rfb/secTypes.h>
22#include <rfb/ServerCore.h>
23#include <rfb/ComparingUpdateTracker.h>
24#define XK_MISCELLANY
25#define XK_XKB_KEYS
26#include <rfb/keysymdef.h>
27
28using namespace rfb;
29
30static LogWriter vlog("VNCSConnST");
31
32VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
33 bool reverse)
34 : sock(s), reverseConnection(reverse), server(server_),
35 image_getter(server->useEconomicTranslate),
36 drawRenderedCursor(false), removeRenderedCursor(false),
Oleg Sheikin4b0304f2005-12-09 10:59:12 +000037 pointerEventTime(0), accessRights(AccessDefault),
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +000038 startTime(time(0)), m_pFileTransfer(0)
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000039{
40 setStreams(&sock->inStream(), &sock->outStream());
41 peerEndpoint.buf = sock->getPeerEndpoint();
42 VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
43
44 setSocketTimeouts();
45 lastEventTime = time(0);
46
47 // Initialise security
48 CharArray sec_types_str;
49 if (reverseConnection)
50 sec_types_str.buf = rfb::Server::rev_sec_types.getData();
51 else
52 sec_types_str.buf = rfb::Server::sec_types.getData();
53 std::list<int> sec_types = parseSecTypes(sec_types_str.buf);
54 std::list<int>::iterator i;
55 for (i=sec_types.begin(); i!=sec_types.end(); i++) {
56 addSecType(*i);
57 }
58
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +000059 if (server->m_pFTManager != NULL) {
60 SFileTransfer *pFT = server->m_pFTManager->createObject(sock);
61 if (pFT != NULL) {
62 m_pFileTransfer = pFT;
63 }
64 }
65
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000066 server->clients.push_front(this);
67}
68
69
70VNCSConnectionST::~VNCSConnectionST()
71{
72 // If we reach here then VNCServerST is deleting us!
73 VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
74 peerEndpoint.buf, closeReason.buf);
75
76 // Release any keys the client still had pressed
77 std::set<rdr::U32>::iterator i;
78 for (i=pressedKeys.begin(); i!=pressedKeys.end(); i++)
79 server->desktop->keyEvent(*i, false);
80 if (server->pointerClient == this)
81 server->pointerClient = 0;
82
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +000083 if (m_pFileTransfer)
84 server->m_pFTManager->destroyObject(m_pFileTransfer);
85
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000086 // Remove this client from the server
87 server->clients.remove(this);
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +000088
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000089}
90
91
92// Methods called from VNCServerST
93
94bool VNCSConnectionST::init()
95{
96 try {
97 initialiseProtocol();
98 } catch (rdr::Exception& e) {
99 close(e.str());
100 return false;
101 }
102 return true;
103}
104
105void VNCSConnectionST::close(const char* reason)
106{
107 // Log the reason for the close
108 if (!closeReason.buf)
109 closeReason.buf = strDup(reason);
110 else
111 vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
112
Peter Åstrand43aa1a12005-02-21 09:58:31 +0000113 if (authenticated()) {
114 server->lastDisconnectTime = time(0);
115 }
116
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000117 // Just shutdown the socket. This will cause processMessages to
118 // eventually fail, causing us and our socket to be deleted.
119 sock->shutdown();
120 setState(RFBSTATE_CLOSING);
121}
122
123
124bool VNCSConnectionST::processMessages()
125{
126 if (state() == RFBSTATE_CLOSING) return false;
127 try {
128 // - Now set appropriate socket timeouts and process data
129 setSocketTimeouts();
130 bool clientsReadyBefore = server->clientsReadyForUpdate();
131
132 while (getInStream()->checkNoWait(1)) {
133 processMsg();
134 }
135
136 if (!clientsReadyBefore && !requested.is_empty())
137 server->desktop->framebufferUpdateRequest();
138
139 return true;
140
141 } catch (rdr::EndOfStream&) {
142 close("Clean disconnection");
143 } catch (rdr::Exception &e) {
144 close(e.str());
145 }
146 return false;
147}
148
149void VNCSConnectionST::writeFramebufferUpdateOrClose()
150{
151 try {
152 writeFramebufferUpdate();
153 } catch(rdr::Exception &e) {
154 close(e.str());
155 }
156}
157
158void VNCSConnectionST::pixelBufferChange()
159{
160 try {
161 if (!authenticated()) return;
162 if (cp.width && cp.height && (server->pb->width() != cp.width ||
163 server->pb->height() != cp.height))
164 {
165 // We need to clip the next update to the new size, but also add any
166 // extra bits if it's bigger. If we wanted to do this exactly, something
167 // like the code below would do it, but at the moment we just update the
168 // entire new size. However, we do need to clip the renderedCursorRect
169 // because that might be added to updates in writeFramebufferUpdate().
170
171 //updates.intersect(server->pb->getRect());
172 //
173 //if (server->pb->width() > cp.width)
174 // updates.add_changed(Rect(cp.width, 0, server->pb->width(),
175 // server->pb->height()));
176 //if (server->pb->height() > cp.height)
177 // updates.add_changed(Rect(0, cp.height, cp.width,
178 // server->pb->height()));
179
180 renderedCursorRect = renderedCursorRect.intersect(server->pb->getRect());
181
182 cp.width = server->pb->width();
183 cp.height = server->pb->height();
184 if (!writer()->writeSetDesktopSize()) {
185 close("Client does not support desktop resize");
186 return;
187 }
188 }
189 // Just update the whole screen at the moment because we're too lazy to
190 // work out what's actually changed.
191 updates.clear();
192 updates.add_changed(server->pb->getRect());
193 vlog.debug("pixel buffer changed - re-initialising image getter");
194 image_getter.init(server->pb, cp.pf(), writer());
195 if (writer()->needFakeUpdate())
196 writeFramebufferUpdate();
197 } catch(rdr::Exception &e) {
198 close(e.str());
199 }
200}
201
202void VNCSConnectionST::setColourMapEntriesOrClose(int firstColour,int nColours)
203{
204 try {
205 setColourMapEntries(firstColour, nColours);
206 } catch(rdr::Exception& e) {
207 close(e.str());
208 }
209}
210
211void VNCSConnectionST::bell()
212{
213 try {
214 if (state() == RFBSTATE_NORMAL) writer()->writeBell();
215 } catch(rdr::Exception& e) {
216 close(e.str());
217 }
218}
219
220void VNCSConnectionST::serverCutText(const char *str, int len)
221{
222 try {
223 if (!(accessRights & AccessCutText)) return;
224 if (!rfb::Server::sendCutText) return;
225 if (state() == RFBSTATE_NORMAL)
226 writer()->writeServerCutText(str, len);
227 } catch(rdr::Exception& e) {
228 close(e.str());
229 }
230}
231
232void VNCSConnectionST::setCursorOrClose()
233{
234 try {
235 setCursor();
236 } catch(rdr::Exception& e) {
237 close(e.str());
238 }
239}
240
241
242int VNCSConnectionST::checkIdleTimeout()
243{
244 int idleTimeout = rfb::Server::idleTimeout;
245 if (idleTimeout == 0) return 0;
246 if (state() != RFBSTATE_NORMAL && idleTimeout < 15)
247 idleTimeout = 15; // minimum of 15 seconds while authenticating
248 time_t now = time(0);
249 if (now < lastEventTime) {
250 // Someone must have set the time backwards. Set lastEventTime so that the
251 // idleTimeout will count from now.
252 vlog.info("Time has gone backwards - resetting idle timeout");
253 lastEventTime = now;
254 }
255 int timeLeft = lastEventTime + idleTimeout - now;
256 if (timeLeft < -60) {
257 // Our callback is over a minute late - someone must have set the time
258 // forwards. Set lastEventTime so that the idleTimeout will count from
259 // now.
260 vlog.info("Time has gone forwards - resetting idle timeout");
261 lastEventTime = now;
262 return idleTimeout;
263 }
264 if (timeLeft <= 0) {
265 close("Idle timeout");
266 return 0;
267 }
268 return timeLeft * 1000;
269}
270
271// renderedCursorChange() is called whenever the server-side rendered cursor
272// changes shape or position. It ensures that the next update will clean up
273// the old rendered cursor and if necessary draw the new rendered cursor.
274
275void VNCSConnectionST::renderedCursorChange()
276{
277 if (state() != RFBSTATE_NORMAL) return;
278 removeRenderedCursor = true;
279 if (needRenderedCursor())
280 drawRenderedCursor = true;
281}
282
283// needRenderedCursor() returns true if this client needs the server-side
284// rendered cursor. This may be because it does not support local cursor or
285// because the current cursor position has not been set by this client.
286// Unfortunately we can't know for sure when the current cursor position has
287// been set by this client. We guess that this is the case when the current
288// cursor position is the same as the last pointer event from this client, or
289// if it is a very short time since this client's last pointer event (up to a
290// second). [ Ideally we should do finer-grained timing here and make the time
291// configurable, but I don't think it's that important. ]
292
293bool VNCSConnectionST::needRenderedCursor()
294{
295 return (state() == RFBSTATE_NORMAL
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000296 && (!cp.supportsLocalCursor && !cp.supportsLocalXCursor
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000297 || (!server->cursorPos.equals(pointerEventPos) &&
298 (time(0) - pointerEventTime) > 0)));
299}
300
301
302void VNCSConnectionST::approveConnectionOrClose(bool accept,
303 const char* reason)
304{
305 try {
306 approveConnection(accept, reason);
307 } catch (rdr::Exception& e) {
308 close(e.str());
309 }
310}
311
312
313
314// -=- Callbacks from SConnection
315
316void VNCSConnectionST::versionReceived() {
317 CharArray address(sock->getPeerAddress());
318 if ((rfb::Server::blacklistLevel == 1) &&
319 server->blHosts->isBlackmarked(address.buf)) {
320 server->connectionsLog.error("blacklisted: %s", address.buf);
321 throwConnFailedException("Too many security failures");
322 }
323}
324
325SSecurity* VNCSConnectionST::getSSecurity(int secType) {
326 if (!server->securityFactory)
327 throw rdr::Exception("no SSecurityFactory registered!");
328 return server->securityFactory->getSSecurity(secType, reverseConnection);
329}
330
331void VNCSConnectionST::authSuccess()
332{
333 lastEventTime = time(0);
334
335 // - Authentication succeeded - clear from blacklist
336 CharArray name; name.buf = sock->getPeerAddress();
337 server->blHosts->clearBlackmark(name.buf);
338
339 server->startDesktop();
340
341 // - Set the connection parameters appropriately
342 cp.width = server->pb->width();
343 cp.height = server->pb->height();
344 cp.setName(server->getName());
345
346 // - Set the default pixel format
347 cp.setPF(server->pb->getPF());
348 char buffer[256];
349 cp.pf().print(buffer, 256);
350 vlog.info("Server default pixel format %s", buffer);
351 image_getter.init(server->pb, cp.pf(), 0);
352
353 // - Mark the entire display as "dirty"
354 updates.add_changed(server->pb->getRect());
Oleg Sheikin4b0304f2005-12-09 10:59:12 +0000355 startTime = time(0);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000356}
357
358void VNCSConnectionST::queryConnection(const char* userName)
359{
360 // - Does the client have the right to bypass the query?
361 if (reverseConnection || !rfb::Server::queryConnect ||
362 (accessRights & AccessNoQuery))
363 {
364 approveConnection(true);
365 return;
366 }
367
368 CharArray reason;
369 VNCServerST::queryResult qr = server->queryConnection(sock, userName,
370 &reason.buf);
371 if (qr == VNCServerST::PENDING) return;
372 approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
373}
374
375void VNCSConnectionST::clientInit(bool shared)
376{
377 lastEventTime = time(0);
378 if (rfb::Server::alwaysShared || reverseConnection) shared = true;
379 if (rfb::Server::neverShared) shared = false;
380 if (!shared) {
381 if (rfb::Server::disconnectClients) {
382 // - Close all the other connected clients
383 vlog.debug("non-shared connection - closing clients");
384 server->closeClients("Non-shared connection requested", getSock());
385 } else {
386 // - Refuse this connection if there are existing clients, in addition to this one
387 if (server->authClientCount() > 1) {
388 close("Server is already in use");
389 return;
390 }
391 }
392 }
393 SConnection::clientInit(shared);
394}
395
396void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
397{
398 SConnection::setPixelFormat(pf);
399 char buffer[256];
400 pf.print(buffer, 256);
401 vlog.info("Client pixel format %s", buffer);
402 image_getter.init(server->pb, pf, writer());
403 setCursor();
404}
405
406void VNCSConnectionST::pointerEvent(int x, int y, int buttonMask)
407{
408 pointerEventTime = lastEventTime = time(0);
Peter Åstrand43aa1a12005-02-21 09:58:31 +0000409 server->lastUserInputTime = lastEventTime;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000410 if (!(accessRights & AccessPtrEvents)) return;
411 if (!rfb::Server::acceptPointerEvents) return;
412 if (!server->pointerClient || server->pointerClient == this) {
413 pointerEventPos = Point(x, y);
414 if (buttonMask)
415 server->pointerClient = this;
416 else
417 server->pointerClient = 0;
418 server->desktop->pointerEvent(pointerEventPos, buttonMask);
419 }
420}
421
422
423class VNCSConnectionSTShiftPresser {
424public:
425 VNCSConnectionSTShiftPresser(SDesktop* desktop_)
426 : desktop(desktop_), pressed(false) {}
427 ~VNCSConnectionSTShiftPresser() {
428 if (pressed) { desktop->keyEvent(XK_Shift_L, false); }
429 }
430 void press() {
431 desktop->keyEvent(XK_Shift_L, true);
432 pressed = true;
433 }
434 SDesktop* desktop;
435 bool pressed;
436};
437
438// keyEvent() - record in the pressedKeys which keys were pressed. Allow
439// multiple down events (for autorepeat), but only allow a single up event.
440void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) {
441 lastEventTime = time(0);
Peter Åstrand43aa1a12005-02-21 09:58:31 +0000442 server->lastUserInputTime = lastEventTime;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000443 if (!(accessRights & AccessKeyEvents)) return;
444 if (!rfb::Server::acceptKeyEvents) return;
445
446 // Turn ISO_Left_Tab into shifted Tab.
447 VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
448 if (key == XK_ISO_Left_Tab) {
449 if (pressedKeys.find(XK_Shift_L) == pressedKeys.end() &&
450 pressedKeys.find(XK_Shift_R) == pressedKeys.end())
451 shiftPresser.press();
452 key = XK_Tab;
453 }
454
455 if (down) {
456 pressedKeys.insert(key);
457 } else {
458 if (!pressedKeys.erase(key)) return;
459 }
460 server->desktop->keyEvent(key, down);
461}
462
463void VNCSConnectionST::clientCutText(const char* str, int len)
464{
465 if (!(accessRights & AccessCutText)) return;
466 if (!rfb::Server::acceptCutText) return;
467 server->desktop->clientCutText(str, len);
468}
469
470void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
471{
472 if (!(accessRights & AccessView)) return;
473
474 SConnection::framebufferUpdateRequest(r, incremental);
475
476 Region reqRgn(r);
477 requested.assign_union(reqRgn);
478
479 if (!incremental) {
480 // Non-incremental update - treat as if area requested has changed
481 updates.add_changed(reqRgn);
482 server->comparer->add_changed(reqRgn);
483 }
484
485 writeFramebufferUpdate();
486}
487
488void VNCSConnectionST::setInitialColourMap()
489{
490 setColourMapEntries(0, 0);
491}
492
493// supportsLocalCursor() is called whenever the status of
494// cp.supportsLocalCursor has changed. If the client does now support local
495// cursor, we make sure that the old server-side rendered cursor is cleaned up
496// and the cursor is sent to the client.
497
498void VNCSConnectionST::supportsLocalCursor()
499{
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000500 if (cp.supportsLocalCursor || cp.supportsLocalXCursor) {
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000501 removeRenderedCursor = true;
502 drawRenderedCursor = false;
503 setCursor();
504 }
505}
506
507void VNCSConnectionST::writeSetCursorCallback()
508{
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000509 if (cp.supportsLocalXCursor) {
510 Pixel pix0, pix1;
511 rdr::U8Array bitmap(server->cursor.getBitmap(&pix0, &pix1));
512 if (bitmap.buf) {
513 // The client supports XCursor and the cursor only has two
514 // colors. Use the XCursor encoding.
515 writer()->writeSetXCursor(server->cursor.width(),
516 server->cursor.height(),
517 server->cursor.hotspot.x,
518 server->cursor.hotspot.y,
519 bitmap.buf, server->cursor.mask.buf);
520 return;
521 } else {
522 // More than two colors
523 if (!cp.supportsLocalCursor) {
524 // FIXME: We could reduce to two colors.
525 vlog.info("Unable to send multicolor cursor: RichCursor not supported by client");
526 return;
527 }
528 }
529 }
530
531 // Use RichCursor
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000532 rdr::U8* transData = writer()->getImageBuf(server->cursor.area());
533 image_getter.translatePixels(server->cursor.data, transData,
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000534 server->cursor.area());
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000535 writer()->writeSetCursor(server->cursor.width(),
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000536 server->cursor.height(),
537 server->cursor.hotspot.x,
538 server->cursor.hotspot.y,
539 transData, server->cursor.mask.buf);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000540}
541
542
543void VNCSConnectionST::writeFramebufferUpdate()
544{
545 if (state() != RFBSTATE_NORMAL || requested.is_empty()) return;
546
547 server->checkUpdate();
548
549 // If the previous position of the rendered cursor overlaps the source of the
550 // copy, then when the copy happens the corresponding rectangle in the
551 // destination will be wrong, so add it to the changed region.
552
553 if (!updates.get_copied().is_empty() && !renderedCursorRect.is_empty()) {
554 Rect bogusCopiedCursor = (renderedCursorRect.translate(updates.get_delta())
555 .intersect(server->pb->getRect()));
556 if (!updates.get_copied().intersect(bogusCopiedCursor).is_empty()) {
557 updates.add_changed(bogusCopiedCursor);
558 }
559 }
560
561 // If we need to remove the old rendered cursor, just add the rectangle to
562 // the changed region.
563
564 if (removeRenderedCursor) {
565 updates.add_changed(renderedCursorRect);
566 renderedCursorRect.clear();
567 removeRenderedCursor = false;
568 }
569
570 // Return if there is nothing to send the client.
571
572 if (updates.is_empty() && !writer()->needFakeUpdate() && !drawRenderedCursor)
573 return;
574
575 // If the client needs a server-side rendered cursor, work out the cursor
576 // rectangle. If it's empty then don't bother drawing it, but if it overlaps
577 // with the update region, we need to draw the rendered cursor regardless of
578 // whether it has changed.
579
580 if (needRenderedCursor()) {
581 renderedCursorRect
582 = (server->renderedCursor.getRect(server->renderedCursorTL)
583 .intersect(requested.get_bounding_rect()));
584
585 if (renderedCursorRect.is_empty()) {
586 drawRenderedCursor = false;
587 } else if (!updates.get_changed().union_(updates.get_copied())
588 .intersect(renderedCursorRect).is_empty()) {
589 drawRenderedCursor = true;
590 }
591
592 // We could remove the new cursor rect from updates here. It's not clear
593 // whether this is worth it. If we do remove it, then we won't draw over
594 // the same bit of screen twice, but we have the overhead of a more complex
595 // region.
596
597 //if (drawRenderedCursor)
598 // updates.subtract(renderedCursorRect);
599 }
600
601 UpdateInfo update;
602 updates.enable_copyrect(cp.useCopyRect);
603 updates.get_update(&update, requested);
604 if (!update.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) {
Peter Åstrand016dc192005-02-10 16:41:06 +0000605 // Compute the number of rectangles. Tight encoder makes the things more
606 // complicated as compared to the original RealVNC.
607 writer()->setupCurrentEncoder();
608 int nRects = update.copied.numRects() + (drawRenderedCursor ? 1 : 0);
609 std::vector<Rect> rects;
610 std::vector<Rect>::const_iterator i;
611 update.changed.get_rects(&rects);
612 for (i = rects.begin(); i != rects.end(); i++) {
613 if (i->width() && i->height())
614 nRects += writer()->getNumRects(*i);
615 }
616
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000617 writer()->writeFramebufferUpdateStart(nRects);
618 Region updatedRegion;
619 writer()->writeRects(update, &image_getter, &updatedRegion);
620 updates.subtract(updatedRegion);
621 if (drawRenderedCursor)
622 writeRenderedCursorRect();
623 writer()->writeFramebufferUpdateEnd();
624 requested.clear();
625 }
626}
627
628
629// writeRenderedCursorRect() writes a single rectangle drawing the rendered
630// cursor on the client.
631
632void VNCSConnectionST::writeRenderedCursorRect()
633{
634 image_getter.setPixelBuffer(&server->renderedCursor);
635 image_getter.setOffset(server->renderedCursorTL);
636
637 Rect actual;
638 writer()->writeRect(renderedCursorRect, &image_getter, &actual);
639
640 image_getter.setPixelBuffer(server->pb);
641 image_getter.setOffset(Point(0,0));
642
643 drawRenderedCursor = false;
644}
645
646void VNCSConnectionST::setColourMapEntries(int firstColour, int nColours)
647{
648 if (!readyForSetColourMapEntries) return;
649 if (server->pb->getPF().trueColour) return;
650
651 image_getter.setColourMapEntries(firstColour, nColours, writer());
652
653 if (cp.pf().trueColour) {
654 updates.add_changed(server->pb->getRect());
655 }
656}
657
658
659// setCursor() is called whenever the cursor has changed shape or pixel format.
660// If the client supports local cursor then it will arrange for the cursor to
661// be sent to the client.
662
663void VNCSConnectionST::setCursor()
664{
665 if (state() != RFBSTATE_NORMAL || !cp.supportsLocalCursor) return;
666 writer()->cursorChange(this);
667 if (writer()->needFakeUpdate())
668 writeFramebufferUpdate();
669}
670
671void VNCSConnectionST::setSocketTimeouts()
672{
673 int timeoutms = rfb::Server::clientWaitTimeMillis;
674 if (timeoutms == 0 || timeoutms > rfb::Server::idleTimeout * 1000) {
675 timeoutms = rfb::Server::idleTimeout * 1000;
676 if (timeoutms == 0)
677 timeoutms = -1;
678 }
679 sock->inStream().setTimeout(timeoutms);
680 sock->outStream().setTimeout(timeoutms);
681}
Oleg Sheikinff43bfd2005-12-07 08:02:52 +0000682
683char* VNCSConnectionST::getStartTime()
684{
685 char* result = ctime(&startTime);
686 result[24] = '\0';
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +0000687 return result;
Oleg Sheikinff43bfd2005-12-07 08:02:52 +0000688}
Oleg Sheikin4b0304f2005-12-09 10:59:12 +0000689
690void VNCSConnectionST::setStatus(int status)
691{
692 switch (status) {
693 case 0:
694 accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
695 break;
696 case 1:
697 accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents) | AccessView;
698 break;
699 case 2:
700 accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents | AccessView);
701 break;
702 }
Oleg Sheikind87a7a72006-01-12 15:27:04 +0000703 framebufferUpdateRequest(server->pb->getRect(), false);
Oleg Sheikin4b0304f2005-12-09 10:59:12 +0000704}
705int VNCSConnectionST::getStatus()
706{
707 if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
708 return 0;
709 if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
710 return 1;
711 if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
712 return 2;
713 return 4;
Dennis Syrovatskyea354642005-12-18 13:10:26 +0000714}
715
716bool VNCSConnectionST::processFTMsg(int type)
717{
Dennis Syrovatsky265d3c82006-04-17 12:36:11 +0000718 if (m_pFileTransfer != NULL)
719 return m_pFileTransfer->processMessages(type);
720 else
721 return false;
Constantin Kaplinsky4cea5e72006-01-13 10:52:39 +0000722}