Merge branch 'vncserver' of https://github.com/CendioOssman/tigervnc
diff --git a/common/network/Socket.h b/common/network/Socket.h
index bfda8a5..c7d06c3 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -151,8 +151,6 @@
     //   there is no timeout and checkTimeouts() should be called the next time
     //   an event occurs.
     virtual int checkTimeouts() = 0;
-
-    virtual bool getDisable() {return false;};
   };
 
 }
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index efc26ac..a79abee 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -260,13 +260,14 @@
   throw ConnFailedException(str);
 }
 
-void SConnection::writeConnFailedFromScratch(const char* msg,
-                                             rdr::OutStream* os)
+void SConnection::setAccessRights(AccessRights ar)
 {
-  os->writeBytes("RFB 003.003\n", 12);
-  os->writeU32(0);
-  os->writeString(msg);
-  os->flush();
+  accessRights = ar;
+}
+
+bool SConnection::accessCheck(AccessRights ar) const
+{
+  return (accessRights & ar) == ar;
 }
 
 void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
@@ -342,6 +343,11 @@
   state_ = RFBSTATE_NORMAL;
 }
 
+void SConnection::close(const char* reason)
+{
+  state_ = RFBSTATE_CLOSING;
+}
+
 void SConnection::setPixelFormat(const PixelFormat& pf)
 {
   SMsgHandler::setPixelFormat(pf);
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 47092e3..2630240 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -69,6 +69,13 @@
     void approveConnection(bool accept, const char* reason=0);
 
 
+    // Methods to terminate the connection
+
+    // close() shuts down the connection to the client and awaits
+    // cleanup of the SConnection object by the server
+    virtual void close(const char* reason);
+
+
     // Overridden from SMsgHandler
 
     virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
@@ -118,8 +125,10 @@
     virtual void enableContinuousUpdates(bool enable,
                                          int x, int y, int w, int h);
 
+    // Other methods
+
     // setAccessRights() allows a security package to limit the access rights
-    // of a VNCSConnectionST to the server.  How the access rights are treated
+    // of a SConnection to the server.  How the access rights are treated
     // is up to the derived class.
 
     typedef rdr::U16 AccessRights;
@@ -132,27 +141,14 @@
     static const AccessRights AccessDefault;        // The default rights, INCLUDING FUTURE ONES
     static const AccessRights AccessNoQuery;        // Connect without local user accepting
     static const AccessRights AccessFull;           // All of the available AND FUTURE rights
-    virtual void setAccessRights(AccessRights ar) = 0;
-
-    // Other methods
+    virtual void setAccessRights(AccessRights ar);
+    virtual bool accessCheck(AccessRights ar) const;
 
     // authenticated() returns true if the client has authenticated
     // successfully.
     bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
                                    state_ == RFBSTATE_NORMAL); }
 
-    // throwConnFailedException() prints a message to the log, sends a conn
-    // failed message to the client (if possible) and throws a
-    // ConnFailedException.
-    void throwConnFailedException(const char* format, ...) __printf_attr(2, 3);
-
-    // writeConnFailedFromScratch() sends a conn failed message to an OutStream
-    // without the need to negotiate the protocol version first.  It actually
-    // does this by assuming that the client will understand version 3.3 of the
-    // protocol.
-    static void writeConnFailedFromScratch(const char* msg,
-                                           rdr::OutStream* os);
-
     SMsgReader* reader() { return reader_; }
     SMsgWriter* writer() { return writer_; }
 
@@ -176,6 +172,11 @@
     rdr::S32 getPreferredEncoding() { return preferredEncoding; }
 
   protected:
+    // throwConnFailedException() prints a message to the log, sends a conn
+    // failed message to the client (if possible) and throws a
+    // ConnFailedException.
+    void throwConnFailedException(const char* format, ...) __printf_attr(2, 3);
+
     void setState(stateEnum s) { state_ = s; }
 
     void setReader(SMsgReader *r) { reader_ = r; }
@@ -201,6 +202,7 @@
     SSecurity* ssecurity;
     stateEnum state_;
     rdr::S32 preferredEncoding;
+    AccessRights accessRights;
   };
 }
 #endif
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index 717ddbc..6118246 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -44,6 +44,8 @@
 #include <rfb/screenTypes.h>
 #include <rfb/util.h>
 
+namespace network { class Socket; }
+
 namespace rfb {
 
   class VNCServer;
@@ -56,14 +58,22 @@
     // set via the VNCServer's setPixelBuffer() method by the time this call
     // returns.
 
-    virtual void start(VNCServer* __unused_attr vs) {}
+    virtual void start(VNCServer* vs) = 0;
 
     // stop() is called by the server when there are no longer any
     // authenticated clients, and therefore the desktop can cease any
     // expensive tasks.  No further calls to the VNCServer passed to start()
     // can be made once stop has returned.
 
-    virtual void stop() {}
+    virtual void stop() = 0;
+
+    // queryConnection() is called when a connection has been
+    // successfully authenticated.  The sock and userName arguments
+    // identify the socket and the name of the authenticated user, if
+    // any. At some point later VNCServer::approveConnection() should
+    // be called to either accept or reject the client.
+    virtual void queryConnection(network::Socket* sock,
+                                 const char* userName) = 0;
 
     // setScreenLayout() requests to reconfigure the framebuffer and/or
     // the layout of screens.
@@ -112,6 +122,10 @@
       server->setPixelBuffer(0);
       server = 0;
     }
+    virtual void queryConnection(network::Socket* sock,
+                                 const char* userName) {
+      server->approveConnection(sock, true, NULL);
+    }
 
   protected:
     VNCServer* server;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index f1591f4..7b261e7 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -52,27 +52,22 @@
     losslessTimer(this), server(server_), updates(false),
     updateRenderedCursor(false), removeRenderedCursor(false),
     continuousUpdates(false), encodeManager(this), pointerEventTime(0),
-    clientHasCursor(false),
-    accessRights(AccessDefault), startTime(time(0))
+    clientHasCursor(false)
 {
   setStreams(&sock->inStream(), &sock->outStream());
   peerEndpoint.buf = sock->getPeerEndpoint();
-  VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
 
   // Configure the socket
   setSocketTimeouts();
   lastEventTime = time(0);
-
-  server->clients.push_front(this);
 }
 
 
 VNCSConnectionST::~VNCSConnectionST()
 {
   // If we reach here then VNCServerST is deleting us!
-  VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
-                                    peerEndpoint.buf,
-                                    (closeReason.buf) ? closeReason.buf : "");
+  if (closeReason.buf)
+    vlog.info("closing %s: %s", peerEndpoint.buf, closeReason.buf);
 
   // Release any keys the client still had pressed
   while (!pressedKeys.empty()) {
@@ -84,19 +79,42 @@
 
     vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
                keysym, keycode);
-    server->desktop->keyEvent(keysym, keycode, false);
+    server->keyEvent(keysym, keycode, false);
   }
 
-  if (server->pointerClient == this)
-    server->pointerClient = 0;
-
-  // Remove this client from the server
-  server->clients.remove(this);
-
   delete [] fenceData;
 }
 
 
+// SConnection methods
+
+bool VNCSConnectionST::accessCheck(AccessRights ar) const
+{
+  // Reverse connections are user initiated, so they are implicitly
+  // allowed to bypass the query
+  if (reverseConnection)
+    ar &= ~AccessNoQuery;
+
+  return SConnection::accessCheck(ar);
+}
+
+void VNCSConnectionST::close(const char* reason)
+{
+  // Log the reason for the close
+  if (!closeReason.buf)
+    closeReason.buf = strDup(reason);
+  else
+    vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
+
+  // Just shutdown the socket and mark our state as closing.  Eventually the
+  // calling code will call VNCServerST's removeSocket() method causing us to
+  // be deleted.
+  sock->shutdown();
+
+  SConnection::close(reason);
+}
+
+
 // Methods called from VNCServerST
 
 bool VNCSConnectionST::init()
@@ -110,25 +128,6 @@
   return true;
 }
 
