You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VNCSConnectionST.cxx 21KB

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