-void VNCSConnectionST::close(const char* reason)
-{
-  // Log the reason for the close
-  if (!closeReason.buf)
-    closeReason.buf = strDup(reason);
-  else
-    vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
-
-  if (authenticated()) {
-      server->lastDisconnectTime = time(0);
-  }
-
-  // Just shutdown the socket and mark our state as closing.  Eventually the
-  // calling code will call VNCServerST's removeSocket() method causing us to
-  // be deleted.
-  sock->shutdown();
-  setState(RFBSTATE_CLOSING);
-}
-
 
 void VNCSConnectionST::processMessages()
 {
@@ -192,8 +191,9 @@
 {
   try {
     if (!authenticated()) return;
-    if (cp.width && cp.height && (server->pb->width() != cp.width ||
-                                  server->pb->height() != cp.height))
+    if (cp.width && cp.height &&
+        (server->getPixelBuffer()->width() != cp.width ||
+         server->getPixelBuffer()->height() != cp.height))
     {
       // We need to clip the next update to the new size, but also add any
       // extra bits if it's bigger.  If we wanted to do this exactly, something
@@ -210,11 +210,11 @@
       //  updates.add_changed(Rect(0, cp.height, cp.width,
       //                           server->pb->height()));
 
-      damagedCursorRegion.assign_intersect(server->pb->getRect());
+      damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
 
-      cp.width = server->pb->width();
-      cp.height = server->pb->height();
-      cp.screenLayout = server->screenLayout;
+      cp.width = server->getPixelBuffer()->width();
+      cp.height = server->getPixelBuffer()->height();
+      cp.screenLayout = server->getScreenLayout();
       if (state() == RFBSTATE_NORMAL) {
         // We should only send EDS to client asking for both
         if (!writer()->writeExtendedDesktopSize()) {
@@ -226,12 +226,12 @@
       }
 
       // Drop any lossy tracking that is now outside the framebuffer
-      encodeManager.pruneLosslessRefresh(Region(server->pb->getRect()));
+      encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect()));
     }
     // Just update the whole screen at the moment because we're too lazy to
     // work out what's actually changed.
     updates.clear();
-    updates.add_changed(server->pb->getRect());
+    updates.add_changed(server->getPixelBuffer()->getRect());
     writeFramebufferUpdate();
   } catch(rdr::Exception &e) {
     close(e.str());
@@ -269,7 +269,7 @@
 void VNCSConnectionST::serverCutTextOrClose(const char *str, int len)
 {
   try {
-    if (!(accessRights & AccessCutText)) return;
+    if (!accessCheck(AccessCutText)) return;
     if (!rfb::Server::sendCutText) return;
     if (state() == RFBSTATE_NORMAL)
       writer()->writeServerCutText(str, len);
@@ -388,7 +388,7 @@
   if (!cp.supportsLocalCursorWithAlpha &&
       !cp.supportsLocalCursor && !cp.supportsLocalXCursor)
     return true;
-  if (!server->cursorPos.equals(pointerEventPos) &&
+  if (!server->getCursorPos().equals(pointerEventPos) &&
       (time(0) - pointerEventTime) > 0)
     return true;
 
@@ -414,82 +414,36 @@
 {
   lastEventTime = time(0);
 
-  server->startDesktop();
-
   // - Set the connection parameters appropriately
-  cp.width = server->pb->width();
-  cp.height = server->pb->height();
-  cp.screenLayout = server->screenLayout;
+  cp.width = server->getPixelBuffer()->width();
+  cp.height = server->getPixelBuffer()->height();
+  cp.screenLayout = server->getScreenLayout();
   cp.setName(server->getName());
-  cp.setLEDState(server->ledState);
+  cp.setLEDState(server->getLEDState());
   
   // - Set the default pixel format
-  cp.setPF(server->pb->getPF());
+  cp.setPF(server->getPixelBuffer()->getPF());
   char buffer[256];
   cp.pf().print(buffer, 256);
   vlog.info("Server default pixel format %s", buffer);
 
   // - Mark the entire display as "dirty"
-  updates.add_changed(server->pb->getRect());
-  startTime = time(0);
+  updates.add_changed(server->getPixelBuffer()->getRect());
 }
 
 void VNCSConnectionST::queryConnection(const char* userName)
 {
-  // - Authentication succeeded - clear from blacklist
-  CharArray name; name.buf = sock->getPeerAddress();
-  server->blHosts->clearBlackmark(name.buf);
-
-  // - Special case to provide a more useful error message
-  if (rfb::Server::neverShared && !rfb::Server::disconnectClients &&
-    server->authClientCount() > 0) {
-    approveConnection(false, "The server is already in use");
-    return;
-  }
-
-  // - Does the client have the right to bypass the query?
-  if (reverseConnection ||
-      !(rfb::Server::queryConnect || sock->requiresQuery()) ||
-      (accessRights & AccessNoQuery))
-  {
-    approveConnection(true);
-    return;
-  }
-
-  // - Get the server to display an Accept/Reject dialog, if required
-  //   If a dialog is displayed, the result will be PENDING, and the
-  //   server will call approveConnection at a later time
-  CharArray reason;
-  VNCServerST::queryResult qr = server->queryConnection(sock, userName,
-                                                        &reason.buf);
-  if (qr == VNCServerST::PENDING)
-    return;
-
-  // - If server returns ACCEPT/REJECT then pass result to SConnection
-  approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
+  server->queryConnection(this, userName);
 }
 
 void VNCSConnectionST::clientInit(bool shared)
 {
   lastEventTime = time(0);
   if (rfb::Server::alwaysShared || reverseConnection) shared = true;
-  if (!(accessRights & AccessNonShared)) shared = true;
+  if (!accessCheck(AccessNonShared)) shared = true;
   if (rfb::Server::neverShared) shared = false;
-  if (!shared) {
-    if (rfb::Server::disconnectClients && (accessRights & AccessNonShared)) {
-      // - Close all the other connected clients
-      vlog.debug("non-shared connection - closing clients");
-      server->closeClients("Non-shared connection requested", getSock());
-    } else {
-      // - Refuse this connection if there are existing clients, in addition to
-      // this one
-      if (server->authClientCount() > 1) {
-        close("Server is already in use");
-        return;
-      }
-    }
-  }
   SConnection::clientInit(shared);
+  server->clientReady(this, shared);
 }
 
 void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
@@ -504,36 +458,29 @@
 void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
 {
   pointerEventTime = lastEventTime = time(0);
-  server->lastUserInputTime = lastEventTime;
-  if (!(accessRights & AccessPtrEvents)) return;
+  if (!accessCheck(AccessPtrEvents)) return;
   if (!rfb::Server::acceptPointerEvents) return;
-  if (!server->pointerClient || server->pointerClient == this) {
-    pointerEventPos = pos;
-    if (buttonMask)
-      server->pointerClient = this;
-    else
-      server->pointerClient = 0;
-    server->desktop->pointerEvent(pointerEventPos, buttonMask);
-  }
+  pointerEventPos = pos;
+  server->pointerEvent(this, pointerEventPos, buttonMask);
 }
 
 
 class VNCSConnectionSTShiftPresser {
 public:
-  VNCSConnectionSTShiftPresser(SDesktop* desktop_)
-    : desktop(desktop_), pressed(false) {}
+  VNCSConnectionSTShiftPresser(VNCServerST* server_)
+    : server(server_), pressed(false) {}
   ~VNCSConnectionSTShiftPresser() {
     if (pressed) {
       vlog.debug("Releasing fake Shift_L");
-      desktop->keyEvent(XK_Shift_L, 0, false);
+      server->keyEvent(XK_Shift_L, 0, false);
     }
   }
   void press() {
     vlog.debug("Pressing fake Shift_L");
-    desktop->keyEvent(XK_Shift_L, 0, true);
+    server->keyEvent(XK_Shift_L, 0, true);
     pressed = true;
   }
-  SDesktop* desktop;
+  VNCServerST* server;
   bool pressed;
 };
 
@@ -543,8 +490,7 @@
   rdr::U32 lookup;
 
   lastEventTime = time(0);
-  server->lastUserInputTime = lastEventTime;
-  if (!(accessRights & AccessKeyEvents)) return;
+  if (!accessCheck(AccessKeyEvents)) return;
   if (!rfb::Server::acceptKeyEvents) return;
 
   if (down)
@@ -552,18 +498,8 @@
   else
     vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
 
-  // Remap the key if required
-  if (server->keyRemapper) {
-    rdr::U32 newkey;
-    newkey = server->keyRemapper->remapKey(keysym);
-    if (newkey != keysym) {
-      vlog.debug("Key remapped to 0x%x", newkey);
-      keysym = newkey;
-    }
-  }
-
   // Avoid lock keys if we don't know the server state
-  if ((server->ledState == ledUnknown) &&
+  if ((server->getLEDState() == ledUnknown) &&
       ((keysym == XK_Caps_Lock) ||
        (keysym == XK_Num_Lock) ||
        (keysym == XK_Scroll_Lock))) {
@@ -581,7 +517,7 @@
       return;
     }
 
-    if (down && (server->ledState != ledUnknown)) {
+    if (down && (server->getLEDState() != ledUnknown)) {
       // CapsLock synchronisation heuristic
       // (this assumes standard interaction between CapsLock the Shift
       // keys and normal characters)
@@ -591,12 +527,12 @@
 
         uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
         shift = isShiftPressed();
-        lock = server->ledState & ledCapsLock;
+        lock = server->getLEDState() & ledCapsLock;
 
         if (lock == (uppercase == shift)) {
           vlog.debug("Inserting fake CapsLock to get in sync with client");
-          server->desktop->keyEvent(XK_Caps_Lock, 0, true);
-          server->desktop->keyEvent(XK_Caps_Lock, 0, false);
+          server->keyEvent(XK_Caps_Lock, 0, true);
+          server->keyEvent(XK_Caps_Lock, 0, false);
         }
       }
 
@@ -611,7 +547,7 @@
         number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
                   (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
         shift = isShiftPressed();
-        lock = server->ledState & ledNumLock;
+        lock = server->getLEDState() & ledNumLock;
 
         if (shift) {
           // We don't know the appropriate NumLock state for when Shift
@@ -625,15 +561,15 @@
           //
         } else if (lock == (number == shift)) {
           vlog.debug("Inserting fake NumLock to get in sync with client");
-          server->desktop->keyEvent(XK_Num_Lock, 0, true);
-          server->desktop->keyEvent(XK_Num_Lock, 0, false);
+          server->keyEvent(XK_Num_Lock, 0, true);
+          server->keyEvent(XK_Num_Lock, 0, false);
         }
       }
     }
   }
 
   // Turn ISO_Left_Tab into shifted Tab.
-  VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
+  VNCSConnectionSTShiftPresser shiftPresser(server);
   if (keysym == XK_ISO_Left_Tab) {
     if (!isShiftPressed())
       shiftPresser.press();
@@ -659,21 +595,21 @@
       return;
   }
 
-  server->desktop->keyEvent(keysym, keycode, down);
+  server->keyEvent(keysym, keycode, down);
 }
 
 void VNCSConnectionST::clientCutText(const char* str, int len)
 {
-  if (!(accessRights & AccessCutText)) return;
+  if (!accessCheck(AccessCutText)) return;
   if (!rfb::Server::acceptCutText) return;
-  server->desktop->clientCutText(str, len);
+  server->clientCutText(str, len);
 }
 
 void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
 {
   Rect safeRect;
 
-  if (!(accessRights & AccessView)) return;
+  if (!accessCheck(AccessView)) return;
 
   SConnection::framebufferUpdateRequest(r, incremental);
 
@@ -712,30 +648,12 @@
 {
   unsigned int result;
 
-  if (!(accessRights & AccessSetDesktopSize)) return;
+  if (!accessCheck(AccessSetDesktopSize)) return;
   if (!rfb::Server::acceptSetDesktopSize) return;
 
-  // Don't bother the desktop with an invalid configuration
-  if (!layout.validate(fb_width, fb_height)) {
-    writer()->writeExtendedDesktopSize(reasonClient, resultInvalid,
-                                       fb_width, fb_height, layout);
-    return;
-  }
-
-  // FIXME: the desktop will call back to VNCServerST and an extra set
-  // of ExtendedDesktopSize messages will be sent. This is okay
-  // protocol-wise, but unnecessary.
-  result = server->desktop->setScreenLayout(fb_width, fb_height, layout);
-
+  result = server->setDesktopSize(this, fb_width, fb_height, layout);
   writer()->writeExtendedDesktopSize(reasonClient, result,
                                      fb_width, fb_height, layout);
-
-  // Only notify other clients on success
-  if (result == resultSuccess) {
-    if (server->screenLayout != layout)
-        throw Exception("Desktop configured a different screen layout than requested");
-    server->notifyScreenLayoutChange(this);
-  }
 }
 
 void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -1001,7 +919,7 @@
 
     bogusCopiedCursor = damagedCursorRegion;
     bogusCopiedCursor.translate(ui.copy_delta);
-    bogusCopiedCursor.assign_intersect(server->pb->getRect());
+    bogusCopiedCursor.assign_intersect(server->getPixelBuffer()->getRect());
     if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
       updates.add_changed(bogusCopiedCursor);
       needNewUpdateInfo = true;
@@ -1124,7 +1042,7 @@
   if (!authenticated())
     return;
 
-  cp.screenLayout = server->screenLayout;
+  cp.screenLayout = server->getScreenLayout();
 
   if (state() != RFBSTATE_NORMAL)
     return;
@@ -1148,7 +1066,7 @@
     cp.setCursor(emptyCursor);
     clientHasCursor = false;
   } else {
-    cp.setCursor(*server->cursor);
+    cp.setCursor(*server->getCursor());
     clientHasCursor = true;
   }
 
@@ -1194,37 +1112,3 @@
   sock->inStream().setTimeout(timeoutms);
   sock->outStream().setTimeout(timeoutms);
 }
-
-char* VNCSConnectionST::getStartTime()
-{
-  char* result = ctime(&startTime);
-  result[24] = '\0';
-  return result; 
-}
-
-void VNCSConnectionST::setStatus(int status)
-{
-  switch (status) {
-  case 0:
-    accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
-    break;
-  case 1:
-    accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents)) | AccessView;
-    break;
-  case 2:
-    accessRights = accessRights & ~(AccessPtrEvents | AccessKeyEvents | AccessView);
-    break;
-  }
-  framebufferUpdateRequest(server->pb->getRect(), false);
-}
-int VNCSConnectionST::getStatus()
-{
-  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
-    return 0;
-  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
-    return 1;
-  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
-    return 2;
-  return 4;
-}
-
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index dfc8bcb..1b7d59a 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -43,21 +43,18 @@
     VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
     virtual ~VNCSConnectionST();
 
+    // SConnection methods
+
+    virtual bool accessCheck(AccessRights ar) const;
+    virtual void close(const char* reason);
+
     // Methods called from VNCServerST.  None of these methods ever knowingly
     // throw an exception.
 
-    // Unless otherwise stated, the SConnectionST may not be valid after any of
-    // these methods are called, since they catch exceptions and may have
-    // called close() which deletes the object.
-
     // init() must be called to initialise the protocol.  If it fails it
     // returns false, and close() will have been called.
     bool init();
 
-    // close() shuts down the socket to the client and deletes the
-    // SConnectionST object.
-    void close(const char* reason);
-
     // processMessages() processes incoming messages from the client, invoking
     // various callbacks as a result.  It continues to process messages until
     // reading might block.  shutdown() will be called on the connection's
@@ -78,14 +75,14 @@
     void serverCutTextOrClose(const char *str, int len);
     void setDesktopNameOrClose(const char *name);
     void setLEDStateOrClose(unsigned int state);
+    void approveConnectionOrClose(bool accept, const char* reason);
 
     // checkIdleTimeout() returns the number of milliseconds left until the
     // idle timeout expires.  If it has expired, the connection is closed and
     // zero is returned.  Zero is also returned if there is no idle timeout.
     int checkIdleTimeout();
 
-    // The following methods never throw exceptions nor do they ever delete the
-    // SConnectionST object.
+    // The following methods never throw exceptions
 
     // getComparerState() returns if this client would like the framebuffer
     // comparer to be enabled.
@@ -103,32 +100,18 @@
     bool needRenderedCursor();
 
     network::Socket* getSock() { return sock; }
+
+    // Change tracking
+
     void add_changed(const Region& region) { updates.add_changed(region); }
     void add_copied(const Region& dest, const Point& delta) {
       updates.add_copied(dest, delta);
     }
 
-    const char* getPeerEndpoint() const {return peerEndpoint.buf;}
-
-    // approveConnectionOrClose() is called some time after
-    // VNCServerST::queryConnection() has returned with PENDING to accept or
-    // reject the connection.  The accept argument should be true for
-    // acceptance, or false for rejection, in which case a string reason may
-    // also be given.
-
-    void approveConnectionOrClose(bool accept, const char* reason);
-
-    char* getStartTime();
-
-    void setStatus(int status);
-    int getStatus();
-
   private:
     // SConnection callbacks
 
-    // These methods are invoked as callbacks from processMsg().  Note that
-    // none of these methods should call any of the above methods which may
-    // delete the SConnectionST object.
+    // These methods are invoked as callbacks from processMsg()
 
     virtual void authSuccess();
     virtual void queryConnection(const char* userName);
@@ -148,12 +131,6 @@
     virtual void supportsContinuousUpdates();
     virtual void supportsLEDState();
 
-    // setAccessRights() allows a security package to limit the access rights
-    // of a VNCSConnectioST to the server.  These access rights are applied
-    // such that the actual rights granted are the minimum of the server's
-    // default access settings and the connection's access settings.
-    virtual void setAccessRights(AccessRights ar) {accessRights=ar;}
-
     // Timer callbacks
     virtual bool handleTimeout(Timer* t);
 
@@ -178,6 +155,7 @@
     void setLEDState(unsigned int state);
     void setSocketTimeouts();
 
+  private:
     network::Socket* sock;
     CharArray peerEndpoint;
     bool reverseConnection;
@@ -209,10 +187,7 @@
     Point pointerEventPos;
     bool clientHasCursor;
 
-    AccessRights accessRights;
-
     CharArray closeReason;
-    time_t startTime;
   };
 }
 #endif
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index c5335ad..298326f 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -22,13 +22,16 @@
 #ifndef __RFB_VNCSERVER_H__
 #define __RFB_VNCSERVER_H__
 
+#include <network/Socket.h>
+
 #include <rfb/UpdateTracker.h>
 #include <rfb/SSecurity.h>
 #include <rfb/ScreenSet.h>
 
 namespace rfb {
 
-  class VNCServer : public UpdateTracker {
+  class VNCServer : public UpdateTracker,
+                    public network::SocketServer {
   public:
     // blockUpdates()/unblockUpdates() tells the server that the pixel buffer
     // is currently in flux and may not be accessed. The attributes of the
@@ -50,7 +53,7 @@
     virtual void setScreenLayout(const ScreenSet& layout) = 0;
 
     // getPixelBuffer() returns a pointer to the PixelBuffer object.
-    virtual PixelBuffer* getPixelBuffer() const = 0;
+    virtual const PixelBuffer* getPixelBuffer() const = 0;
 
     // serverCutText() tells the server that the cut text has changed.  This
     // will normally be sent to all clients.
@@ -59,10 +62,22 @@
     // bell() tells the server that it should make all clients make a bell sound.
     virtual void bell() = 0;
 
+    // approveConnection() is called some time after
+    // SDesktop::queryConnection() has been called, to accept or reject
+    // the connection.  The accept argument should be true for
+    // acceptance, or false for rejection, in which case a string
+    // reason may also be given.
+    virtual void approveConnection(network::Socket* sock, bool accept,
+                                   const char* reason = NULL) = 0;
+
     // - Close all currently-connected clients, by calling
     //   their close() method with the supplied reason.
     virtual void closeClients(const char* reason) = 0;
 
+    // getConnection() gets the SConnection for a particular Socket.  If
+    // the Socket is not recognised then null is returned.
+    virtual SConnection* getConnection(network::Socket* sock) = 0;
+
     // setCursor() tells the server that the cursor has changed.  The
     // cursorData argument contains width*height rgba quadruplets with
     // non-premultiplied alpha.
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 8cc04f7..038da3d 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -53,7 +53,7 @@
 
 #include <rfb/ComparingUpdateTracker.h>
 #include <rfb/KeyRemapper.h>
-#include <rfb/ListConnInfo.h>
+#include <rfb/LogWriter.h>
 #include <rfb/Security.h>
 #include <rfb/ServerCore.h>
 #include <rfb/VNCServerST.h>
@@ -66,7 +66,7 @@
 using namespace rfb;
 
 static LogWriter slog("VNCServerST");
-LogWriter VNCServerST::connectionsLog("Connections");
+static LogWriter connectionsLog("Connections");
 
 //
 // -=- VNCServerST Implementation
@@ -80,9 +80,8 @@
     name(strDup(name_)), pointerClient(0), comparer(0),
     cursor(new Cursor(0, 0, Point(), NULL)),
     renderedCursorInvalid(false),
-    queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
-    lastConnectionTime(0), disableclients(false),
-    frameTimer(this)
+    keyRemapper(&KeyRemapper::defInstance),
+    lastConnectionTime(0), frameTimer(this)
 {
   lastUserInputTime = lastDisconnectTime = time(0);
   slog.debug("creating single-threaded server %s", name.buf);
@@ -99,9 +98,11 @@
   stopFrameClock();
 
   // Delete all the clients, and their sockets, and any closing sockets
-  //   NB: Deleting a client implicitly removes it from the clients list
   while (!clients.empty()) {
-    delete clients.front();
+    VNCSConnectionST* client;
+    client = clients.front();
+    clients.pop_front();
+    delete client;
   }
 
   // Stop the desktop object if active, *only* after deleting all clients!
@@ -125,8 +126,13 @@
   if (blHosts->isBlackmarked(address.buf)) {
     connectionsLog.error("blacklisted: %s", address.buf);
     try {
-      SConnection::writeConnFailedFromScratch("Too many security failures",
-                                              &sock->outStream());
+      rdr::OutStream& os = sock->outStream();
+
+      // Shortest possible way to tell a client it is not welcome
+      os.writeBytes("RFB 003.003\n", 12);
+      os.writeU32(0);
+      os.writeString("Too many security failures");
+      os.flush();
     } catch (rdr::Exception&) {
     }
     sock->shutdown();
@@ -134,11 +140,16 @@
     return;
   }
 
+  CharArray name;
+  name.buf = sock->getPeerEndpoint();
+  connectionsLog.status("accepted: %s", name.buf);
+
   if (clients.empty()) {
     lastConnectionTime = time(0);
   }
 
   VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+  clients.push_front(client);
   client->init();
 }
 
@@ -147,9 +158,22 @@
   std::list<VNCSConnectionST*>::iterator ci;
   for (ci = clients.begin(); ci != clients.end(); ci++) {
     if ((*ci)->getSock() == sock) {
+      clients.remove(*ci);
+
+      // - Release the cursor if this client owns it
+      if (pointerClient == *ci)
+        pointerClient = NULL;
+
+      if ((*ci)->authenticated())
+        lastDisconnectTime = time(0);
+
       // - Delete the per-Socket resources
       delete *ci;
 
+      CharArray name;
+      name.buf = sock->getPeerEndpoint();
+      connectionsLog.status("closed: %s", name.buf);
+
       // - Check that the desktop object is still required
       if (authClientCount() == 0)
         stopDesktop();
@@ -467,6 +491,81 @@
   }
 }
 
+// Event handlers
+
+void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
+{
+  lastUserInputTime = time(0);
+
+  // Remap the key if required
+  if (keyRemapper) {
+    rdr::U32 newkey;
+    newkey = keyRemapper->remapKey(keysym);
+    if (newkey != keysym) {
+      slog.debug("Key remapped to 0x%x", newkey);
+      keysym = newkey;
+    }
+  }
+
+  desktop->keyEvent(keysym, keycode, down);
+}
+
+void VNCServerST::pointerEvent(VNCSConnectionST* client,
+                               const Point& pos, int buttonMask)
+{
+  lastUserInputTime = time(0);
+
+  // Let one client own the cursor whilst buttons are pressed in order
+  // to provide a bit more sane user experience
+  if ((pointerClient != NULL) && (pointerClient != client))
+    return;
+
+  if (buttonMask)
+    pointerClient = client;
+  else
+    pointerClient = NULL;
+
+  desktop->pointerEvent(pos, buttonMask);
+}
+
+void VNCServerST::clientCutText(const char* str, int len)
+{
+  desktop->clientCutText(str, len);
+}
+
+unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester,
+                                         int fb_width, int fb_height,
+                                         const ScreenSet& layout)
+{
+  unsigned int result;
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+
+  // Don't bother the desktop with an invalid configuration
+  if (!layout.validate(fb_width, fb_height))
+    return resultInvalid;
+
+  // FIXME: the desktop will call back to VNCServerST and an extra set
+  // of ExtendedDesktopSize messages will be sent. This is okay
+  // protocol-wise, but unnecessary.
+  result = desktop->setScreenLayout(fb_width, fb_height, layout);
+  if (result != resultSuccess)
+    return result;
+
+  // Sanity check
+  if (screenLayout != layout)
+    throw Exception("Desktop configured a different screen layout than requested");
+
+  // Notify other clients
+  for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+    ci_next = ci; ci_next++;
+    if ((*ci) == requester)
+      continue;
+    (*ci)->screenLayoutChangeOrClose(reasonOtherClient);
+  }
+
+  return resultSuccess;
+}
+
 // Other public methods
 
 void VNCServerST::approveConnection(network::Socket* sock, bool accept,
@@ -504,7 +603,7 @@
   }
 }
 
-SConnection* VNCServerST::getSConnection(network::Socket* sock) {
+SConnection* VNCServerST::getConnection(network::Socket* sock) {
   std::list<VNCSConnectionST*>::iterator ci;
   for (ci = clients.begin(); ci != clients.end(); ci++) {
     if ((*ci)->getSock() == sock)
@@ -534,6 +633,63 @@
   return false;
 }
 
+void VNCServerST::queryConnection(VNCSConnectionST* client,
+                                  const char* userName)
+{
+  // - Authentication succeeded - clear from blacklist
+  CharArray name;
+  name.buf = client->getSock()->getPeerAddress();
+  blHosts->clearBlackmark(name.buf);
+
+  // - Prepare the desktop for that the client will start requiring
+  // resources after this
+  startDesktop();
+
+  // - Special case to provide a more useful error message
+  if (rfb::Server::neverShared &&
+      !rfb::Server::disconnectClients &&
+      authClientCount() > 0) {
+    approveConnection(client->getSock(), false,
+                      "The server is already in use");
+    return;
+  }
+
+  // - Are we configured to do queries?
+  if (!rfb::Server::queryConnect &&
+      !client->getSock()->requiresQuery()) {
+    approveConnection(client->getSock(), true, NULL);
+    return;
+  }
+
+  // - Does the client have the right to bypass the query?
+  if (client->accessCheck(SConnection::AccessNoQuery))
+  {
+    approveConnection(client->getSock(), true, NULL);
+    return;
+  }
+
+  desktop->queryConnection(client->getSock(), userName);
+}
+
+void VNCServerST::clientReady(VNCSConnectionST* client, bool shared)
+{
+  if (!shared) {
+    if (rfb::Server::disconnectClients &&
+        client->accessCheck(SConnection::AccessNonShared)) {
+      // - Close all the other connected clients
+      slog.debug("non-shared connection - closing clients");
+      closeClients("Non-shared connection requested", client->getSock());
+    } else {
+      // - Refuse this connection if there are existing clients, in addition to
+      // this one
+      if (authClientCount() > 1) {
+        client->close("Server is already in use");
+        return;
+      }
+    }
+  }
+}
+
 // -=- Internal methods
 
 void VNCServerST::startDesktop()
@@ -689,50 +845,6 @@
   return &renderedCursor;
 }
 
-void VNCServerST::getConnInfo(ListConnInfo * listConn)
-{
-  listConn->Clear();
-  listConn->setDisable(getDisable());
-  if (clients.empty())
-    return;
-  std::list<VNCSConnectionST*>::iterator i;
-  for (i = clients.begin(); i != clients.end(); i++)
-    listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
-                      (*i)->getStartTime(), (*i)->getStatus());
-}
-
-void VNCServerST::setConnStatus(ListConnInfo* listConn)
-{
-  setDisable(listConn->getDisable());
-  if (listConn->Empty() || clients.empty()) return;
-  for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
-    VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
-    std::list<VNCSConnectionST*>::iterator i;
-    for (i = clients.begin(); i != clients.end(); i++) {
-      if ((*i) == conn) {
-        int status = listConn->iGetStatus();
-        if (status == 3) {
-          (*i)->close(0);
-        } else {
-          (*i)->setStatus(status);
-        }
-        break;
-      }
-    }
-  }
-}
-
-void VNCServerST::notifyScreenLayoutChange(VNCSConnectionST* requester)
-{
-  std::list<VNCSConnectionST*>::iterator ci, ci_next;
-  for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
-    ci_next = ci; ci_next++;
-    if ((*ci) == requester)
-      continue;
-    (*ci)->screenLayoutChangeOrClose(reasonOtherClient);
-  }
-}
-
 bool VNCServerST::getComparerState()
 {
   if (rfb::Server::compareFB == 0)
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index b7845dd..545b9a4 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -28,11 +28,9 @@
 
 #include <rfb/SDesktop.h>
 #include <rfb/VNCServer.h>
-#include <rfb/LogWriter.h>
 #include <rfb/Blacklist.h>
 #include <rfb/Cursor.h>
 #include <rfb/Timer.h>
-#include <network/Socket.h>
 #include <rfb/ScreenSet.h>
 
 namespace rfb {
@@ -44,8 +42,7 @@
   class KeyRemapper;
 
   class VNCServerST : public VNCServer,
-                      public Timer::Callback,
-                      public network::SocketServer {
+                      public Timer::Callback {
   public:
     // -=- Constructors
 
@@ -93,102 +90,70 @@
     virtual void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout);
     virtual void setPixelBuffer(PixelBuffer* pb);
     virtual void setScreenLayout(const ScreenSet& layout);
-    virtual PixelBuffer* getPixelBuffer() const { return pb; }
+    virtual const PixelBuffer* getPixelBuffer() const { return pb; }
     virtual void serverCutText(const char* str, int len);
+
+    virtual void approveConnection(network::Socket* sock, bool accept,
+                                   const char* reason);
+    virtual void closeClients(const char* reason) {closeClients(reason, 0);}
+    virtual SConnection* getConnection(network::Socket* sock);
+
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
     virtual void setCursor(int width, int height, const Point& hotspot,
                            const rdr::U8* data);
     virtual void setCursorPos(const Point& p);
+    virtual void setName(const char* name_);
     virtual void setLEDState(unsigned state);
 
     virtual void bell();
 
-    // - Close all currently-connected clients, by calling
-    //   their close() method with the supplied reason.
-    virtual void closeClients(const char* reason) {closeClients(reason, 0);}
-
     // VNCServerST-only methods
 
+    // Methods to get the currently set server state
+
+    const ScreenSet& getScreenLayout() const { return screenLayout; }
+    const Cursor* getCursor() const { return cursor; }
+    const Point& getCursorPos() const { return cursorPos; }
+    const char* getName() const { return name.buf; }
+    unsigned getLEDState() const { return ledState; }
+
+    // Event handlers
+    void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
+    void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask);
+    void clientCutText(const char* str, int len);
+
+    unsigned int setDesktopSize(VNCSConnectionST* requester,
+                                int fb_width, int fb_height,
+                                const ScreenSet& layout);
+
     // closeClients() closes all RFB sessions, except the specified one (if
     // any), and logs the specified reason for closure.
     void closeClients(const char* reason, network::Socket* sock);
 
-    // getSConnection() gets the SConnection for a particular Socket.  If
-    // the Socket is not recognised then null is returned.
+    // queryConnection() does some basic checks and then passes on the
+    // request to the desktop.
+    void queryConnection(VNCSConnectionST* client, const char* userName);
 
-    SConnection* getSConnection(network::Socket* sock);
+    // clientReady() is called by a VNCSConnectionST instance when the
+    // client has completed the handshake and is ready for normal
+    // communication.
+    void clientReady(VNCSConnectionST* client, bool shared);
 
-    // getName() returns the name of this VNC Server.  NB: The value returned
-    // is the server's internal buffer which may change after any other methods
-    // are called - take a copy if necessary.
-    const char* getName() const {return name.buf;}
+    // Estimated time until the next time new updates will be pushed
+    // to clients
+    int msToNextUpdate();
 
-    // setName() specifies the desktop name that the server should provide to
-    // clients
-    virtual void setName(const char* name_);
+    // Part of the framebuffer that has been modified but is not yet
+    // ready to be sent to clients
+    Region getPendingRegion();
 
-    // A QueryConnectionHandler, if supplied, is passed details of incoming
-    // connections to approve, reject, or query the user about.
-    //
-    // queryConnection() is called when a connection has been
-    // successfully authenticated.  The sock and userName arguments identify
-    // the socket and the name of the authenticated user, if any.  It should
-    // return ACCEPT if the connection should be accepted, REJECT if it should
-    // be rejected, or PENDING if a decision cannot yet be reached.  If REJECT
-    // is returned, *reason can be set to a string describing the reason - this
-    // will be delete[]ed when it is finished with.  If PENDING is returned,
-    // approveConnection() must be called some time later to accept or reject
-    // the connection.
-    enum queryResult { ACCEPT, REJECT, PENDING };
-    struct QueryConnectionHandler {
-      virtual ~QueryConnectionHandler() {}
-      virtual queryResult queryConnection(network::Socket* sock,
-                                          const char* userName,
-                                          char** reason) = 0;
-    };
-    void setQueryConnectionHandler(QueryConnectionHandler* qch) {
-      queryConnectionHandler = qch;
-    }
-
-    // queryConnection is called as described above, and either passes the
-    // request on to the registered handler, or accepts the connection if
-    // no handler has been specified.
-    virtual queryResult queryConnection(network::Socket* sock,
-                                        const char* userName,
-                                        char** reason) {
-      return queryConnectionHandler
-        ? queryConnectionHandler->queryConnection(sock, userName, reason)
-        : ACCEPT;
-    }
-
-    // approveConnection() is called by the active QueryConnectionHandler,
-    // some time after queryConnection() has returned with PENDING, to accept
-    // or reject the connection.  The accept argument should be true for
-    // acceptance, or false for rejection, in which case a string reason may
-    // also be given.
-    void approveConnection(network::Socket* sock, bool accept,
-                           const char* reason);
-
-    // setBlacklist() is called to replace the VNCServerST's internal
-    // Blacklist instance with another instance.  This allows a single
-    // Blacklist to be shared by multiple VNCServerST instances.
-    void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}
-
-    // setKeyRemapper() replaces the VNCServerST's default key remapper.
-    // NB: A null pointer is valid here.
-    void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; }
-
-    void getConnInfo(ListConnInfo * listConn);
-    void setConnStatus(ListConnInfo* listConn);
-
-    bool getDisable() { return disableclients;};
-    void setDisable(bool disable) { disableclients = disable;};
+    // getRenderedCursor() returns an up to date version of the server
+    // side rendered cursor buffer
+    const RenderedCursor* getRenderedCursor();
 
   protected:
 
-    friend class VNCSConnectionST;
-
     // Timer callbacks
     virtual bool handleTimeout(Timer* t);
 
@@ -197,7 +162,17 @@
     void startDesktop();
     void stopDesktop();
 
-    static LogWriter connectionsLog;
+    // - Check how many of the clients are authenticated.
+    int authClientCount();
+
+    bool needRenderedCursor();
+    void startFrameClock();
+    void stopFrameClock();
+    void writeUpdate();
+
+    bool getComparerState();
+
+  protected:
     Blacklist blacklist;
     Blacklist* blHosts;
 
@@ -221,30 +196,12 @@
     RenderedCursor renderedCursor;
     bool renderedCursorInvalid;
 
-    // - Check how many of the clients are authenticated.
-    int authClientCount();
-
-    bool needRenderedCursor();
-    void startFrameClock();
-    void stopFrameClock();
-    int msToNextUpdate();
-    void writeUpdate();
-    Region getPendingRegion();
-    const RenderedCursor* getRenderedCursor();
-
-    void notifyScreenLayoutChange(VNCSConnectionST *requester);
-
-    bool getComparerState();
-
-    QueryConnectionHandler* queryConnectionHandler;
     KeyRemapper* keyRemapper;
 
     time_t lastUserInputTime;
     time_t lastDisconnectTime;
     time_t lastConnectionTime;
 
-    bool disableclients;
-
     Timer frameTimer;
   };
 
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index fa5adf4..5f71ccb 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -18,6 +18,10 @@
  * USA.
  */
 
+#include <assert.h>
+
+#include <rfb/LogWriter.h>
+
 #include <x0vncserver/XDesktop.h>
 
 #include <X11/XKBlib.h>
@@ -53,6 +57,10 @@
                           "Send keyboard events straight through and "
                           "avoid mapping them to the current keyboard "
                           "layout", false);
+IntParameter queryConnectTimeout("QueryConnectTimeout",
+                                 "Number of seconds to show the Accept Connection dialog before "
+                                 "rejecting the connection",
+                                 10);
 
 static rfb::LogWriter vlog("XDesktop");
 
@@ -63,6 +71,7 @@
 
 XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
   : dpy(dpy_), geometry(geometry_), pb(0), server(0),
+    queryConnectDialog(0), queryConnectSock(0),
     oldButtonMask(0), haveXtest(false), haveDamage(false),
     maxButtons(0), running(false), ledMasks(), ledState(0),
     codeMap(0), codeMapLen(0)
@@ -227,7 +236,7 @@
   pb = new XPixelBuffer(dpy, factory, geometry->getRect());
   vlog.info("Allocated %s", pb->getImage()->classDesc());
 
-  server = (VNCServerST *)vs;
+  server = vs;
   server->setPixelBuffer(pb, computeScreenLayout());
 
 #ifdef HAVE_XDAMAGE
@@ -254,6 +263,9 @@
     XDamageDestroy(dpy, damage);
 #endif
 
+  delete queryConnectDialog;
+  queryConnectDialog = 0;
+
   server->setPixelBuffer(0);
   server = 0;
 
@@ -265,6 +277,30 @@
   return running;
 }
 
+void XDesktop::queryConnection(network::Socket* sock,
+                               const char* userName)
+{
+  assert(isRunning());
+
+  if (queryConnectSock) {
+    server->approveConnection(sock, false, "Another connection is currently being queried.");
+    return;
+  }
+
+  if (!userName)
+    userName = "(anonymous)";
+
+  queryConnectSock = sock;
+
+  CharArray address(sock->getPeerAddress());
+  delete queryConnectDialog;
+  queryConnectDialog = new QueryConnectDialog(dpy, address.buf,
+                                              userName,
+                                              queryConnectTimeout,
+                                              this);
+  queryConnectDialog->map();
+}
+
 void XDesktop::pointerEvent(const Point& pos, int buttonMask) {
 #ifdef HAVE_XTEST
   if (!haveXtest) return;
@@ -686,6 +722,21 @@
   return false;
 }
 
+void XDesktop::queryApproved()
+{
+  assert(isRunning());
+  server->approveConnection(queryConnectSock, true, 0);
+  queryConnectSock = 0;
+}
+
+void XDesktop::queryRejected()
+{
+  assert(isRunning());
+  server->approveConnection(queryConnectSock, false,
+                            "Connection rejected by local user");
+  queryConnectSock = 0;
+}
+
 bool XDesktop::setCursor()
 {
   XFixesCursorImage *cim;
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index ff52c01..7d06061 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -21,7 +21,7 @@
 #ifndef __XDESKTOP_H__
 #define __XDESKTOP_H__
 
-#include <rfb/VNCServerST.h>
+#include <rfb/SDesktop.h>
 #include <tx/TXWindow.h>
 #include <unixcommon.h>
 
@@ -30,13 +30,17 @@
 #include <X11/extensions/Xdamage.h>
 #endif
 
+#include <vncconfig/QueryConnectDialog.h>
+
 class Geometry;
 class XPixelBuffer;
 
 // number of XKb indicator leds to handle
 #define XDESKTOP_N_LEDS 3
 
-class XDesktop : public rfb::SDesktop, public TXGlobalEventHandler
+class XDesktop : public rfb::SDesktop,
+                 public TXGlobalEventHandler,
+                 public QueryResultCallback
 {
 public:
   XDesktop(Display* dpy_, Geometry *geometry);
@@ -46,6 +50,8 @@
   virtual void start(rfb::VNCServer* vs);
   virtual void stop();
   bool isRunning();
+  virtual void queryConnection(network::Socket* sock,
+                               const char* userName);
   virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
   KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
   virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
@@ -56,11 +62,17 @@
   // -=- TXGlobalEventHandler interface
   virtual bool handleGlobalEvent(XEvent* ev);
 
+  // -=- QueryResultCallback interface
+  virtual void queryApproved();
+  virtual void queryRejected();
+
 protected:
   Display* dpy;
   Geometry* geometry;
   XPixelBuffer* pb;
-  rfb::VNCServerST* server;
+  rfb::VNCServer* server;
+  QueryConnectDialog* queryConnectDialog;
+  network::Socket* queryConnectSock;
   int oldButtonMask;
   bool haveXtest;
   bool haveDamage;
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index d0d4be8..c77870d 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -33,8 +33,6 @@
 #include <network/TcpSocket.h>
 #include <network/UnixSocket.h>
 
-#include <vncconfig/QueryConnectDialog.h>
-
 #include <signal.h>
 #include <X11/X.h>
 #include <X11/Xlib.h>
@@ -61,10 +59,6 @@
 IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
 StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
 IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
-IntParameter queryConnectTimeout("QueryConnectTimeout",
-                                 "Number of seconds to show the Accept Connection dialog before "
-                                 "rejecting the connection",
-                                 10);
 StringParameter hostsFile("HostsFile", "File with IP access control rules", "");
 
 //
@@ -79,50 +73,6 @@
 }
 
 
-class QueryConnHandler : public VNCServerST::QueryConnectionHandler,
-                         public QueryResultCallback {
-public:
-  QueryConnHandler(Display* dpy, VNCServerST* vs)
-    : display(dpy), server(vs), queryConnectDialog(0), queryConnectSock(0) {}
-  ~QueryConnHandler() { delete queryConnectDialog; }
-
-  // -=- VNCServerST::QueryConnectionHandler interface
-  virtual VNCServerST::queryResult queryConnection(network::Socket* sock,
-                                                   const char* userName,
-                                                   char** reason) {
-    if (queryConnectSock) {
-      *reason = strDup("Another connection is currently being queried.");
-      return VNCServerST::REJECT;
-    }
-    if (!userName) userName = "(anonymous)";
-    queryConnectSock = sock;
-    CharArray address(sock->getPeerAddress());
-    delete queryConnectDialog;
-    queryConnectDialog = new QueryConnectDialog(display, address.buf,
-                                                userName, queryConnectTimeout,
-                                                this);
-    queryConnectDialog->map();
-    return VNCServerST::PENDING;
-  }
-
-  // -=- QueryResultCallback interface
-  virtual void queryApproved() {
-    server->approveConnection(queryConnectSock, true, 0);
-    queryConnectSock = 0;
-  }
-  virtual void queryRejected() {
-    server->approveConnection(queryConnectSock, false,
-                              "Connection rejected by local user");
-    queryConnectSock = 0;
-  }
-private:
-  Display* display;
-  VNCServerST* server;
-  QueryConnectDialog* queryConnectDialog;
-  network::Socket* queryConnectSock;
-};
-
-
 class FileTcpFilter : public TcpFilter
 {
 
@@ -307,8 +257,6 @@
     XDesktop desktop(dpy, &geo);
 
     VNCServerST server("x0vncserver", &desktop);
-    QueryConnHandler qcHandler(dpy, &server);
-    server.setQueryConnectionHandler(&qcHandler);
 
     if (rfbunixpath.getValueStr()[0] != '\0') {
       listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 04107dc..e61472b 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -81,7 +81,6 @@
 
   server = new VNCServerST(name, this);
   setFramebuffer(width, height, fbptr, stride);
-  server->setQueryConnectionHandler(this);
 
   for (std::list<SocketListener*>::iterator i = listeners.begin();
        i != listeners.end();
@@ -145,22 +144,31 @@
   server->setScreenLayout(::computeScreenLayout(&outputIdMap));
 }
 
-rfb::VNCServerST::queryResult
-XserverDesktop::queryConnection(network::Socket* sock,
-                                const char* userName,
-                                char** reason)
+void XserverDesktop::start(rfb::VNCServer* vs)
+{
+  // We already own the server object, and we always keep it in a
+  // ready state
+  assert(vs == server);
+}
+
+void XserverDesktop::stop()
+{
+}
+
+void XserverDesktop::queryConnection(network::Socket* sock,
+                                     const char* userName)
 {
   int count;
 
   if (queryConnectTimer.isStarted()) {
-    *reason = strDup("Another connection is currently being queried.");
-    return rfb::VNCServerST::REJECT;
+    server->approveConnection(sock, false, "Another connection is currently being queried.");
+    return;
   }
 
   count = vncNotifyQueryConnect();
   if (count == 0) {
-    *reason = strDup("Unable to query the local user to accept the connection.");
-    return rfb::VNCServerST::REJECT;
+    server->approveConnection(sock, false, "Unable to query the local user to accept the connection.");
+    return;
   }
 
   queryConnectAddress.replaceBuf(sock->getPeerAddress());
@@ -171,8 +179,6 @@
   queryConnectSocket = sock;
 
   queryConnectTimer.start(queryConnectTimeout * 1000);
-
-  return rfb::VNCServerST::PENDING;
 }
 
 void XserverDesktop::bell()
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 014fcb5..ff36b3b 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -34,7 +34,7 @@
 #include <rfb/SDesktop.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/Configuration.h>
-#include <rfb/VNCServerST.h>
+#include <rfb/Timer.h>
 #include <unixcommon.h>
 #include "Input.h"
 
@@ -45,7 +45,6 @@
 namespace network { class SocketListener; class Socket; class SocketServer; }
 
 class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
-                       public rfb::VNCServerST::QueryConnectionHandler,
                        public rfb::Timer::Callback {
 public:
 
@@ -86,6 +85,10 @@
                          const char* rejectMsg=0);
 
   // rfb::SDesktop callbacks
+  virtual void start(rfb::VNCServer* vs);
+  virtual void stop();
+  virtual void queryConnection(network::Socket* sock,
+                               const char* userName);
   virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
   virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
   virtual void clientCutText(const char* str, int len);
@@ -95,11 +98,6 @@
   // rfb::PixelBuffer callbacks
   virtual void grabRegion(const rfb::Region& r);
 
-  // rfb::VNCServerST::QueryConnectionHandler callback
-  virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
-                                                        const char* userName,
-                                                        char** reason);
-
 protected:
   bool handleListenerEvent(int fd,
                            std::list<network::SocketListener*>* sockets,
@@ -113,7 +111,7 @@
 private:
 
   int screenIndex;
-  rfb::VNCServerST* server;
+  rfb::VNCServer* server;
   std::list<network::SocketListener*> listeners;
   bool directFbptr;
 
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 9b2cbb0..afb72ad 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -20,6 +20,8 @@
 //
 // The SDisplay class encapsulates a particular system display.
 
+#include <assert.h>
+
 #include <rfb_win32/SDisplay.h>
 #include <rfb_win32/Service.h>
 #include <rfb_win32/TsSessions.h>
@@ -66,7 +68,7 @@
   : server(0), pb(0), device(0),
     core(0), ptr(0), kbd(0), clipboard(0),
     inputs(0), monitor(0), cleanDesktop(0), cursor(0),
-    statusLocation(0), ledState(0)
+    statusLocation(0), queryConnectionHandler(0), ledState(0)
 {
   updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
 }
@@ -139,6 +141,20 @@
 }
 
 
+void SDisplay::queryConnection(network::Socket* sock,
+                               const char* userName)
+{
+  assert(server != NULL);
+
+  if (queryConnectionHandler) {
+    queryConnectionHandler->queryConnection(sock, userName);
+    return;
+  }
+
+  server->approveConnection(sock, true);
+}
+
+
 void SDisplay::startCore() {
 
   // Currently, we just check whether we're in the console session, and
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index c1d5c1e..76ddf50 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -52,6 +52,13 @@
       virtual const char* methodName() const = 0;
     };
 
+    class QueryConnectionHandler {
+    public:
+      virtual ~QueryConnectionHandler() {}
+      virtual void queryConnection(network::Socket* sock,
+                                   const char* userName) = 0;
+    };
+
     class SDisplay : public SDesktop,
       WMMonitor::Notifier,
       Clipboard::Notifier,
@@ -65,6 +72,8 @@
 
       virtual void start(VNCServer* vs);
       virtual void stop();
+      virtual void queryConnection(network::Socket* sock,
+                                   const char* userName);
       virtual void pointerEvent(const Point& pos, int buttonmask);
       virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
       virtual void clientCutText(const char* str, int len);
@@ -86,6 +95,12 @@
 
       void setStatusLocation(bool* status) {statusLocation = status;}
 
+      // -=- Set handler for incoming connections
+
+      void setQueryConnectionHandler(QueryConnectionHandler* qch) {
+        queryConnectionHandler = qch;
+      }
+
       static IntParameter updateMethod;
       static BoolParameter disableLocalInputs;
       static StringParameter disconnectAction;
@@ -150,6 +165,9 @@
       // -=- Where to write the active/inactive indicator to
       bool* statusLocation;
 
+      // -=- Whom to query incoming connections
+      QueryConnectionHandler* queryConnectionHandler;
+
       unsigned ledState;
     };
 
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index 5b211a0..aa469e5 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -78,6 +78,7 @@
   li.sock = sock_;
   li.server = srvr;
   li.notifier = acn;
+  li.disable = false;
   listeners[event] = li;
 }
 
@@ -128,6 +129,32 @@
   throw rdr::Exception("Socket not registered");
 }
 
+bool SocketManager::getDisable(network::SocketServer* srvr)
+{
+  std::map<HANDLE,ListenInfo>::iterator i;
+  for (i=listeners.begin(); i!=listeners.end(); i++) {
+    if (i->second.server == srvr) {
+      return i->second.disable;
+    }
+  }
+  throw rdr::Exception("Listener not registered");
+}
+
+void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
+{
+  bool found = false;
+  std::map<HANDLE,ListenInfo>::iterator i;
+  for (i=listeners.begin(); i!=listeners.end(); i++) {
+    if (i->second.server == srvr) {
+      i->second.disable = disable;
+      // There might be multiple sockets for the same server, so
+      // continue iterating
+      found = true;
+    }
+  }
+  if (!found)
+    throw rdr::Exception("Listener not registered");
+}
 
 int SocketManager::checkTimeouts() {
   int timeout = EventManager::checkTimeouts();
@@ -164,7 +191,7 @@
     WSAEnumNetworkEvents(li.sock->getFd(), event, &network_events);
     if (network_events.lNetworkEvents & FD_ACCEPT) {
       network::Socket* new_sock = li.sock->accept();
-      if (new_sock && li.server->getDisable()) {
+      if (new_sock && li.disable) {
         delete new_sock;
         new_sock = 0;
       }
diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
index c3c8faf..e5ca02e 100644
--- a/win/rfb_win32/SocketManager.h
+++ b/win/rfb_win32/SocketManager.h
@@ -65,6 +65,9 @@
       // the SocketServer.
       void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
 
+      bool getDisable(network::SocketServer* srvr);
+      void setDisable(network::SocketServer* srvr, bool disable);
+
     protected:
       virtual int checkTimeouts();
       virtual void processEvent(HANDLE event);
@@ -78,6 +81,7 @@
         network::SocketListener* sock;
         network::SocketServer* server;
         AddressChangeNotifier* notifier;
+        bool disable;
       };
       std::map<HANDLE, ListenInfo> listeners;
       std::map<HANDLE, ConnInfo> connections;
diff --git a/win/winvnc/ControlPanel.cxx b/win/winvnc/ControlPanel.cxx
index ba6cab2..72831e5 100644
--- a/win/winvnc/ControlPanel.cxx
+++ b/win/winvnc/ControlPanel.cxx
@@ -19,10 +19,9 @@
 {
   TCHAR *ColumnsStrings[] = {
     (TCHAR *) "IP address",
-    (TCHAR *) "Time connected",
     (TCHAR *) "Status"
   };
-  InitLVColumns(IDC_LIST_CONNECTIONS, handle, 120, 3, ColumnsStrings,
+  InitLVColumns(IDC_LIST_CONNECTIONS, handle, 120, 2, ColumnsStrings,
                 LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
                 LVS_EX_FULLROWSELECT, LVCFMT_LEFT);
   SendCommand(4, -1);
@@ -74,7 +73,7 @@
   
 }
 
-void ControlPanel::UpdateListView(rfb::ListConnInfo* LCInfo)
+void ControlPanel::UpdateListView(ListConnInfo* LCInfo)
 {
   getSelConnInfo();
   DeleteAllLVItem(IDC_LIST_CONNECTIONS, handle);
@@ -85,12 +84,12 @@
 
   ListConn.Copy(LCInfo);
 
-  char* ItemString[3];
+  char* ItemString[2];
   int i = 0;
 
   for (ListConn.iBegin(); !ListConn.iEnd(); ListConn.iNext()) {
     ListConn.iGetCharInfo(ItemString);
-    InsertLVItem(IDC_LIST_CONNECTIONS, handle, i, (TCHAR **) ItemString, 3);
+    InsertLVItem(IDC_LIST_CONNECTIONS, handle, i, (TCHAR **) ItemString, 2);
     for (ListSelConn.iBegin(); !ListSelConn.iEnd(); ListSelConn.iNext()) {
       if (ListSelConn.iGetConn() == ListConn.iGetConn())
         SelectLVItem(IDC_LIST_CONNECTIONS, handle, i);
@@ -141,6 +140,8 @@
 {
   COPYDATASTRUCT copyData;
   copyData.dwData = command;
+  copyData.cbData = 0;
+  copyData.lpData = 0;
   getSelConnInfo();
   if (data != -1) {
     ListConnStatus.Copy(&ListSelConn);
@@ -149,8 +150,6 @@
   } else {
     ListConnStatus.Clear();
   }
-  copyData.cbData = 0;
-  copyData.lpData = &ListConnStatus;
   SendMessage(m_hSTIcon, WM_COPYDATA, 0, (LPARAM)&copyData);
 }
 
diff --git a/win/winvnc/ControlPanel.h b/win/winvnc/ControlPanel.h
index 73b859f..f64a608 100644
--- a/win/winvnc/ControlPanel.h
+++ b/win/winvnc/ControlPanel.h
@@ -11,10 +11,10 @@
 
 #include <list>
 #include <winvnc/resource.h>
+#include <winvnc/ListConnInfo.h>
 #include <rfb_win32/Dialog.h>
 #include <rfb_win32/ListViewControl.h>
 #include <rfb_win32/Win32Util.h>
-#include <rfb/ListConnInfo.h>
 
 namespace winvnc {
   
@@ -27,19 +27,19 @@
     virtual bool showDialog();
     virtual void initDialog();
     virtual bool onCommand(int cmd);
-    void UpdateListView(rfb::ListConnInfo* LCInfo);
+    void UpdateListView(ListConnInfo* LCInfo);
     HWND GetHandle() {return handle;};
     void SendCommand(DWORD command, int data);
     ~ControlPanel();
-    rfb::ListConnInfo ListConnStatus;
+    ListConnInfo ListConnStatus;
   protected: 
     virtual BOOL dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
     void getSelConnInfo();
     HWND m_hSTIcon;
-    rfb::ListConnInfo ListConn;
-    rfb::ListConnInfo ListSelConn;
+    ListConnInfo ListConn;
+    ListConnInfo ListSelConn;
     bool stop_updating;
   };
 };
 
-#endif  
\ No newline at end of file
+#endif  
diff --git a/common/rfb/ListConnInfo.h b/win/winvnc/ListConnInfo.h
similarity index 80%
rename from common/rfb/ListConnInfo.h
rename to win/winvnc/ListConnInfo.h
index c49947d..6ca5b7c 100644
--- a/common/rfb/ListConnInfo.h
+++ b/win/winvnc/ListConnInfo.h
@@ -24,7 +24,7 @@
 
 #include <rfb/util.h>
 
-namespace rfb {
+namespace winvnc {
 
   struct ListConnInfo  {
     ListConnInfo() : disableClients(false) {}
@@ -32,7 +32,6 @@
     void Clear() {
       conn.clear();
       IP_address.clear();
-      time_conn.clear();
       status.clear();
     }
 
@@ -41,7 +40,6 @@
     void iBegin() {
       ci = conn.begin();
       Ii = IP_address.begin();
-      ti = time_conn.begin();
       si = status.begin();
     }
 
@@ -50,32 +48,29 @@
     void iNext() {
       ci++;
       Ii++;
-      ti++;
       si++;
     }
 
-    void addInfo(void* Conn, char* IP, char* Time, int Status) {
+    void addInfo(void* Conn, char* IP, int Status) {
       conn.push_back(Conn);
-      IP_address.push_back(strDup(IP));
-      time_conn.push_back(strDup(Time));
+      IP_address.push_back(rfb::strDup(IP));
       status.push_back(Status);
     }
 
-    void iGetCharInfo(char* buf[3]) {
+    void iGetCharInfo(char* buf[2]) {
       buf[0] = *Ii;
-      buf[1] = *ti;
       switch (*si) {
       case 0:
-        buf[2] = strDup("Full control");
+        buf[1] = rfb::strDup("Full control");
         break;
       case 1:
-        buf[2] = strDup("View only");
+        buf[1] = rfb::strDup("View only");
         break;
       case 2:
-        buf[2] = strDup("Stop updating");
+        buf[1] = rfb::strDup("Stop updating");
         break;
       default:
-        buf[2] = strDup("Unknown");
+        buf[1] = rfb::strDup("Unknown");
       }
     }
 
@@ -95,9 +90,9 @@
     }
 
     void iAdd (ListConnInfo* InputList) {
-      char* buf[3];
+      char* buf[2];
       InputList->iGetCharInfo(buf);
-      addInfo(InputList->iGetConn(), buf[0], buf[1], InputList->iGetStatus());
+      addInfo(InputList->iGetConn(), buf[0], InputList->iGetStatus());
     }
 
     void setDisable(bool disable) {disableClients = disable;}
@@ -113,11 +108,9 @@
   private:
     std::list<void*> conn;
     std::list<char*> IP_address;
-    std::list<char*> time_conn;
     std::list<int> status;
     std::list<void*>::iterator ci;
     std::list<char*>::iterator Ii;
-    std::list<char*>::iterator ti;
     std::list<int>::iterator si;
     bool disableClients;
   };
diff --git a/win/winvnc/STrayIcon.cxx b/win/winvnc/STrayIcon.cxx
index 05a38d6..a90819d 100644
--- a/win/winvnc/STrayIcon.cxx
+++ b/win/winvnc/STrayIcon.cxx
@@ -184,7 +184,7 @@
         case 2:
           return thread.server.disconnectClients("IPC disconnect") ? 1 : 0;
         case 3:
-          thread.server.setClientsStatus((rfb::ListConnInfo *)command->lpData);
+          thread.server.setClientsStatus(&CPanel->ListConnStatus);
         case 4:
           thread.server.getClientsInfo(&LCInfo);
           CPanel->UpdateListView(&LCInfo);
@@ -230,7 +230,7 @@
   LaunchProcess vncConnect;
   STrayIconThread& thread;
   ControlPanel * CPanel;
-  rfb::ListConnInfo LCInfo;
+  ListConnInfo LCInfo;
 };
 
 
diff --git a/win/winvnc/VNCServerService.cxx b/win/winvnc/VNCServerService.cxx
index 5656de0..f5a4dba 100644
--- a/win/winvnc/VNCServerService.cxx
+++ b/win/winvnc/VNCServerService.cxx
@@ -19,6 +19,7 @@
 // -=- WinVNC Version 4.0 Service-Mode implementation
 
 #include <winvnc/VNCServerService.h>
+#include <rfb/LogWriter.h>
 #include <rfb_win32/TsSessions.h>
 #include <rfb_win32/ModuleFileName.h>
 #include <windows.h>
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index 9f6a954..03b1bca 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -20,6 +20,7 @@
 
 #include <winvnc/VNCServerWin32.h>
 #include <winvnc/resource.h>
+#include <winvnc/ListConnInfo.h>
 #include <winvnc/STrayIcon.h>
 
 #include <os/Mutex.h>
@@ -71,9 +72,7 @@
 
   // Initialise the desktop
   desktop.setStatusLocation(&isDesktopStarted);
-
-  // Initialise the VNC server
-  vncServer.setQueryConnectionHandler(this);
+  desktop.setQueryConnectionHandler(this);
 
   // Register the desktop's event to be handled
   sockMgr.addEvent(desktop.getUpdateEvent(), &desktop);
@@ -241,27 +240,27 @@
   return false;
 }
 
-bool VNCServerWin32::getClientsInfo(rfb::ListConnInfo* LCInfo) {
+bool VNCServerWin32::getClientsInfo(ListConnInfo* LCInfo) {
   return queueCommand(GetClientsInfo, LCInfo, 0);
 }
 
-bool VNCServerWin32::setClientsStatus(rfb::ListConnInfo* LCInfo) {
+bool VNCServerWin32::setClientsStatus(ListConnInfo* LCInfo) {
   return queueCommand(SetClientsStatus, LCInfo, 0);
 }
 
-VNCServerST::queryResult VNCServerWin32::queryConnection(network::Socket* sock,
-                                            const char* userName,
-                                            char** reason)
+void VNCServerWin32::queryConnection(network::Socket* sock,
+                                     const char* userName)
 {
-  if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn())
-    return VNCServerST::ACCEPT;
+  if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn()) {
+    vncServer.approveConnection(sock, true, NULL);
+    return;
+  }
   if (queryConnectDialog) {
-    *reason = rfb::strDup("Another connection is currently being queried.");
-    return VNCServerST::REJECT;
+    vncServer.approveConnection(sock, false, "Another connection is currently being queried.");
+    return;
   }
   queryConnectDialog = new QueryConnectDialog(sock, userName, this);
   queryConnectDialog->startDialog();
-  return VNCServerST::PENDING;
 }
 
 void VNCServerWin32::queryConnectionComplete() {
@@ -309,10 +308,10 @@
       sockMgr.addSocket((network::Socket*)commandData, &vncServer);
       break;
   case GetClientsInfo:
-    vncServer.getConnInfo((ListConnInfo*)commandData); 
+    getConnInfo((ListConnInfo*)commandData);
     break;
   case SetClientsStatus:
-    vncServer.setConnStatus((ListConnInfo*)commandData); 
+    setConnStatus((ListConnInfo*)commandData);
     break;
 
     case QueryConnectionComplete:
@@ -341,3 +340,82 @@
   }
 }
 
+void VNCServerWin32::getConnInfo(ListConnInfo * listConn)
+{
+  std::list<network::Socket*> sockets;
+  std::list<network::Socket*>::iterator i;
+
+  listConn->Clear();
+  listConn->setDisable(sockMgr.getDisable(&vncServer));
+
+  vncServer.getSockets(&sockets);
+
+  for (i = sockets.begin(); i != sockets.end(); i++) {
+    rfb::SConnection* conn;
+    int status;
+
+    conn = vncServer.getConnection(*i);
+    if (!conn)
+      continue;
+
+    if (conn->accessCheck(rfb::SConnection::AccessPtrEvents |
+                          rfb::SConnection::AccessKeyEvents |
+                          rfb::SConnection::AccessView))
+      status = 0;
+    else if (conn->accessCheck(rfb::SConnection::AccessView))
+      status = 1;
+    else
+      status = 2;
+
+    listConn->addInfo((void*)(*i), (*i)->getPeerAddress(), status);
+  }
+}
+
+void VNCServerWin32::setConnStatus(ListConnInfo* listConn)
+{
+  sockMgr.setDisable(&vncServer, listConn->getDisable());
+
+  if (listConn->Empty())
+    return;
+
+  for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
+    network::Socket* sock;
+    rfb::SConnection* conn;
+    int status;
+
+    sock = (network::Socket*)listConn->iGetConn();
+
+    conn = vncServer.getConnection(sock);
+    if (!conn)
+      continue;
+
+    status = listConn->iGetStatus();
+    if (status == 3) {
+      conn->close(0);
+    } else {
+      rfb::SConnection::AccessRights ar;
+
+      ar = rfb::SConnection::AccessDefault;
+
+      switch (status) {
+      case 0:
+        ar |= rfb::SConnection::AccessPtrEvents |
+              rfb::SConnection::AccessKeyEvents |
+              rfb::SConnection::AccessView;
+        break;
+      case 1:
+        ar |= rfb::SConnection::AccessView;
+        ar &= ~(rfb::SConnection::AccessPtrEvents |
+                rfb::SConnection::AccessKeyEvents);
+        break;
+      case 2:
+        ar &= ~(rfb::SConnection::AccessPtrEvents |
+                rfb::SConnection::AccessKeyEvents |
+                rfb::SConnection::AccessView);
+        break;
+      }
+      conn->setAccessRights(ar);
+      conn->framebufferUpdateRequest(vncServer.getPixelBuffer()->getRect(), false);
+    }
+  }
+}
diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h
index 271cb76..1a73782 100644
--- a/win/winvnc/VNCServerWin32.h
+++ b/win/winvnc/VNCServerWin32.h
@@ -37,9 +37,10 @@
 
 namespace winvnc {
 
+  class ListConnInfo;
   class STrayIconThread;
 
-  class VNCServerWin32 : rfb::VNCServerST::QueryConnectionHandler,
+  class VNCServerWin32 : rfb::win32::QueryConnectionHandler,
                          rfb::win32::SocketManager::AddressChangeNotifier,
                          rfb::win32::RegConfig::Callback,
                          rfb::win32::EventHandler {
@@ -73,17 +74,16 @@
     // Where to read the configuration settings from
     static const TCHAR* RegConfigPath;
 
-    bool getClientsInfo(rfb::ListConnInfo* LCInfo);
+    bool getClientsInfo(ListConnInfo* LCInfo);
 
-    bool setClientsStatus(rfb::ListConnInfo* LCInfo);
+    bool setClientsStatus(ListConnInfo* LCInfo);
 
   protected:
-    // VNCServerST::QueryConnectionHandler interface
+    // QueryConnectionHandler interface
     // Callback used to prompt user to accept or reject a connection.
     // CALLBACK IN VNCServerST "HOST" THREAD
-    virtual rfb::VNCServerST::queryResult queryConnection(network::Socket* sock,
-                                                          const char* userName,
-                                                          char** reason);
+    virtual void queryConnection(network::Socket* sock,
+                                 const char* userName);
 
     // SocketManager::AddressChangeNotifier interface
     // Used to keep tray icon up to date
@@ -97,6 +97,9 @@
     // Used to perform queued commands
     virtual void processEvent(HANDLE event);
 
+    void getConnInfo(ListConnInfo * listConn);
+    void setConnStatus(ListConnInfo* listConn);
+
   protected:
     // Perform a particular internal function in the server thread
     typedef enum {NoCommand, DisconnectClients, AddClient, QueryConnectionComplete, SetClientsStatus, GetClientsInfo} Command;