The "rfb" library merged with VNC 4.1.1 code.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@522 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/rfb/Blacklist.cxx b/rfb/Blacklist.cxx
index 4c4f95b..4590bef 100644
--- a/rfb/Blacklist.cxx
+++ b/rfb/Blacklist.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Blacklist.h b/rfb/Blacklist.h
index 4df7ec8..0eb3846 100644
--- a/rfb/Blacklist.h
+++ b/rfb/Blacklist.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/CConnection.cxx b/rfb/CConnection.cxx
index c6a3eed..36778f0 100644
--- a/rfb/CConnection.cxx
+++ b/rfb/CConnection.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -44,10 +44,6 @@
   deleteReaderAndWriter();
 }
 
-void CConnection::setServerName(const char* serverName_) {
-  serverName.buf = strDup(serverName_);
-}
-
 void CConnection::deleteReaderAndWriter()
 {
   delete reader_;
@@ -207,10 +203,7 @@
 void CConnection::processSecurityMsg()
 {
   vlog.debug("processing security message");
-  bool done;
-  if (!security->processMsg(this, &done))
-    throwAuthFailureException();
-  if (done) {
+  if (security->processMsg(this)) {
     state_ = RFBSTATE_SECURITY_RESULT;
     processSecurityResultMsg();
   }
@@ -229,17 +222,23 @@
   switch (result) {
   case secResultOK:
     securityCompleted();
-    break;
+    return;
   case secResultFailed:
     vlog.debug("auth failed");
-    throwAuthFailureException();
+    break;
   case secResultTooMany:
     vlog.debug("auth failed - too many tries");
-    throwAuthFailureException();
+    break;
   default:
-    vlog.error("unknown security result");
-    throwAuthFailureException();
-  };
+    throw Exception("Unknown security result from server");
+  }
+  CharArray reason;
+  if (cp.beforeVersion(3,8))
+    reason.buf = strDup("Authentication failure");
+  else
+    reason.buf = is->readString();
+  state_ = RFBSTATE_INVALID;
+  throw AuthFailureException(reason.buf);
 }
 
 void CConnection::processInitMsg()
@@ -248,20 +247,6 @@
   reader_->readServerInit();
 }
 
-void CConnection::throwAuthFailureException()
-{
-  CharArray reason;
-  vlog.debug("state=%d, ver=%d.%d", state(), cp.majorVersion, cp.minorVersion);
-  if (state()==RFBSTATE_SECURITY_RESULT && !cp.beforeVersion(3,8)) {
-    reason.buf = is->readString();
-  } else {
-    reason.buf = strDup("Authentication failure");
-  }
-  state_ = RFBSTATE_INVALID;
-  vlog.error(reason.buf);
-  throw AuthFailureException(reason.buf);
-}
-
 void CConnection::throwConnFailedException()
 {
   state_ = RFBSTATE_INVALID;
diff --git a/rfb/CConnection.h b/rfb/CConnection.h
index 480fca3..79110eb 100644
--- a/rfb/CConnection.h
+++ b/rfb/CConnection.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -41,11 +41,14 @@
     CConnection();
     virtual ~CConnection();
 
-    // ***
-    void setServerName(const char* serverName_);
-
     // Methods to initialise the connection
 
+    // setServerName() is used to provide a unique(ish) name for the server to
+    // which we are connected.  This might be the result of getPeerEndpoint on
+    // a TcpSocket, for example, or a host specified by DNS name & port.
+    // The serverName is used when verifying the Identity of a host (see RA2).
+    void setServerName(const char* name_) { serverName.replaceBuf(strDup(name_)); }
+
     // setStreams() sets the streams to be used for the connection.  These must
     // be set before initialiseProtocol() and processMsg() are called.  The
     // CSecurity object may call setStreams() again to provide alternative
@@ -129,7 +132,9 @@
     rdr::InStream* getInStream() { return is; }
     rdr::OutStream* getOutStream() { return os; }
 
-    char* getServerName() {return strDup(serverName.buf);}
+    // Access method used by SSecurity implementations that can verify servers'
+    // Identities, to determine the unique(ish) name of the server.
+    const char* getServerName() const { return serverName.buf; }
 
     enum stateEnum {
       RFBSTATE_UNINITIALISED,
diff --git a/rfb/CMsgHandler.cxx b/rfb/CMsgHandler.cxx
index cc7c11f..bbc1176 100644
--- a/rfb/CMsgHandler.cxx
+++ b/rfb/CMsgHandler.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -34,7 +34,7 @@
   cp.height = height;
 }
 
-void CMsgHandler::setCursor(const Point& hotspot, const Point& size, void* data, void* mask)
+void CMsgHandler::setCursor(int w, int h, const Point& hotspot, void* data, void* mask)
 {
 }
 
diff --git a/rfb/CMsgHandler.h b/rfb/CMsgHandler.h
index 29218c8..6c86df0 100644
--- a/rfb/CMsgHandler.h
+++ b/rfb/CMsgHandler.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -36,8 +36,15 @@
     CMsgHandler();
     virtual ~CMsgHandler();
 
+    // The following methods are called as corresponding messages are read.  A
+    // derived class should override these methods as desired.  Note that for
+    // the setDesktopSize(), setPixelFormat() and setName() methods, a derived
+    // class should call on to CMsgHandler's methods to set the members of cp
+    // appropriately.
+
     virtual void setDesktopSize(int w, int h);
-    virtual void setCursor(const Point& hotspot, const Point& size, void* data, void* mask);
+    virtual void setCursor(int width, int height, const Point& hotspot,
+                           void* data, void* mask);
     virtual void setPixelFormat(const PixelFormat& pf);
     virtual void setName(const char* name);
     virtual void serverInit();
diff --git a/rfb/CMsgReader.cxx b/rfb/CMsgReader.cxx
index 46973eb..38547c0 100644
--- a/rfb/CMsgReader.cxx
+++ b/rfb/CMsgReader.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -41,10 +41,6 @@
   delete [] imageBuf;
 }
 
-void CMsgReader::endMsg()
-{
-}
-
 void CMsgReader::readSetColourMapEntries()
 {
   is->skip(1);
@@ -53,13 +49,11 @@
   rdr::U16Array rgbs(nColours * 3);
   for (int i = 0; i < nColours * 3; i++)
     rgbs.buf[i] = is->readU16();
-  endMsg();
   handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
 }
 
 void CMsgReader::readBell()
 {
-  endMsg();
   handler->bell();
 }
 
@@ -75,19 +69,16 @@
   CharArray ca(len+1);
   ca.buf[len] = 0;
   is->readBytes(ca.buf, len);
-  endMsg();
   handler->serverCutText(ca.buf, len);
 }
 
 void CMsgReader::readFramebufferUpdateStart()
 {
-  endMsg();
   handler->framebufferUpdateStart();
 }
 
 void CMsgReader::readFramebufferUpdateEnd()
 {
-  endMsg();
   handler->framebufferUpdateEnd();
 }
 
@@ -128,17 +119,17 @@
   handler->copyRect(r, srcX, srcY);
 }
 
-void CMsgReader::readSetCursor(const Point& hotspot, const Point& size)
+void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
 {
-  int data_len = size.x * size.y * (handler->cp.pf().bpp/8);
-  int mask_len = ((size.x+7)/8) * size.y;
+  int data_len = width * height * (handler->cp.pf().bpp/8);
+  int mask_len = ((width+7)/8) * height;
   rdr::U8Array data(data_len);
   rdr::U8Array mask(mask_len);
 
   is->readBytes(data.buf, data_len);
   is->readBytes(mask.buf, mask_len);
 
-  handler->setCursor(hotspot, size, data.buf, mask.buf);
+  handler->setCursor(width, height, hotspot, data.buf, mask.buf);
 }
 
 rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels)
diff --git a/rfb/CMsgReader.h b/rfb/CMsgReader.h
index 8b4638c..7a611fc 100644
--- a/rfb/CMsgReader.h
+++ b/rfb/CMsgReader.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -53,15 +53,13 @@
     virtual void readBell();
     virtual void readServerCutText();
 
-    virtual void endMsg();
-
     virtual void readFramebufferUpdateStart();
     virtual void readFramebufferUpdateEnd();
     virtual void readRect(const Rect& r, unsigned int encoding);
 
     virtual void readCopyRect(const Rect& r);
 
-    virtual void readSetCursor(const Point& hotspot, const Point& size);
+    virtual void readSetCursor(int width, int height, const Point& hotspot);
 
     CMsgReader(CMsgHandler* handler, rdr::InStream* is);
 
diff --git a/rfb/CMsgReaderV3.cxx b/rfb/CMsgReaderV3.cxx
index 9370804..d0cfc89 100644
--- a/rfb/CMsgReaderV3.cxx
+++ b/rfb/CMsgReaderV3.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,6 +21,7 @@
 #include <rdr/InStream.h>
 #include <rfb/CMsgReaderV3.h>
 #include <rfb/CMsgHandler.h>
+#include <rfb/util.h>
 
 using namespace rfb;
 
@@ -41,10 +42,8 @@
   PixelFormat pf;
   pf.read(is);
   handler->setPixelFormat(pf);
-  char* name = is->readString();
-  handler->setName(name);
-  delete [] name;
-  endMsg();
+  CharArray name(is->readString());
+  handler->setName(name.buf);
   handler->serverInit();
 }
 
@@ -85,7 +84,7 @@
       handler->setDesktopSize(w, h);
       break;
     case pseudoEncodingCursor:
-      readSetCursor(Point(x, y), Point(w, h));
+      readSetCursor(w, h, Point(x,y));
       break;
     case pseudoEncodingLastRect:
       nUpdateRectsLeft = 1;     // this rectangle is the last one
@@ -104,6 +103,5 @@
 {
   is->skip(1);
   nUpdateRectsLeft = is->readU16();
-  endMsg();
   handler->framebufferUpdateStart();
 }
diff --git a/rfb/CMsgReaderV3.h b/rfb/CMsgReaderV3.h
index 93c8c6a..689bb65 100644
--- a/rfb/CMsgReaderV3.h
+++ b/rfb/CMsgReaderV3.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/CMsgWriter.cxx b/rfb/CMsgWriter.cxx
index fb272c4..cdfb4e5 100644
--- a/rfb/CMsgWriter.cxx
+++ b/rfb/CMsgWriter.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -96,7 +96,7 @@
 }
 
 
-void CMsgWriter::writeKeyEvent(rdr::U32 key, bool down)
+void CMsgWriter::keyEvent(rdr::U32 key, bool down)
 {
   startMsg(msgTypeKeyEvent);
   os->writeU8(down);
@@ -106,22 +106,23 @@
 }
 
 
-void CMsgWriter::writePointerEvent(int x, int y, int buttonMask)
+void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
 {
-  if (x < 0) x = 0;
-  if (y < 0) y = 0;
-  if (x >= cp->width) x = cp->width - 1;
-  if (y >= cp->height) y = cp->height - 1;
+  Point p(pos);
+  if (p.x < 0) p.x = 0;
+  if (p.y < 0) p.y = 0;
+  if (p.x >= cp->width) p.x = cp->width - 1;
+  if (p.y >= cp->height) p.y = cp->height - 1;
 
   startMsg(msgTypePointerEvent);
   os->writeU8(buttonMask);
-  os->writeU16(x);
-  os->writeU16(y);
+  os->writeU16(p.x);
+  os->writeU16(p.y);
   endMsg();
 }
 
 
-void CMsgWriter::writeClientCutText(const char* str, int len)
+void CMsgWriter::clientCutText(const char* str, int len)
 {
   startMsg(msgTypeClientCutText);
   os->pad(3);
@@ -129,8 +130,3 @@
   os->writeBytes(str, len);
   endMsg();
 }
-
-void CMsgWriter::setOutStream(rdr::OutStream* os_)
-{
-  os = os_;
-}
diff --git a/rfb/CMsgWriter.h b/rfb/CMsgWriter.h
index 8d6e373..19be8df 100644
--- a/rfb/CMsgWriter.h
+++ b/rfb/CMsgWriter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -22,7 +22,7 @@
 #ifndef __RFB_CMSGWRITER_H__
 #define __RFB_CMSGWRITER_H__
 
-#include <rdr/types.h>
+#include <rfb/InputHandler.h>
 
 namespace rdr { class OutStream; }
 
@@ -32,24 +32,25 @@
   class ConnParams;
   struct Rect;
 
-  class CMsgWriter {
+  class CMsgWriter : public InputHandler {
   public:
     virtual ~CMsgWriter();
 
+    // CMsgWriter abstract interface methods
     virtual void writeClientInit(bool shared)=0;
+    virtual void startMsg(int type)=0;
+    virtual void endMsg()=0;
 
+    // CMsgWriter implemented methods
     virtual void writeSetPixelFormat(const PixelFormat& pf);
     virtual void writeSetEncodings(int nEncodings, rdr::U32* encodings);
     virtual void writeSetEncodings(int preferredEncoding, bool useCopyRect);
     virtual void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
-    virtual void writeKeyEvent(rdr::U32 key, bool down);
-    virtual void writePointerEvent(int x, int y, int buttonMask);
-    virtual void writeClientCutText(const char* str, int len);
 
-    virtual void startMsg(int type)=0;
-    virtual void endMsg()=0;
-
-    virtual void setOutStream(rdr::OutStream* os);
+    // InputHandler implementation
+    virtual void keyEvent(rdr::U32 key, bool down);
+    virtual void pointerEvent(const Point& pos, int buttonMask);
+    virtual void clientCutText(const char* str, int len);
 
     ConnParams* getConnParams() { return cp; }
     rdr::OutStream* getOutStream() { return os; }
diff --git a/rfb/CMsgWriterV3.cxx b/rfb/CMsgWriterV3.cxx
index a6ad237..a980795 100644
--- a/rfb/CMsgWriterV3.cxx
+++ b/rfb/CMsgWriterV3.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/CMsgWriterV3.h b/rfb/CMsgWriterV3.h
index 0cf6157..0b2f9af 100644
--- a/rfb/CMsgWriterV3.h
+++ b/rfb/CMsgWriterV3.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/CSecurity.h b/rfb/CSecurity.h
index 639d550..90a01d7 100644
--- a/rfb/CSecurity.h
+++ b/rfb/CSecurity.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -18,10 +18,14 @@
 //
 // CSecurity - class on the client side for handling security handshaking.  A
 // derived class for a particular security type overrides the processMsg()
-// method.  processMsg() is called first when the security type has been
-// decided on, and will keep being called whenever there is data to read from
-// the server until either it returns false, indicating authentication/security
-// failure, or it returns with done set to true, to indicate success.
+// method.
+
+// processMsg() is called first when the security type has been decided on, and
+// will keep being called whenever there is data to read from the server.  It
+// should return false when it needs more data, or true when the security
+// handshaking is over and we are now waiting for the SecurityResult message
+// from the server.  In the event of failure a suitable exception should be
+// thrown.
 //
 // Note that the first time processMsg() is called, there is no guarantee that
 // there is any data to read from the CConnection's InStream, but subsequent
@@ -39,7 +43,7 @@
   class CSecurity {
   public:
     virtual ~CSecurity() {}
-    virtual bool processMsg(CConnection* cc, bool* done)=0;
+    virtual bool processMsg(CConnection* cc)=0;
     virtual void destroy() { delete this; }
     virtual int getType() const = 0;
     virtual const char* description() const = 0;
diff --git a/rfb/CSecurityNone.h b/rfb/CSecurityNone.h
index 23b36ce..54c1016 100644
--- a/rfb/CSecurityNone.h
+++ b/rfb/CSecurityNone.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -28,9 +28,7 @@
 
   class CSecurityNone : public CSecurity {
   public:
-    virtual bool processMsg(CConnection* cc, bool* done) {
-      *done = true; return true;
-    }
+    virtual bool processMsg(CConnection* cc) { return true; }
     virtual int getType() const {return secTypeNone;}
     virtual const char* description() const {return "No Encryption";}
   };
diff --git a/rfb/CSecurityVncAuth.cxx b/rfb/CSecurityVncAuth.cxx
index 3d6c87c..ba5a30b 100644
--- a/rfb/CSecurityVncAuth.cxx
+++ b/rfb/CSecurityVncAuth.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -18,19 +18,25 @@
 //
 // CSecurityVncAuth
 //
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
 
 #include <string.h>
 #include <stdio.h>
 #include <rfb/CConnection.h>
 #include <rfb/UserPasswdGetter.h>
-#include <rfb/vncAuth.h>
+#include <rfb/Password.h>
 #include <rfb/CSecurityVncAuth.h>
-#include <rfb/LogWriter.h>
 #include <rfb/util.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+
 
 using namespace rfb;
 
-static LogWriter vlog("VncAuth");
+static const int vncAuthChallengeSize = 16;
+
 
 CSecurityVncAuth::CSecurityVncAuth(UserPasswdGetter* upg_)
   : upg(upg_)
@@ -41,23 +47,28 @@
 {
 }
 
-bool CSecurityVncAuth::processMsg(CConnection* cc, bool* done)
+bool CSecurityVncAuth::processMsg(CConnection* cc)
 {
-  *done = false;
   rdr::InStream* is = cc->getInStream();
   rdr::OutStream* os = cc->getOutStream();
 
+  // Read the challenge & obtain the user's password
   rdr::U8 challenge[vncAuthChallengeSize];
   is->readBytes(challenge, vncAuthChallengeSize);
-  CharArray passwd;
-  if (!upg->getUserPasswd(0, &passwd.buf)) {
-    vlog.error("Getting password failed");
-    return false;
-  }
-  vncAuthEncryptChallenge(challenge, passwd.buf);
-  memset(passwd.buf, 0, strlen(passwd.buf));
+  PlainPasswd passwd;
+  upg->getUserPasswd(0, &passwd.buf);
+
+  // Calculate the correct response
+  rdr::U8 key[8];
+  int pwdLen = strlen(passwd.buf);
+  for (int i=0; i<8; i++)
+    key[i] = i<pwdLen ? passwd.buf[i] : 0;
+  deskey(key, EN0);
+  for (int j = 0; j < vncAuthChallengeSize; j += 8)
+    des(challenge+j, challenge+j);
+
+  // Return the response to the server
   os->writeBytes(challenge, vncAuthChallengeSize);
   os->flush();
-  *done = true;
   return true;
 }
diff --git a/rfb/CSecurityVncAuth.h b/rfb/CSecurityVncAuth.h
index bfa40b3..8d38d87 100644
--- a/rfb/CSecurityVncAuth.h
+++ b/rfb/CSecurityVncAuth.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -20,7 +20,6 @@
 
 #include <rfb/CSecurity.h>
 #include <rfb/secTypes.h>
-#include <rfb/vncAuth.h>
 
 namespace rfb {
 
@@ -30,7 +29,7 @@
   public:
     CSecurityVncAuth(UserPasswdGetter* pg);
     virtual ~CSecurityVncAuth();
-    virtual bool processMsg(CConnection* cc, bool* done);
+    virtual bool processMsg(CConnection* cc);
     virtual int getType() const {return secTypeVncAuth;};
     virtual const char* description() const {return "No Encryption";}
   private:
diff --git a/rfb/ColourCube.h b/rfb/ColourCube.h
index 904256c..b83cbba 100644
--- a/rfb/ColourCube.h
+++ b/rfb/ColourCube.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/ColourMap.h b/rfb/ColourMap.h
index ee7783d..da6cb12 100644
--- a/rfb/ColourMap.h
+++ b/rfb/ColourMap.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/ComparingUpdateTracker.cxx b/rfb/ComparingUpdateTracker.cxx
index 0b548a6..ce3d68a 100644
--- a/rfb/ComparingUpdateTracker.cxx
+++ b/rfb/ComparingUpdateTracker.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -24,8 +24,7 @@
 using namespace rfb;
 
 ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
-  : SimpleUpdateTracker(true), fb(buffer),
-    oldFb(fb->getPF(), 0, 0), firstCompare(true)
+  : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
 {
     changed.assign_union(fb->getRect());
 }
@@ -35,19 +34,6 @@
 }
 
 
-void ComparingUpdateTracker::flush_update(UpdateInfo* info,
-                                          const Region& cliprgn, int maxArea)
-{
-  throw rfb::Exception("flush_update(UpdateInfo*) not implemented");
-}
-
-void ComparingUpdateTracker::flush_update(UpdateTracker &ut,
-                                          const Region &cliprgn)
-{
-  throw rfb::Exception("flush_update(UpdateTracker&) not implemented");
-}
-
-
 #define BLOCK_SIZE 16
 
 void ComparingUpdateTracker::compare()
@@ -60,7 +46,7 @@
     // since in effect the entire framebuffer has changed.
     oldFb.setSize(fb->width(), fb->height());
     for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
-      Rect pos(0, y, fb->width(), vncmin(fb->height(), y+BLOCK_SIZE));
+      Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
       int srcStride;
       const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
       oldFb.imageRect(pos, srcData, srcStride);
@@ -100,20 +86,20 @@
   for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
   {
     // Get a strip of the source buffer
-    Rect pos(r.tl.x, blockTop, r.br.x, vncmin(r.br.y, blockTop+BLOCK_SIZE));
+    Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
     int fbStride;
     const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
     int newStrideBytes = fbStride * bytesPerPixel;
 
     rdr::U8* oldBlockPtr = oldData;
-    int blockBottom = vncmin(blockTop+BLOCK_SIZE, r.br.y);
+    int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
 
     for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
     {
       const rdr::U8* newPtr = newBlockPtr;
       rdr::U8* oldPtr = oldBlockPtr;
 
-      int blockRight = vncmin(blockLeft+BLOCK_SIZE, r.br.x);
+      int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
       int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
 
       for (int y = blockTop; y < blockBottom; y++)
diff --git a/rfb/ComparingUpdateTracker.h b/rfb/ComparingUpdateTracker.h
index bec93d1..5d2e5ed 100644
--- a/rfb/ComparingUpdateTracker.h
+++ b/rfb/ComparingUpdateTracker.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -32,10 +32,6 @@
     // as appropriate.
 
     virtual void compare();
-
-    virtual void flush_update(UpdateInfo* info, const Region& cliprgn,
-                              int maxArea);
-    virtual void flush_update(UpdateTracker &info, const Region &cliprgn);
   private:
     void compareRect(const Rect& r, Region* newchanged);
     PixelBuffer* fb;
diff --git a/rfb/Configuration.cxx b/rfb/Configuration.cxx
index a08260d..9ebc20a 100644
--- a/rfb/Configuration.cxx
+++ b/rfb/Configuration.cxx
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
- *    
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -32,15 +32,19 @@
 #include <rfb/Configuration.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Exception.h>
-
-#ifdef WIN32
-
-// Under Win32, we use these routines from several threads,
-// so we must provide suitable locking.
 #include <rfb/Threading.h>
 
-static rfb::Mutex configLock;
-
+#ifdef __RFB_THREADING_IMPL
+// On platforms that support Threading, we use Locks to make getData safe
+#define LOCK_CONFIG Lock l(*configLock())
+rfb::Mutex* configLock_ = 0;
+static rfb::Mutex* configLock() {
+  if (!configLock_)
+    configLock_ = new rfb::Mutex;
+  return configLock_;
+}
+#else
+#define LOCK_CONFIG
 #endif
 
 #include <rdr/HexOutStream.h>
@@ -51,15 +55,47 @@
 static LogWriter vlog("Config");
 
 
-// -=- Configuration
-
-VoidParameter* Configuration::head = 0;
-
-bool Configuration::setParam(const char* n, const char* v, bool immutable) {
-  return setParam(n, strlen(n), v, immutable);
+// -=- The Global Configuration object
+Configuration* Configuration::global_ = 0;
+Configuration* Configuration::global() {
+  if (!global_)
+    global_ = new Configuration("Global");
+  return global_;
 }
 
-bool Configuration::setParam(const char* name, int len,
+
+// -=- Configuration implementation
+
+Configuration::Configuration(const char* name_, Configuration* attachToGroup) 
+: name(strDup(name_)), head(0), _next(0) {
+  if (attachToGroup) {
+    _next = attachToGroup->_next;
+    attachToGroup->_next = this;
+  }
+}
+
+Configuration& Configuration::operator=(const Configuration& src) {
+  VoidParameter* current = head;
+  while (current) {
+    VoidParameter* srcParam = ((Configuration&)src).get(current->getName());
+    if (srcParam) {
+      current->immutable = false;
+      CharArray value(srcParam->getValueStr());
+      vlog.debug("operator=(%s, %s)", current->getName(), value.buf);
+      current->setParam(value.buf);
+    }
+    current = current->_next;
+  }
+  if (_next)
+    *_next=src;
+  return *this;
+}
+
+bool Configuration::set(const char* n, const char* v, bool immutable) {
+  return set(n, strlen(n), v, immutable);
+}
+
+bool Configuration::set(const char* name, int len,
                              const char* val, bool immutable)
 {
   VoidParameter* current = head;
@@ -75,10 +111,10 @@
     }
     current = current->_next;
   }
-  return false;
+  return _next ? _next->set(name, len, val, immutable) : false;
 }
 
-bool Configuration::setParam(const char* config, bool immutable) {
+bool Configuration::set(const char* config, bool immutable) {
   bool hyphen = false;
   if (config[0] == '-') {
     hyphen = true;
@@ -87,7 +123,7 @@
   }
   const char* equal = strchr(config, '=');
   if (equal) {
-    return setParam(config, equal-config, equal+1, immutable);
+    return set(config, equal-config, equal+1, immutable);
   } else if (hyphen) {
     VoidParameter* current = head;
     while (current) {
@@ -101,10 +137,10 @@
       current = current->_next;
     }
   }    
-  return false;
+  return _next ? _next->set(config, immutable) : false;
 }
 
-VoidParameter* Configuration::getParam(const char* param)
+VoidParameter* Configuration::get(const char* param)
 {
   VoidParameter* current = head;
   while (current) {
@@ -112,11 +148,13 @@
       return current;
     current = current->_next;
   }
-  return 0;
+  return _next ? _next->get(param) : 0;
 }
 
-void Configuration::listParams(int width, int nameWidth) {
+void Configuration::list(int width, int nameWidth) {
   VoidParameter* current = head;
+
+  fprintf(stderr, "%s Parameters:\n", name.buf);
   while (current) {
     char* def_str = current->getDefaultStr();
     const char* desc = current->getDescription();
@@ -150,14 +188,20 @@
     }
     current = current->_next;
   }
+
+  if (_next)
+    _next->list(width, nameWidth);
 }
 
+
 // -=- VoidParameter
 
-VoidParameter::VoidParameter(const char* name_, const char* desc_)
+VoidParameter::VoidParameter(const char* name_, const char* desc_, Configuration* conf)
   : immutable(false), _hasBeenSet(false), name(name_), description(desc_) {
-  _next = Configuration::head;
-  Configuration::head = this;
+  if (!conf)
+    conf = Configuration::global();
+  _next = conf->head;
+  conf->head = this;
 }
 
 VoidParameter::~VoidParameter() {
@@ -200,8 +244,8 @@
 // -=- AliasParameter
 
 AliasParameter::AliasParameter(const char* name_, const char* desc_,
-                               VoidParameter* param_)
-  : VoidParameter(name_, desc_), param(param_) {
+                               VoidParameter* param_, Configuration* conf)
+  : VoidParameter(name_, desc_, conf), param(param_) {
 }
 
 bool
@@ -235,8 +279,8 @@
 
 // -=- BoolParameter
 
-BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v)
-: VoidParameter(name_, desc_), value(v), def_value(v) {
+BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf)
+: VoidParameter(name_, desc_, conf), value(v), def_value(v) {
 }
 
 bool
@@ -271,15 +315,11 @@
 
 char*
 BoolParameter::getDefaultStr() const {
-  char* result = new char[8];
-  sprintf(result, "%d", (int)def_value);
-  return result;
+  return strDup(def_value ? "1" : "0");
 }
 
 char* BoolParameter::getValueStr() const {
-  char* result = new char[8];
-  sprintf(result, "%d", (int)value);
-  return result;
+  return strDup(value ? "1" : "0");
 }
 
 bool BoolParameter::isBool() const {
@@ -292,15 +332,21 @@
 
 // -=- IntParameter
 
-IntParameter::IntParameter(const char* name_, const char* desc_, int v)
-: VoidParameter(name_, desc_), value(v), def_value(v) {
+IntParameter::IntParameter(const char* name_, const char* desc_, int v,
+                           int minValue_, int maxValue_, Configuration* conf)
+  : VoidParameter(name_, desc_, conf), value(v), def_value(v),
+    minValue(minValue_), maxValue(maxValue_)
+{
 }
 
 bool
 IntParameter::setParam(const char* v) {
   if (immutable) return true;
   vlog.debug("set %s(Int) to %s", getName(), v);
-  value = atoi(v);
+  int i = atoi(v);
+  if (i < minValue || i > maxValue)
+    return false;
+  value = i;
   return true;
 }
 
@@ -308,6 +354,8 @@
 IntParameter::setParam(int v) {
   if (immutable) return true;
   vlog.debug("set %s(Int) to %d", getName(), v);
+  if (v < minValue || v > maxValue)
+    return false;
   value = v;
   return true;
 }
@@ -332,8 +380,8 @@
 // -=- StringParameter
 
 StringParameter::StringParameter(const char* name_, const char* desc_,
-                                 const char* v)
-  : VoidParameter(name_, desc_), value(strDup(v)), def_value(v)
+                                 const char* v, Configuration* conf)
+  : VoidParameter(name_, desc_, conf), value(strDup(v)), def_value(v)
 {
   if (!v) {
     fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
@@ -346,14 +394,12 @@
 }
 
 bool StringParameter::setParam(const char* v) {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   if (immutable) return true;
   if (!v)
     throw rfb::Exception("setParam(<null>) not allowed");
   vlog.debug("set %s(String) to %s", getName(), v);
-  strFree(value);
+  CharArray oldValue(value);
   value = strDup(v);
   return value != 0;
 }
@@ -363,16 +409,14 @@
 }
 
 char* StringParameter::getValueStr() const {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   return strDup(value);
 }
 
 // -=- BinaryParameter
 
-BinaryParameter::BinaryParameter(const char* name_, const char* desc_, const void* v, int l)
-: VoidParameter(name_, desc_), value(0), length(0), def_value((char*)v), def_length(l) {
+BinaryParameter::BinaryParameter(const char* name_, const char* desc_, const void* v, int l, Configuration* conf)
+: VoidParameter(name_, desc_, conf), value(0), length(0), def_value((char*)v), def_length(l) {
   if (l) {
     value = new char[l];
     length = l;
@@ -385,18 +429,14 @@
 }
 
 bool BinaryParameter::setParam(const char* v) {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   if (immutable) return true;
   vlog.debug("set %s(Binary) to %s", getName(), v);
   return rdr::HexInStream::hexStrToBin(v, &value, &length);
 }
 
 void BinaryParameter::setParam(const void* v, int len) {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   if (immutable) return; 
   vlog.debug("set %s(Binary)", getName());
   delete [] value; value = 0;
@@ -412,16 +452,12 @@
 }
 
 char* BinaryParameter::getValueStr() const {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   return rdr::HexOutStream::binToHexStr(value, length);
 }
 
 void BinaryParameter::getData(void** data_, int* length_) const {
-#ifdef WIN32
-  Lock l(configLock);
-#endif
+  LOCK_CONFIG;
   if (length_) *length_ = length;
   if (data_) {
     *data_ = new char[length];
diff --git a/rfb/Configuration.h b/rfb/Configuration.h
index d50c1cb..e3b85b8 100644
--- a/rfb/Configuration.h
+++ b/rfb/Configuration.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -27,38 +27,106 @@
 // Simply defining a new parameter and associating it with a Configuration
 // will allow it to be configured by the user.
 //
-// The Configuration class is used to allow multiple distinct configurations
-// to co-exist at the same time.  A process serving several desktops, for
-// instance, can create a Configuration instance for each, to allow them
-// to be configured independently, from the command-line, registry, etc.
+// If no Configuration is specified when creating a Parameter, then the
+// global Configuration will be assumed.
+//
+// Configurations can be "chained" into groups.  Each group has a root
+// Configuration, a pointer to which should be passed to the constructors
+// of the other group members.  set() and get() operations called on the
+// root will iterate through all of the group's members.
+//
+// NB: On platforms that support Threading, locking is performed to protect
+//     complex parameter types from concurrent access (e.g. strings).
+// NB: NO LOCKING is performed when linking Configurations to groups
+//     or when adding Parameters to Configurations.
 
 #ifndef __RFB_CONFIGURATION_H__
 #define __RFB_CONFIGURATION_H__
 
+#include <rfb/util.h>
+
 namespace rfb {
   class VoidParameter;
+  struct ParameterIterator;
 
   // -=- Configuration
   //     Class used to access parameters.
 
   class Configuration {
   public:
+    // - Create a new Configuration object
+    Configuration(const char* name, Configuration* attachToGroup=0);
+
+    // - Return the buffer containing the Configuration's name
+    const char* getName() const { return name.buf; }
+
+    // - Assignment operator.  For every Parameter in this Configuration's
+    //   group, get()s the corresponding source parameter and copies its
+    //   content.
+    Configuration& operator=(const Configuration& src);
+
     // - Set named parameter to value
-    static bool setParam(const char* param, const char* value, bool immutable=false);
+    bool set(const char* param, const char* value, bool immutable=false);
 
     // - Set parameter to value (separated by "=")
-    static bool setParam(const char* config, bool immutable=false);
+    bool set(const char* config, bool immutable=false);
 
     // - Set named parameter to value, with name truncated at len
-    static bool setParam(const char* name, int len,
-                         const char* val, bool immutable);
+    bool set(const char* name, int len,
+                  const char* val, bool immutable);
 
     // - Get named parameter
-    static VoidParameter* getParam(const char* param);
+    VoidParameter* get(const char* param);
 
-    static void listParams(int width=79, int nameWidth=10);
+    // - List the parameters of this Configuration group
+    void list(int width=79, int nameWidth=10);
 
-    static VoidParameter* head;
+    // - readFromFile
+    //   Read configuration parameters from the specified file.
+    void readFromFile(const char* filename);
+
+    // - writeConfigToFile
+    //   Write a new configuration parameters file, then mv it
+    //   over the old file.
+    void writeToFile(const char* filename);
+
+
+    // - Get the Global Configuration object
+    //   NB: This call does NOT lock the Configuration system.
+    //       ALWAYS ensure that if you have ANY global Parameters,
+    //       then they are defined as global objects, to ensure that
+    //       global() is called when only the main thread is running.
+    static Configuration* global();
+
+    // - Container for process-wide Global parameters
+    static bool setParam(const char* param, const char* value, bool immutable=false) {
+      return global()->set(param, value, immutable);
+    }
+    static bool setParam(const char* config, bool immutable=false) { 
+      return global()->set(config, immutable);
+    }
+    static bool setParam(const char* name, int len,
+      const char* val, bool immutable) {
+      return global()->set(name, len, val, immutable);
+    }
+    static VoidParameter* getParam(const char* param) { return global()->get(param); }
+    static void listParams(int width=79, int nameWidth=10) { global()->list(width, nameWidth); }
+
+  protected:
+    friend class VoidParameter;
+    friend struct ParameterIterator;
+
+    // Name for this Configuration
+    CharArray name;
+
+    // - Pointer to first Parameter in this group
+    VoidParameter* head;
+
+    // Pointer to next Configuration in this group
+    Configuration* _next;
+
+    // The process-wide, Global Configuration object
+    static Configuration* global_;
   };
 
   // -=- VoidParameter
@@ -66,7 +134,7 @@
 
   class VoidParameter {
   public:
-    VoidParameter(const char* name_, const char* desc_);
+    VoidParameter(const char* name_, const char* desc_, Configuration* conf=0);
     virtual  ~VoidParameter();
     const char* getName() const;
     const char* getDescription() const;
@@ -81,8 +149,11 @@
     virtual void setHasBeenSet();
     bool hasBeenSet();
 
-    VoidParameter* _next;
   protected:
+    friend class Configuration;
+    friend struct ParameterIterator;
+
+    VoidParameter* _next;
     bool immutable;
     bool _hasBeenSet;
     const char* name;
@@ -91,7 +162,7 @@
 
   class AliasParameter : public VoidParameter {
   public:
-    AliasParameter(const char* name_, const char* desc_,VoidParameter* param_);
+    AliasParameter(const char* name_, const char* desc_,VoidParameter* param_, Configuration* conf=0);
     virtual bool setParam(const char* value);
     virtual bool setParam();
     virtual char* getDefaultStr() const;
@@ -104,7 +175,7 @@
 
   class BoolParameter : public VoidParameter {
   public:
-    BoolParameter(const char* name_, const char* desc_, bool v);
+    BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf=0);
     virtual bool setParam(const char* value);
     virtual bool setParam();
     virtual void setParam(bool b);
@@ -119,7 +190,8 @@
 
   class IntParameter : public VoidParameter {
   public:
-    IntParameter(const char* name_, const char* desc_, int v);
+    IntParameter(const char* name_, const char* desc_, int v,
+                 int minValue=INT_MIN, int maxValue=INT_MAX, Configuration* conf=0);
     virtual bool setParam(const char* value);
     virtual bool setParam(int v);
     virtual char* getDefaultStr() const;
@@ -128,13 +200,14 @@
   protected:
     int value;
     int def_value;
+    int minValue, maxValue;
   };
 
   class StringParameter : public VoidParameter {
   public:
     // StringParameter contains a null-terminated string, which CANNOT
     // be Null, and so neither can the default value!
-    StringParameter(const char* name_, const char* desc_, const char* v);
+    StringParameter(const char* name_, const char* desc_, const char* v, Configuration* conf=0);
     virtual ~StringParameter();
     virtual bool setParam(const char* value);
     virtual char* getDefaultStr() const;
@@ -150,13 +223,15 @@
 
   class BinaryParameter : public VoidParameter {
   public:
-    BinaryParameter(const char* name_, const char* desc_, const void* v, int l);
+    BinaryParameter(const char* name_, const char* desc_, const void* v, int l, Configuration* conf=0);
     virtual ~BinaryParameter();
     virtual bool setParam(const char* value);
     virtual void setParam(const void* v, int l);
     virtual char* getDefaultStr() const;
     virtual char* getValueStr() const;
 
+    // getData() will return length zero if there is no data
+    // NB: data may be set to zero, OR set to a zero-length buffer
     void getData(void** data, int* length) const;
 
   protected:
@@ -166,6 +241,25 @@
     int def_length;
   };
 
+  // -=- ParameterIterator
+  //     Iterates over all the Parameters in a Configuration group.  The
+  //     current Parameter is accessed via param, the current Configuration
+  //     via config.  The next() method moves on to the next Parameter.
+
+  struct ParameterIterator {
+    ParameterIterator(Configuration* c) : config(c), param(c ? c->head : 0) {}
+    void next() {
+      param = param->_next;
+      while (!param) {
+        config = config->_next;
+        if (!config) break;
+        param = config->head;
+      }
+    }
+    Configuration* config;
+    VoidParameter* param;
+  };
+
 };
 
 #endif // __RFB_CONFIGURATION_H__
diff --git a/rfb/ConnParams.cxx b/rfb/ConnParams.cxx
index 4a8e534..d4ae589 100644
--- a/rfb/ConnParams.cxx
+++ b/rfb/ConnParams.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -27,9 +27,10 @@
 
 ConnParams::ConnParams()
   : majorVersion(0), minorVersion(0), width(0), height(0), useCopyRect(false),
-    supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(false), supportsLastRect(false), 
-    customCompressLevel(false), compressLevel(6), noJpeg(false), qualityLevel(-1), 
-    name_(0), nEncodings_(0), encodings_(0), 
+    supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true),
+    supportsLastRect(false), customCompressLevel(false), compressLevel(6),
+    noJpeg(false), qualityLevel(-1), 
+    name_(0), nEncodings_(0), encodings_(0),
     currentEncoding_(encodingRaw), verStrPos(0)
 {
   setName("");
@@ -88,6 +89,7 @@
   nEncodings_ = nEncodings;
   useCopyRect = false;
   supportsLocalCursor = false;
+  supportsDesktopResize = false;
   supportsLocalXCursor = false;
   supportsLastRect = false;
   customCompressLevel = false;
diff --git a/rfb/ConnParams.h b/rfb/ConnParams.h
index 09e79c2..47e6a5f 100644
--- a/rfb/ConnParams.h
+++ b/rfb/ConnParams.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Cursor.cxx b/rfb/Cursor.cxx
index b50d925..c8dc341 100644
--- a/rfb/Cursor.cxx
+++ b/rfb/Cursor.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -83,6 +83,7 @@
 {
   bool gotPix0 = false;
   bool gotPix1 = false;
+  *pix0 = *pix1 = 0;
   rdr::U8Array source(maskLen());
   memset(source.buf, 0, maskLen());
 
diff --git a/rfb/Cursor.h b/rfb/Cursor.h
index 0f18775..7d94d70 100644
--- a/rfb/Cursor.h
+++ b/rfb/Cursor.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Decoder.cxx b/rfb/Decoder.cxx
index e04cbf9..b6e4fd5 100644
--- a/rfb/Decoder.cxx
+++ b/rfb/Decoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Decoder.h b/rfb/Decoder.h
index 914b26a..3fdba53 100644
--- a/rfb/Decoder.h
+++ b/rfb/Decoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Encoder.cxx b/rfb/Encoder.cxx
index aba38b3..53cb170 100644
--- a/rfb/Encoder.cxx
+++ b/rfb/Encoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Encoder.h b/rfb/Encoder.h
index 71739ba..df50dd6 100644
--- a/rfb/Encoder.h
+++ b/rfb/Encoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/HTTPServer.cxx b/rfb/HTTPServer.cxx
index 3bac4f8..e40d480 100644
--- a/rfb/HTTPServer.cxx
+++ b/rfb/HTTPServer.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -20,11 +20,6 @@
 #include <rfb/LogWriter.h>
 #include <rfb/util.h>
 #include <rdr/MemOutStream.h>
-#include <time.h>
-
-// *** Shouldn't really link against this - only for ClientWaitTimeMillis
-//     and IdleTimeout
-#include <rfb/ServerCore.h>
 
 #ifdef WIN32
 #define strcasecmp _stricmp
@@ -36,6 +31,9 @@
 
 static LogWriter vlog("HTTPServer");
 
+const int clientWaitTimeMillis = 20000;
+const int idleTimeoutSecs = 5 * 60;
+
 
 //
 // -=- LineReader
@@ -94,7 +92,8 @@
 class rfb::HTTPServer::Session {
 public:
   Session(network::Socket& s, rfb::HTTPServer& srv)
-    : contentType(0), line(s.inStream(), 256), sock(s),
+    : contentType(0), contentLength(-1), lastModified(-1),
+      line(s.inStream(), 256), sock(s),
       server(srv), state(ReadRequestLine), lastActive(time(0)) {
   }
   ~Session() {
@@ -111,6 +110,8 @@
 protected:
   CharArray uri;
   const char* contentType;
+  int contentLength;
+  time_t lastModified;
   LineReader line;
   network::Socket& sock;
   rfb::HTTPServer& server;
@@ -140,6 +141,7 @@
 
 // - Write an HTTP-compliant response to the client
 
+
 void
 HTTPServer::Session::writeResponse(int result, const char* text) {
   char buffer[1024];
@@ -149,6 +151,19 @@
   OutStream& os=sock.outStream();
   writeLine(os, buffer);
   writeLine(os, "Server: TightVNC/4.0");
+  time_t now = time(0);
+  struct tm* tm = gmtime(&now);
+  strftime(buffer, 1024, "Date: %a, %d %b %Y %H:%M:%S GMT", tm);
+  writeLine(os, buffer);
+  if (lastModified == (time_t)-1 || lastModified == 0)
+    lastModified = now;
+  tm = gmtime(&lastModified);
+  strftime(buffer, 1024, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT", tm);
+  writeLine(os, buffer);
+  if (contentLength != -1) {
+    sprintf(buffer,"Content-Length: %d",contentLength);
+    writeLine(os, buffer);
+  }
   writeLine(os, "Connection: close");
   os.writeBytes("Content-Type: ", 14);
   if (result == 200) {
@@ -247,7 +262,10 @@
       {
         CharArray address(sock.getPeerAddress());
         vlog.info("getting %s for %s", uri.buf, address.buf);
-        InStream* data = server.getFile(uri.buf, &contentType);
+        contentLength = -1;
+        lastModified = -1;
+        InStream* data = server.getFile(uri.buf, &contentType, &contentLength,
+                                        &lastModified);
         if (!data)
           return writeResponse(404);
 
@@ -277,9 +295,9 @@
 
 int HTTPServer::Session::checkIdleTimeout() {
   time_t now = time(0);
-  int timeout = (lastActive + rfb::Server::idleTimeout) - now;
+  int timeout = (lastActive + idleTimeoutSecs) - now;
   if (timeout > 0)
-    return timeout * 1000;
+    return secsToMillis(timeout);
   sock.shutdown();
   return 0;
 }
@@ -291,28 +309,38 @@
 
 HTTPServer::~HTTPServer() {
   std::list<Session*>::iterator i;
-  for (i=sessions.begin(); i!=sessions.end(); i++) {
-    delete (*i)->getSock();
+  for (i=sessions.begin(); i!=sessions.end(); i++)
     delete *i;
-  }
 }
 
 
 // -=- SocketServer interface implementation
 
 void
-HTTPServer::addClient(network::Socket* sock) {
+HTTPServer::addSocket(network::Socket* sock, bool) {
   Session* s = new Session(*sock, *this);
   if (!s) {
     sock->shutdown();
   } else {
-    sock->inStream().setTimeout(rfb::Server::clientWaitTimeMillis);
-    sock->outStream().setTimeout(rfb::Server::clientWaitTimeMillis);
+    sock->inStream().setTimeout(clientWaitTimeMillis);
+    sock->outStream().setTimeout(clientWaitTimeMillis);
     sessions.push_front(s);
   }
 }
 
-bool
+void
+HTTPServer::removeSocket(network::Socket* sock) {
+  std::list<Session*>::iterator i;
+  for (i=sessions.begin(); i!=sessions.end(); i++) {
+    if ((*i)->getSock() == sock) {
+      delete *i;
+      sessions.erase(i);
+      return;
+    }
+  }
+}
+
+void
 HTTPServer::processSocketEvent(network::Socket* sock) {
   std::list<Session*>::iterator i;
   for (i=sessions.begin(); i!=sessions.end(); i++) {
@@ -320,21 +348,16 @@
       try {
         if ((*i)->processHTTP()) {
           vlog.info("completed HTTP request");
-          delete *i;
-          sessions.erase(i);
-          break;
+          sock->shutdown();
         }
-        return true;
       } catch (rdr::Exception& e) {
         vlog.error("untrapped: %s", e.str());
-        delete *i;
-        sessions.erase(i);
-        break;
+        sock->shutdown();
       }
+      return;
     }
   }
-  delete sock;
-  return false;
+  throw rdr::Exception("invalid Socket in HTTPServer");
 }
 
 void HTTPServer::getSockets(std::list<network::Socket*>* sockets)
@@ -359,7 +382,9 @@
 // -=- Default getFile implementation
 
 InStream*
-HTTPServer::getFile(const char* name, const char** contentType) {
+HTTPServer::getFile(const char* name, const char** contentType,
+                    int* contentLength, time_t* lastModified)
+{
   return 0;
 }
 
diff --git a/rfb/HTTPServer.h b/rfb/HTTPServer.h
index 9431195..6412946 100644
--- a/rfb/HTTPServer.h
+++ b/rfb/HTTPServer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -32,6 +32,7 @@
 #include <rfb/UpdateTracker.h>
 #include <rfb/Configuration.h>
 #include <network/Socket.h>
+#include <time.h>
 
 namespace rfb {
 
@@ -46,32 +47,27 @@
 
     virtual ~HTTPServer();
 
-    // -=- Client management
+    // SocketServer interface
 
-    // - Run a client connection on the supplied socket
+    // addSocket()
     //   This causes the server to perform HTTP protocol on the
     //   supplied socket.
-    //   The socket will be closed if protocol initialisation
-    //   fails.
-    virtual void addClient(network::Socket* sock);
+    virtual void addSocket(network::Socket* sock, bool outgoing=false);
 
-    // -=- Event processing methods
+    // removeSocket()
+    //   Could clean up socket-specific resources here.
+    virtual void removeSocket(network::Socket* sock);
 
-    // - Process an input event on a particular Socket
+    // processSocketEvent()
     //   The platform-specific side of the server implementation calls
     //   this method whenever data arrives on one of the active
     //   network sockets.
-    //   The method returns true if the Socket is still in use by the
-    //   server, or false if it is no longer required and should be
-    //   deleted.
-    //   NB:  If false is returned then the Socket is deleted and must
-    //   not be accessed again!
+    virtual void processSocketEvent(network::Socket* sock);
 
-    virtual bool processSocketEvent(network::Socket* sock);
-
-    // - Check for socket timeouts
+    // Check for socket timeouts
     virtual int checkTimeouts();
 
+
     // getSockets() gets a list of sockets.  This can be used to generate an
     // fd_set for calling select().
 
@@ -92,13 +88,15 @@
     //   NB: The contentType is statically allocated by the getFile impl.
     //   NB: contentType is *guaranteed* to be valid when getFile is called.
 
-    virtual rdr::InStream* getFile(const char* name, const char** contentType);
+    virtual rdr::InStream* getFile(const char* name, const char** contentType,
+                                   int* contentLength, time_t* lastModified);
 
     // - guessContentType is passed the name of a file and returns the
     //   name of an HTTP content type, based on the file's extension.  If
     //   the extension isn't recognised then defType is returned.  This can
     //   be used from getFile to easily default to the supplied contentType,
-    //   or by passing zero in to determine whether a type is recognised or not.
+    //   or by passing zero in to determine whether a type is recognised or
+    //   not.
 
     static const char* guessContentType(const char* name, const char* defType);
 
diff --git a/rfb/HextileDecoder.cxx b/rfb/HextileDecoder.cxx
index 97c7ca7..e817c73 100644
--- a/rfb/HextileDecoder.cxx
+++ b/rfb/HextileDecoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/HextileDecoder.h b/rfb/HextileDecoder.h
index 718bd38..e7dd3d5 100644
--- a/rfb/HextileDecoder.h
+++ b/rfb/HextileDecoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/HextileEncoder.cxx b/rfb/HextileEncoder.cxx
index a96cf79..ba71d56 100644
--- a/rfb/HextileEncoder.cxx
+++ b/rfb/HextileEncoder.cxx
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright (C) 2005 Constantin Kaplinsky.  All Rights Reserved.
- *    
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/HextileEncoder.h b/rfb/HextileEncoder.h
index f09ead8..c78107a 100644
--- a/rfb/HextileEncoder.h
+++ b/rfb/HextileEncoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Hostname.h b/rfb/Hostname.h
index bdff474..ebdf816 100644
--- a/rfb/Hostname.h
+++ b/rfb/Hostname.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -19,11 +19,13 @@
 #ifndef __RFB_HOSTNAME_H__
 #define __RFB_HOSTNAME_H__
 
+#include <stdlib.h>
+#include <rdr/Exception.h>
 #include <rfb/util.h>
 
 namespace rfb {
 
-  void getHostAndPort(const char* hi, char** host, int* port, int basePort=5900) {
+  static void getHostAndPort(const char* hi, char** host, int* port, int basePort=5900) {
     CharArray portBuf;
     CharArray hostBuf;
     if (hi[0] == '[') {
diff --git a/rfb/ImageGetter.h b/rfb/ImageGetter.h
index b550a12..290249f 100644
--- a/rfb/ImageGetter.h
+++ b/rfb/ImageGetter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/vncAuth.h b/rfb/InputHandler.h
similarity index 60%
copy from rfb/vncAuth.h
copy to rfb/InputHandler.h
index 18d87ad..b5e5e87 100644
--- a/rfb/vncAuth.h
+++ b/rfb/InputHandler.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -15,17 +15,26 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
-#ifndef __RFB_VNCAUTH_H__
-#define __RFB_VNCAUTH_H__
+//
+// InputHandler - abstract interface for accepting keyboard &
+// pointer input and clipboard data.
+//
+
+#ifndef __RFB_INPUTHANDLER_H__
+#define __RFB_INPUTHANDLER_H__
 
 #include <rdr/types.h>
+#include <rfb/Rect.h>
 
 namespace rfb {
 
-  const int vncAuthChallengeSize = 16;
+  class InputHandler {
+  public:
+    virtual ~InputHandler() {}
+    virtual void keyEvent(rdr::U32 key, bool down) {}
+    virtual void pointerEvent(const Point& pos, int buttonMask) {}
+    virtual void clientCutText(const char* str, int len) {}
+  };
 
-  void vncAuthEncryptChallenge(rdr::U8* challenge, const char* passwd);
-  void vncAuthObfuscatePasswd(char* passwd);
-  void vncAuthUnobfuscatePasswd(char* passwd);
 }
 #endif
diff --git a/rfb/KeyRemapper.cxx b/rfb/KeyRemapper.cxx
new file mode 100644
index 0000000..05f0763
--- /dev/null
+++ b/rfb/KeyRemapper.cxx
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <rfb/KeyRemapper.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("KeyRemapper");
+
+KeyRemapper KeyRemapper::defInstance;
+
+#ifdef __RFB_THREADING_IMPL
+static Mutex mappingLock;
+#endif
+
+void KeyRemapper::setMapping(const char* m) {
+#ifdef __RFB_THREADING_IMPL
+  Lock l(mappingLock);
+#endif
+  mapping.clear();
+  while (m[0]) {
+    int from, to;
+    char bidi;
+    const char* nextComma = strchr(m, ',');
+    if (!nextComma)
+      nextComma = m + strlen(m);
+    if (sscanf(m, "0x%x%c>0x%x", &from,
+               &bidi, &to) == 3) {
+      if (bidi != '-' && bidi != '<')
+        vlog.error("warning: unknown operation %c>, assuming ->", bidi);
+      mapping[from] = to;
+      if (bidi == '<')
+        mapping[to] = from;
+    } else {
+      vlog.error("warning: bad mapping %.*s", nextComma-m, m);
+    }
+    m = nextComma;
+    if (nextComma[0])
+      m++;
+  }
+}
+
+rdr::U32 KeyRemapper::remapKey(rdr::U32 key) const {
+#ifdef __RFB_THREADING_IMPL
+  Lock l(mappingLock);
+#endif
+  std::map<rdr::U32,rdr::U32>::const_iterator i = mapping.find(key);
+  if (i != mapping.end())
+    return i->second;
+  return key;
+}
+
+
+class KeyMapParameter : public StringParameter {
+public:
+  KeyMapParameter()
+    : StringParameter("RemapKeys", "Comma-separated list of incoming keysyms to remap.  Mappings are expressed as two hex values, prefixed by 0x, and separated by ->", "") {
+    setParam(value);
+  }
+  bool setParam(const char* v) {
+    KeyRemapper::defInstance.setMapping(v);
+    return StringParameter::setParam(v);
+  }
+} defaultParam;
+
+
diff --git a/rfb/vncAuth.h b/rfb/KeyRemapper.h
similarity index 63%
rename from rfb/vncAuth.h
rename to rfb/KeyRemapper.h
index 18d87ad..a4b7aa0 100644
--- a/rfb/vncAuth.h
+++ b/rfb/KeyRemapper.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -15,17 +15,25 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
-#ifndef __RFB_VNCAUTH_H__
-#define __RFB_VNCAUTH_H__
 
+#ifndef __RFB_KEYREMAPPER_H__
+#define __RFB_KEYREMAPPER_H__
+
+#include <map>
 #include <rdr/types.h>
 
 namespace rfb {
 
-  const int vncAuthChallengeSize = 16;
+  class KeyRemapper {
+  public:
+    KeyRemapper(const char* m="") { setMapping(m); }
+    void setMapping(const char* m);
+    rdr::U32 remapKey(rdr::U32 key) const;
+    static KeyRemapper defInstance;
+  private:
+    std::map<rdr::U32,rdr::U32> mapping;
+  };
 
-  void vncAuthEncryptChallenge(rdr::U8* challenge, const char* passwd);
-  void vncAuthObfuscatePasswd(char* passwd);
-  void vncAuthUnobfuscatePasswd(char* passwd);
-}
-#endif
+};
+
+#endif // __RFB_KEYREMAPPER_H__
diff --git a/rfb/LogWriter.cxx b/rfb/LogWriter.cxx
index 6f267f1..c6461d1 100644
--- a/rfb/LogWriter.cxx
+++ b/rfb/LogWriter.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -53,13 +53,13 @@
 LogWriter::listLogWriters(int width) {
   // *** make this respect width...
   LogWriter* current = log_writers;
-  printf("  ");
+  fprintf(stderr, "  ");
   while (current) {
-    printf("%s", current->m_name);
+    fprintf(stderr, "%s", current->m_name);
     current = current->m_next;
-    if (current) printf(", ");
+    if (current) fprintf(stderr, ", ");
   }
-  printf("\n");
+  fprintf(stderr, "\n");
 }
 
 LogWriter* LogWriter::log_writers;
diff --git a/rfb/LogWriter.h b/rfb/LogWriter.h
index 58e81f2..124c58e 100644
--- a/rfb/LogWriter.h
+++ b/rfb/LogWriter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Logger.cxx b/rfb/Logger.cxx
index 84b8f55..8b3c6ee 100644
--- a/rfb/Logger.cxx
+++ b/rfb/Logger.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Logger.h b/rfb/Logger.h
index 4233964..e53764b 100644
--- a/rfb/Logger.h
+++ b/rfb/Logger.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Logger_file.cxx b/rfb/Logger_file.cxx
index ac249b3..8a109e4 100644
--- a/rfb/Logger_file.cxx
+++ b/rfb/Logger_file.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -53,6 +53,10 @@
 #endif
   if (!m_file) {
     if (!m_filename) return;
+    CharArray bakFilename(strlen(m_filename) + 1 + 4);
+    sprintf(bakFilename.buf, "%s.bak", m_filename);
+    remove(bakFilename.buf);
+    rename(m_filename, bakFilename.buf);
     m_file = fopen(m_filename, "w+");
     if (!m_file) return;
   }
diff --git a/rfb/Logger_file.h b/rfb/Logger_file.h
index 30c3f40..5e0c917 100644
--- a/rfb/Logger_file.h
+++ b/rfb/Logger_file.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Logger_stdio.cxx b/rfb/Logger_stdio.cxx
index ac9556e..581dcd5 100644
--- a/rfb/Logger_stdio.cxx
+++ b/rfb/Logger_stdio.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Logger_stdio.h b/rfb/Logger_stdio.h
index 68f795f..a1d17a0 100644
--- a/rfb/Logger_stdio.h
+++ b/rfb/Logger_stdio.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Makefile.in b/rfb/Makefile.in
index f2976c0..3f501a9 100644
--- a/rfb/Makefile.in
+++ b/rfb/Makefile.in
@@ -21,10 +21,12 @@
   HTTPServer.cxx \
   HextileDecoder.cxx \
   HextileEncoder.cxx \
+  KeyRemapper.cxx \
   LogWriter.cxx \
   Logger.cxx \
   Logger_file.cxx \
   Logger_stdio.cxx \
+  Password.cxx \
   PixelBuffer.cxx \
   PixelFormat.cxx \
   RREEncoder.cxx \
@@ -41,6 +43,7 @@
   ServerCore.cxx \
   SSecurityFactoryStandard.cxx \
   SSecurityVncAuth.cxx \
+  Timer.cxx \
   TightDecoder.cxx \
   TightEncoder.cxx \
   TightPalette.cxx \
@@ -53,8 +56,7 @@
   ZRLEDecoder.cxx \
   encodings.cxx \
   secTypes.cxx \
-  util.cxx \
-  vncAuth.cxx
+  util.cxx
 
 SRCS = d3des.c $(CXXSRCS)
 
diff --git a/rfb/Password.cxx b/rfb/Password.cxx
new file mode 100644
index 0000000..9127862
--- /dev/null
+++ b/rfb/Password.cxx
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+//
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
+
+#include <string.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+#include <rdr/types.h>
+#include <rdr/Exception.h>
+#include <rfb/Password.h>
+
+using namespace rfb;
+
+static unsigned char d3desObfuscationKey[] = {23,82,107,6,35,78,88,7};
+
+
+PlainPasswd::PlainPasswd() {}
+
+PlainPasswd::PlainPasswd(char* pwd) : CharArray(pwd) {
+}
+
+PlainPasswd::PlainPasswd(const ObfuscatedPasswd& obfPwd) : CharArray(9) {
+  if (obfPwd.length < 8)
+    throw rdr::Exception("bad obfuscated password length");
+  deskey(d3desObfuscationKey, DE1);
+  des((rdr::U8*)obfPwd.buf, (rdr::U8*)buf);
+  buf[8] = 0;
+}
+
+PlainPasswd::~PlainPasswd() {
+  replaceBuf(0);
+}
+
+void PlainPasswd::replaceBuf(char* b) {
+  if (buf)
+    memset(buf, 0, strlen(buf));
+  CharArray::replaceBuf(b);
+}
+
+
+ObfuscatedPasswd::ObfuscatedPasswd() : length(0) {
+}
+
+ObfuscatedPasswd::ObfuscatedPasswd(int len) : CharArray(len), length(len) {
+}
+
+ObfuscatedPasswd::ObfuscatedPasswd(const PlainPasswd& plainPwd) : CharArray(8), length(8) {
+  int l = strlen(plainPwd.buf), i;
+  for (i=0; i<8; i++)
+    buf[i] = i<l ? plainPwd.buf[i] : 0;
+  deskey(d3desObfuscationKey, EN0);
+  des((rdr::U8*)buf, (rdr::U8*)buf);
+}
+
+ObfuscatedPasswd::~ObfuscatedPasswd() {
+  if (buf)
+    memset(buf, 0, length);
+}
diff --git a/rfb/Password.h b/rfb/Password.h
new file mode 100644
index 0000000..ab26903
--- /dev/null
+++ b/rfb/Password.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#ifndef __RFB_PASSWORD_H__
+#define __RFB_PASSWORD_H__
+
+#include <rfb/util.h>
+
+namespace rfb {
+
+  class ObfuscatedPasswd;
+
+  class PlainPasswd : public CharArray {
+  public:
+    PlainPasswd();
+    PlainPasswd(char* pwd);
+    PlainPasswd(const ObfuscatedPasswd& obfPwd);
+    ~PlainPasswd();
+    void replaceBuf(char* b);
+  };
+
+  class ObfuscatedPasswd : public CharArray {
+  public:
+    ObfuscatedPasswd();
+    ObfuscatedPasswd(int l);
+    ObfuscatedPasswd(const PlainPasswd& plainPwd);
+    ~ObfuscatedPasswd();
+    int length;
+  };
+
+}
+#endif
diff --git a/rfb/Pixel.h b/rfb/Pixel.h
index 2b1aaf0..4e9d164 100644
--- a/rfb/Pixel.h
+++ b/rfb/Pixel.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/PixelBuffer.cxx b/rfb/PixelBuffer.cxx
index fcad227..d093426 100644
--- a/rfb/PixelBuffer.cxx
+++ b/rfb/PixelBuffer.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/PixelBuffer.h b/rfb/PixelBuffer.h
index 2ba105a..4a13923 100644
--- a/rfb/PixelBuffer.h
+++ b/rfb/PixelBuffer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/PixelFormat.cxx b/rfb/PixelFormat.cxx
index 8809fb5..74b6837 100644
--- a/rfb/PixelFormat.cxx
+++ b/rfb/PixelFormat.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/PixelFormat.h b/rfb/PixelFormat.h
index 0f2edd2..111c38c 100644
--- a/rfb/PixelFormat.h
+++ b/rfb/PixelFormat.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RREDecoder.cxx b/rfb/RREDecoder.cxx
index c613dbb..da56ee7 100644
--- a/rfb/RREDecoder.cxx
+++ b/rfb/RREDecoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RREDecoder.h b/rfb/RREDecoder.h
index 75a5e85..2309f75 100644
--- a/rfb/RREDecoder.h
+++ b/rfb/RREDecoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RREEncoder.cxx b/rfb/RREEncoder.cxx
index 612a869..b000e9d 100644
--- a/rfb/RREEncoder.cxx
+++ b/rfb/RREEncoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RREEncoder.h b/rfb/RREEncoder.h
index 40b203e..1281410 100644
--- a/rfb/RREEncoder.h
+++ b/rfb/RREEncoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RawDecoder.cxx b/rfb/RawDecoder.cxx
index 5a5d62b..57cb37b 100644
--- a/rfb/RawDecoder.cxx
+++ b/rfb/RawDecoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RawDecoder.h b/rfb/RawDecoder.h
index b3dd9b7..9fdbb22 100644
--- a/rfb/RawDecoder.h
+++ b/rfb/RawDecoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RawEncoder.cxx b/rfb/RawEncoder.cxx
index d758ec6..a2545b6 100644
--- a/rfb/RawEncoder.cxx
+++ b/rfb/RawEncoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/RawEncoder.h b/rfb/RawEncoder.h
index c8b6a62..1b9ad92 100644
--- a/rfb/RawEncoder.h
+++ b/rfb/RawEncoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Rect.h b/rfb/Rect.h
index 1f88daf..52e92b5 100644
--- a/rfb/Rect.h
+++ b/rfb/Rect.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,11 +21,16 @@
 #ifndef __RFB_RECT_INCLUDED__
 #define __RFB_RECT_INCLUDED__
 
-#ifndef vncmin
-#define vncmin(a,b)            (((a) < (b)) ? (a) : (b))
+// Some platforms (e.g. Windows) include max() and min() macros in their
+// standard headers, but they are also standard C++ template functions, so some
+// C++ headers will undefine them.  So we steer clear of the names min and max
+// and define __rfbmin and __rfbmax instead.
+
+#ifndef __rfbmax
+#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
 #endif
-#ifndef vncmax
-#define vncmax(a,b)            (((a) > (b)) ? (a) : (b))
+#ifndef __rfbmin
+#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
 namespace rfb {
@@ -69,20 +74,20 @@
     }
     inline Rect intersect(const Rect &r) const {
       Rect result;
-      result.tl.x = vncmax(tl.x, r.tl.x);
-      result.tl.y = vncmax(tl.y, r.tl.y);
-      result.br.x = vncmax(vncmin(br.x, r.br.x), result.tl.x);
-      result.br.y = vncmax(vncmin(br.y, r.br.y), result.tl.y);
+      result.tl.x = __rfbmax(tl.x, r.tl.x);
+      result.tl.y = __rfbmax(tl.y, r.tl.y);
+      result.br.x = __rfbmax(__rfbmin(br.x, r.br.x), result.tl.x);
+      result.br.y = __rfbmax(__rfbmin(br.y, r.br.y), result.tl.y);
       return result;
     }
     inline Rect union_boundary(const Rect &r) const {
       if (r.is_empty()) return *this;
       if (is_empty()) return r;
       Rect result;
-      result.tl.x = vncmin(tl.x, r.tl.x);
-      result.tl.y = vncmin(tl.y, r.tl.y);
-      result.br.x = vncmax(br.x, r.br.x);
-      result.br.y = vncmax(br.y, r.br.y);
+      result.tl.x = __rfbmin(tl.x, r.tl.x);
+      result.tl.y = __rfbmin(tl.y, r.tl.y);
+      result.br.x = __rfbmax(br.x, r.br.x);
+      result.br.y = __rfbmax(br.y, r.br.y);
       return result;
     }
     inline Rect translate(const Point &p) const {
diff --git a/rfb/Region.cxx b/rfb/Region.cxx
index bbcc892..7965a6c 100644
--- a/rfb/Region.cxx
+++ b/rfb/Region.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/Region.h b/rfb/Region.h
index 8fb9889..9337556 100644
--- a/rfb/Region.h
+++ b/rfb/Region.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/SConnection.cxx b/rfb/SConnection.cxx
index e969ed8..f8a3f36 100644
--- a/rfb/SConnection.cxx
+++ b/rfb/SConnection.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,7 +21,6 @@
 #include <rfb/secTypes.h>
 #include <rfb/SMsgReaderV3.h>
 #include <rfb/SMsgWriterV3.h>
-#include <rfb/SSecurity.h>
 #include <rfb/SConnection.h>
 #include <rfb/ServerCore.h>
 
@@ -41,10 +40,11 @@
 const SConnection::AccessRights SConnection::AccessFull       = 0xffff;
 
 
-SConnection::SConnection()
+SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
   : readyForSetColourMapEntries(false),
     is(0), os(0), reader_(0), writer_(0),
-    nSecTypes(0), security(0), state_(RFBSTATE_UNINITIALISED)
+    security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
+    reverseConnection(reverseConnection_)
 {
   defaultMajorVersion = 3;
   defaultMinorVersion = 8;
@@ -74,15 +74,6 @@
   os = os_;
 }
 
-void SConnection::addSecType(rdr::U8 secType)
-{
-  if (nSecTypes == maxSecTypes)
-    throw Exception("too many security types");
-  secTypes[nSecTypes++] = secType;
-  vlog.debug("Offering security type %s(%d)",
-             secTypeName(secType),secType);
-}
-
 void SConnection::initialiseProtocol()
 {
   cp.writeVersion(os);
@@ -144,37 +135,40 @@
 
   versionReceived();
 
+  std::list<rdr::U8> secTypes;
+  std::list<rdr::U8>::iterator i;
+  securityFactory->getSecTypes(&secTypes, reverseConnection);
+
   if (cp.isVersion(3,3)) {
 
     // cope with legacy 3.3 client only if "no authentication" or "vnc
     // authentication" is supported.
-
-    int i;
-    for (i = 0; i < nSecTypes; i++) {
-      if (secTypes[i] == secTypeNone || secTypes[i] == secTypeVncAuth) break;
+    for (i=secTypes.begin(); i!=secTypes.end(); i++) {
+      if (*i == secTypeNone || *i == secTypeVncAuth) break;
     }
-    if (i == nSecTypes) {
+    if (i == secTypes.end()) {
       char msg[256];
       sprintf(msg,"No supported security type for %d.%d client",
               cp.majorVersion, cp.minorVersion);
       throwConnFailedException(msg);
     }
 
-    os->writeU32(secTypes[i]);
-    if (secTypes[i] == secTypeNone) os->flush();
+    os->writeU32(*i);
+    if (*i == secTypeNone) os->flush();
     state_ = RFBSTATE_SECURITY;
-    security = getSSecurity(secTypes[i]);
+    security = securityFactory->getSSecurity(*i, reverseConnection);
     processSecurityMsg();
     return;
   }
 
   // list supported security types for >=3.7 clients
 
-  if (nSecTypes == 0)
+  if (secTypes.empty())
     throwConnFailedException("No supported security types");
 
-  os->writeU8(nSecTypes);
-  os->writeBytes(secTypes, nSecTypes);
+  os->writeU8(secTypes.size());
+  for (i=secTypes.begin(); i!=secTypes.end(); i++)
+    os->writeU8(*i);
   os->flush();
   state_ = RFBSTATE_SECURITY_TYPE;
 }
@@ -186,40 +180,33 @@
   int secType = is->readU8();
   vlog.info("Client requests security type %s(%d)",
             secTypeName(secType),secType);
-  int i;
-  for (i = 0; i < nSecTypes; i++) {
-    if (secType == secTypes[i]) break;
+
+  try {
+    state_ = RFBSTATE_SECURITY;
+    security = securityFactory->getSSecurity(secType, reverseConnection);
+  } catch (rdr::Exception& e) {
+    throwConnFailedException(e.str());
   }
-  if (i == nSecTypes) {
-    char msg[256];
-    sprintf(msg,"Security type %s(%d) from client not supported",
-            secTypeName(secType),secType);
-    throwConnFailedException(msg);
-  }
-  state_ = RFBSTATE_SECURITY;
-  security = getSSecurity(secType);
+
   processSecurityMsg();
 }
 
 void SConnection::processSecurityMsg()
 {
   vlog.debug("processing security message");
-  bool done;
-  bool ok = security->processMsg(this, &done);
-  if (done) {
-    state_ = RFBSTATE_QUERYING;
-    if (ok) {
+  try {
+    bool done = security->processMsg(this);
+    if (done) {
+      state_ = RFBSTATE_QUERYING;
       queryConnection(security->getUserName());
-    } else {
-      const char* failureMsg = security->failureMessage();
-      if (!failureMsg) failureMsg = "Authentication failure";
-      approveConnection(false, failureMsg);
     }
-  }
-  if (!ok) {
-    state_ = RFBSTATE_INVALID;
-    authFailure();
-    throw AuthFailureException();
+  } catch (AuthFailureException& e) {
+    vlog.error("AuthFailureException: %s", e.str());
+    os->writeU32(secResultFailed);
+    if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+      os->writeString(e.str());
+    os->flush();
+    throw;
   }
 }
 
@@ -264,10 +251,6 @@
 {
 }
 
-void SConnection::authFailure()
-{
-}
-
 void SConnection::queryConnection(const char* userName)
 {
   approveConnection(true);
@@ -298,7 +281,6 @@
     authSuccess();
   } else {
     state_ = RFBSTATE_INVALID;
-    authFailure();
     throw AuthFailureException(reason);
   }
 }
diff --git a/rfb/SConnection.h b/rfb/SConnection.h
index 19453c6..6b943f5 100644
--- a/rfb/SConnection.h
+++ b/rfb/SConnection.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -26,6 +26,7 @@
 #include <rdr/InStream.h>
 #include <rdr/OutStream.h>
 #include <rfb/SMsgHandler.h>
+#include <rfb/SSecurity.h>
 
 namespace rfb {
 
@@ -36,7 +37,7 @@
   class SConnection : public SMsgHandler {
   public:
 
-    SConnection();
+    SConnection(SSecurityFactory* sf, bool reverseConnection_);
     virtual ~SConnection();
 
     // Methods to initialise the connection
@@ -49,10 +50,6 @@
     // (i.e. SConnection will not delete them).
     void setStreams(rdr::InStream* is, rdr::OutStream* os);
 
-    // addSecType() should be called once for each security type which the
-    // server supports to this client.
-    void addSecType(rdr::U8 secType);
-
     // initialiseProtocol() should be called once the streams and security
     // types are set.  Subsequently, processMsg() should be called whenever
     // there is data to read on the InStream.
@@ -78,19 +75,9 @@
     // to deal with unknown/bogus viewer protocol numbers.
     virtual void versionReceived();
 
-    // getSSecurity() gets the SSecurity object for the given type.  The type
-    // is guaranteed to be one of the secTypes passed in to addSecType().  The
-    // SSecurity object's destroy() method will be called by the SConnection
-    // from its destructor.
-    virtual SSecurity* getSSecurity(int secType)=0;
-
     // authSuccess() is called when authentication has succeeded.
     virtual void authSuccess();
 
-    // authFailure() is called when authentication has failed.  This method is
-    // not normally overridden since an exception is thrown anyway.
-    virtual void authFailure();
-
     // queryConnection() is called when authentication has succeeded, but
     // before informing the client.  It can be overridden to query a local user
     // to accept the incoming connection, for example.  The userName argument
@@ -178,7 +165,8 @@
 
     stateEnum state() { return state_; }
 
-    // ssecurity() returns a pointer to this connection's SSecurity object, if any
+    // ssecurity() returns a pointer to this connection's SSecurity object, if
+    // any
     const SSecurity* ssecurity() const { return security; }
 
   protected:
@@ -186,7 +174,6 @@
 
     bool readyForSetColourMapEntries;
 
-  private:
     void processVersionMsg();
     void processSecurityTypeMsg();
     void processSecurityMsg();
@@ -197,11 +184,10 @@
     rdr::OutStream* os;
     SMsgReader* reader_;
     SMsgWriter* writer_;
-    enum { maxSecTypes = 8 };
-    int nSecTypes;
-    rdr::U8 secTypes[maxSecTypes];
     SSecurity* security;
+    SSecurityFactory* securityFactory;
     stateEnum state_;
+    bool reverseConnection;
   };
 }
 #endif
diff --git a/rfb/SDesktop.h b/rfb/SDesktop.h
index eb17a52..7b054e3 100644
--- a/rfb/SDesktop.h
+++ b/rfb/SDesktop.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -39,13 +39,14 @@
 
 #include <rfb/PixelBuffer.h>
 #include <rfb/VNCServer.h>
+#include <rfb/InputHandler.h>
 #include <rfb/Exception.h>
 
 namespace rfb {
 
   class VNCServer;
 
-  class SDesktop {
+  class SDesktop : public InputHandler {
   public:
     // start() is called by the server when the first client authenticates
     // successfully, and can be used to begin any expensive tasks which are not
@@ -62,13 +63,6 @@
 
     virtual void stop() {}
 
-    // pointerEvent(), keyEvent() and clientCutText() are called in response to
-    // the relevant RFB protocol messages from clients.
-
-    virtual void pointerEvent(const Point& pos, rdr::U8 buttonmask) {}
-    virtual void keyEvent(rdr::U32 key, bool down) {}
-    virtual void clientCutText(const char* str, int len) {}
-
     // framebufferUpdateRequest() is called to let the desktop know that at
     // least one client has become ready for an update.  Desktops can check
     // whether there are clients ready at any time by calling the VNCServer's
@@ -81,6 +75,10 @@
 
     virtual Point getFbSize() = 0;
 
+    // InputHandler interface
+    // pointerEvent(), keyEvent() and clientCutText() are called in response to
+    // the relevant RFB protocol messages from clients.
+    // See InputHandler for method signatures.
   protected:
     virtual ~SDesktop() {}
   };
diff --git a/rfb/SMsgHandler.cxx b/rfb/SMsgHandler.cxx
index d6a139c..ccc97ad 100644
--- a/rfb/SMsgHandler.cxx
+++ b/rfb/SMsgHandler.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -47,18 +47,6 @@
 {
 }
 
-void SMsgHandler::keyEvent(rdr::U32 key, bool down)
-{
-}
-
-void SMsgHandler::pointerEvent(int x, int y, int buttonMask)
-{
-}
-
-void SMsgHandler::clientCutText(const char* str, int len)
-{
-}
-
 void SMsgHandler::supportsLocalCursor()
 {
 }
diff --git a/rfb/SMsgHandler.h b/rfb/SMsgHandler.h
index 148403f..cf3377d 100644
--- a/rfb/SMsgHandler.h
+++ b/rfb/SMsgHandler.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -25,13 +25,13 @@
 #include <rdr/types.h>
 #include <rfb/PixelFormat.h>
 #include <rfb/ConnParams.h>
-#include <rfb/Rect.h>
+#include <rfb/InputHandler.h>
 
 namespace rdr { class InStream; }
 
 namespace rfb {
 
-  class SMsgHandler {
+  class SMsgHandler : public InputHandler {
   public:
     SMsgHandler();
     virtual ~SMsgHandler();
@@ -46,9 +46,9 @@
     virtual void setPixelFormat(const PixelFormat& pf);
     virtual void setEncodings(int nEncodings, rdr::U32* encodings);
     virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
-    virtual void keyEvent(rdr::U32 key, bool down);
-    virtual void pointerEvent(int x, int y, int buttonMask);
-    virtual void clientCutText(const char* str, int len);
+
+    // InputHandler interface
+    // The InputHandler methods will be called for the corresponding messages.
 
     // supportsLocalCursor() is called whenever the status of
     // cp.supportsLocalCursor has changed.  At the moment this happens on a
diff --git a/rfb/SMsgReader.cxx b/rfb/SMsgReader.cxx
index 2939aa1..f89e0f4 100644
--- a/rfb/SMsgReader.cxx
+++ b/rfb/SMsgReader.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,9 +21,12 @@
 #include <rfb/util.h>
 #include <rfb/SMsgHandler.h>
 #include <rfb/SMsgReader.h>
+#include <rfb/Configuration.h>
 
 using namespace rfb;
 
+static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
+
 SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
   : handler(handler_), is(is_)
 {
@@ -33,16 +36,11 @@
 {
 }
 
-void SMsgReader::endMsg()
-{
-}
-
 void SMsgReader::readSetPixelFormat()
 {
   is->skip(3);
   PixelFormat pf;
   pf.read(is);
-  endMsg();
   handler->setPixelFormat(pf);
 }
 
@@ -50,12 +48,10 @@
 {
   is->skip(1);
   int nEncodings = is->readU16();
-  rdr::U32* encodings = new rdr::U32[nEncodings];
+  rdr::U32Array encodings(nEncodings);
   for (int i = 0; i < nEncodings; i++)
-    encodings[i] = is->readU32();
-  endMsg();
-  handler->setEncodings(nEncodings, encodings);
-  delete [] encodings;
+    encodings.buf[i] = is->readU32();
+  handler->setEncodings(nEncodings, encodings.buf);
 }
 
 void SMsgReader::readFramebufferUpdateRequest()
@@ -65,7 +61,6 @@
   int y = is->readU16();
   int w = is->readU16();
   int h = is->readU16();
-  endMsg();
   handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
 }
 
@@ -74,7 +69,6 @@
   bool down = is->readU8();
   is->skip(2);
   rdr::U32 key = is->readU32();
-  endMsg();
   handler->keyEvent(key, down);
 }
 
@@ -83,8 +77,7 @@
   int mask = is->readU8();
   int x = is->readU16();
   int y = is->readU16();
-  endMsg();
-  handler->pointerEvent(x, y, mask);
+  handler->pointerEvent(Point(x, y), mask);
 }
 
 
@@ -92,7 +85,7 @@
 {
   is->skip(3);
   int len = is->readU32();
-  if (len > 256*1024) {
+  if (len > maxCutText) {
     is->skip(len);
     fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
     return;
@@ -100,6 +93,5 @@
   CharArray ca(len+1);
   ca.buf[len] = 0;
   is->readBytes(ca.buf, len);
-  endMsg();
   handler->clientCutText(ca.buf, len);
 }
diff --git a/rfb/SMsgReader.h b/rfb/SMsgReader.h
index 4d26938..e6e4044 100644
--- a/rfb/SMsgReader.h
+++ b/rfb/SMsgReader.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -46,7 +46,6 @@
     virtual void readKeyEvent();
     virtual void readPointerEvent();
     virtual void readClientCutText();
-    virtual void endMsg();
 
     SMsgReader(SMsgHandler* handler, rdr::InStream* is);
 
diff --git a/rfb/SMsgReaderV3.cxx b/rfb/SMsgReaderV3.cxx
index 0ce1bca..be01b5d 100644
--- a/rfb/SMsgReaderV3.cxx
+++ b/rfb/SMsgReaderV3.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -36,7 +36,6 @@
 void SMsgReaderV3::readClientInit()
 {
   bool shared = is->readU8();
-  endMsg();
   handler->clientInit(shared);
 }
 
diff --git a/rfb/SMsgReaderV3.h b/rfb/SMsgReaderV3.h
index 28cc7a6..c6b7bf4 100644
--- a/rfb/SMsgReaderV3.h
+++ b/rfb/SMsgReaderV3.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/SMsgWriter.cxx b/rfb/SMsgWriter.cxx
index 067fb11..085dfc1 100644
--- a/rfb/SMsgWriter.cxx
+++ b/rfb/SMsgWriter.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -176,11 +176,6 @@
   endRect();
 }
 
-void SMsgWriter::setOutStream(rdr::OutStream* os_)
-{
-  os = os_;
-}
-
 rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels)
 {
   int requiredBytes = required * (cp->pf().bpp / 8);
diff --git a/rfb/SMsgWriter.h b/rfb/SMsgWriter.h
index 6dc272c..ed8ad0e 100644
--- a/rfb/SMsgWriter.h
+++ b/rfb/SMsgWriter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -80,8 +80,8 @@
     // in response to the writeSetCursorCallback() callback.  For a V3 writer
     // this will happen when the next update is sent.
     virtual void cursorChange(WriteSetCursorCallback* cb)=0;
-    virtual void writeSetCursor(int width, int height, int hotspotX,
-                                int hotspotY, void* data, void* mask)=0;
+    virtual void writeSetCursor(int width, int height, const Point& hotspot,
+                                void* data, void* mask)=0;
     virtual void writeSetXCursor(int width, int height, int hotspotX,
                                 int hotspotY, void* data, void* mask)=0;
 
@@ -127,9 +127,6 @@
     virtual void startRect(const Rect& r, unsigned int enc)=0;
     virtual void endRect()=0;
 
-    // setOutStream() changes the OutStream on the fly.
-    virtual void setOutStream(rdr::OutStream* os);
-
     ConnParams* getConnParams() { return cp; }
     rdr::OutStream* getOutStream() { return os; }
     rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0);
diff --git a/rfb/SMsgWriterV3.cxx b/rfb/SMsgWriterV3.cxx
index e91e514..a85f85e 100644
--- a/rfb/SMsgWriterV3.cxx
+++ b/rfb/SMsgWriterV3.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -69,14 +69,14 @@
   wsccb = cb;
 }
 
-void SMsgWriterV3::writeSetCursor(int width, int height, int hotspotX,
-                                  int hotspotY, void* data, void* mask)
+void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
+                                  void* data, void* mask)
 {
   if (!wsccb) return;
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
-  os->writeS16(hotspotX);
-  os->writeS16(hotspotY);
+  os->writeS16(hotspot.x);
+  os->writeS16(hotspot.y);
   os->writeU16(width);
   os->writeU16(height);
   os->writeU32(pseudoEncodingCursor);
@@ -138,6 +138,8 @@
 void SMsgWriterV3::writeFramebufferUpdateEnd()
 {
   if (needSetDesktopSize) {
+    if (!cp->supportsDesktopResize)
+      throw Exception("Client does not support desktop resize");
     if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
       throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
     os->writeS16(0);
@@ -193,9 +195,3 @@
     rectsSent[currentEncoding]++;
   }
 }
-
-void SMsgWriterV3::setOutStream(rdr::OutStream* os_)
-{
-  SMsgWriter::setOutStream(os_);
-  realOS = os;
-}
diff --git a/rfb/SMsgWriterV3.h b/rfb/SMsgWriterV3.h
index fbd07d6..501fa48 100644
--- a/rfb/SMsgWriterV3.h
+++ b/rfb/SMsgWriterV3.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -33,8 +33,8 @@
     virtual void endMsg();
     virtual bool writeSetDesktopSize();
     virtual void cursorChange(WriteSetCursorCallback* cb);
-    virtual void writeSetCursor(int width, int height, int hotspotX,
-                                int hotspotY, void* data, void* mask);
+    virtual void writeSetCursor(int width, int height, const Point& hotspot,
+                                void* data, void* mask);
     virtual void writeSetXCursor(int width, int height, int hotspotX,
 				 int hotspotY, void* data, void* mask);
     virtual void writeFramebufferUpdateStart(int nRects);
@@ -44,8 +44,6 @@
     virtual void startRect(const Rect& r, unsigned int encoding);
     virtual void endRect();
 
-    virtual void setOutStream(rdr::OutStream* os);
-
   private:
     rdr::MemOutStream* updateOS;
     rdr::OutStream* realOS;
diff --git a/rfb/SSecurity.h b/rfb/SSecurity.h
index 2ca5344..108985b 100644
--- a/rfb/SSecurity.h
+++ b/rfb/SSecurity.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -18,10 +18,16 @@
 //
 // SSecurity - class on the server side for handling security handshaking.  A
 // derived class for a particular security type overrides the processMsg()
-// method.  processMsg() is called first when the security type has been
-// decided on, and will keep being called whenever there is data to read from
-// the client until either it returns false, indicating authentication/security
-// failure, or it returns with done set to true, to indicate success.
+// method.
+
+// processMsg() is called first when the security type has been decided on, and
+// will keep being called whenever there is data to read from the client.  It
+// should return false when it needs more data, or true when the connection has
+// been successfully authenticated.  In the event of authentication failure an
+// AuthFailureException should be thrown - this will result in a "failed"
+// security result being sent to the client with the str() from the exception
+// being sent as the reason.  Any other type of failure should be indicated by
+// some other kind of exception which will cause the connection to be aborted.
 //
 // processMsg() must never block (or at least must never block until the client
 // has been authenticated) - this is to prevent denial of service attacks.
@@ -33,13 +39,13 @@
 // getType() should return the secType value corresponding to the SSecurity
 // implementation.
 //
-// failureMessage_.buf can be set to a string which will be passed to the client
-// if processMsg returns false, to indicate the reason for the failure.
 
 #ifndef __RFB_SSECURITY_H__
 #define __RFB_SSECURITY_H__
 
+#include <rdr/types.h>
 #include <rfb/util.h>
+#include <list>
 
 namespace rfb {
 
@@ -48,7 +54,7 @@
   class SSecurity {
   public:
     virtual ~SSecurity() {}
-    virtual bool processMsg(SConnection* sc, bool* done)=0;
+    virtual bool processMsg(SConnection* sc)=0;
     virtual void destroy() { delete this; }
     virtual int getType() const = 0;
 
@@ -57,20 +63,21 @@
     // necessary.  Null may be returned to indicate that there is no user name
     // for this security type.
     virtual const char* getUserName() const = 0;
-
-    virtual const char* failureMessage() {return failureMessage_.buf;}
-  protected:
-    CharArray failureMessage_;
   };
 
   // SSecurityFactory creates new SSecurity instances for
   // particular security types.
   // The instances must be destroyed by calling destroy()
   // on them when done.
+  // getSecTypes returns a list of the security types that are both configured
+  // and actually supported.  Which configuration is considered depends on the
+  // reverseConnection parameter.
   class SSecurityFactory {
   public:
     virtual ~SSecurityFactory() {}
-    virtual SSecurity* getSSecurity(int secType, bool noAuth=false)=0;
+    virtual SSecurity* getSSecurity(rdr::U8 secType, bool noAuth=false)=0;
+    virtual void getSecTypes(std::list<rdr::U8>* secTypes,
+                             bool reverseConnection) = 0;
   };
 
 }
diff --git a/rfb/SSecurityFactoryStandard.cxx b/rfb/SSecurityFactoryStandard.cxx
index e3a40aa..a072698 100644
--- a/rfb/SSecurityFactoryStandard.cxx
+++ b/rfb/SSecurityFactoryStandard.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -25,77 +25,104 @@
 #include <rfb/LogWriter.h>
 #include <rfb/Exception.h>
 #include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/Password.h>
 
 using namespace rfb;
 
 static LogWriter vlog("SSecurityFactoryStandard");
 
-VncAuthPasswdParameter* SSecurityFactoryStandard::vncAuthPasswd = 0;
+StringParameter SSecurityFactoryStandard::sec_types
+("SecurityTypes",
+ "Specify which security scheme to use for incoming connections (None, VncAuth)",
+ "VncAuth");
+
+StringParameter SSecurityFactoryStandard::rev_sec_types
+("ReverseSecurityTypes",
+ "Specify encryption scheme to use for reverse connections (None)",
+ "None");
 
 
-SSecurity* SSecurityFactoryStandard::getSSecurity(int secType, bool noAuth) {
+StringParameter SSecurityFactoryStandard::vncAuthPasswdFile
+("PasswordFile", "Password file for VNC authentication", "");
+VncAuthPasswdParameter SSecurityFactoryStandard::vncAuthPasswd
+("Password", "Obfuscated binary encoding of the password which clients must supply to "
+ "access the server", &SSecurityFactoryStandard::vncAuthPasswdFile);
+
+
+SSecurity* SSecurityFactoryStandard::getSSecurity(rdr::U8 secType, bool reverseConnection) {
   switch (secType) {
-  case secTypeNone:    return new SSecurityNone();
+  case secTypeNone: return new SSecurityNone();
   case secTypeVncAuth:
-    if (!vncAuthPasswd)
-      throw rdr::Exception("No VncAuthPasswdParameter defined!");
-    return new SSecurityVncAuth(vncAuthPasswd);
+    return new SSecurityVncAuth(&vncAuthPasswd);
   default:
-    throw Exception("Unsupported secType?");
+    throw Exception("Security type not supported");
   }
 }
 
-VncAuthPasswdParameter::VncAuthPasswdParameter() {
-  if (SSecurityFactoryStandard::vncAuthPasswd)
-    throw rdr::Exception("duplicate VncAuthPasswdParameter!");
-  SSecurityFactoryStandard::vncAuthPasswd = this;
+void SSecurityFactoryStandard::getSecTypes(std::list<rdr::U8>* secTypes, bool reverseConnection) {
+  CharArray secTypesStr;
+  if (reverseConnection)
+    secTypesStr.buf = rev_sec_types.getData();
+  else
+    secTypesStr.buf = sec_types.getData();
+  std::list<int> configured = parseSecTypes(secTypesStr.buf);
+  std::list<int>::iterator i;
+  for (i=configured.begin(); i!=configured.end(); i++) {
+    if (isSecTypeSupported(*i))
+      secTypes->push_back(*i);
+  }
+}
+
+bool SSecurityFactoryStandard::isSecTypeSupported(rdr::U8 secType) {
+  switch (secType) {
+  case secTypeNone:
+  case secTypeVncAuth:
+    return true;
+  default:
+    return false;
+  }
 }
 
 
-VncAuthPasswdConfigParameter::VncAuthPasswdConfigParameter()
-: passwdParam("Password",
-   "Obfuscated binary encoding of the password which clients must supply to "
-   "access the server", 0, 0) {
+VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name,
+                                               const char* desc,
+                                               StringParameter* passwdFile_)
+: BinaryParameter(name, desc, 0, 0), passwdFile(passwdFile_) {
 }
 
-char* VncAuthPasswdConfigParameter::getVncAuthPasswd() {
-  CharArray obfuscated;
-  int len;
-  passwdParam.getData((void**)&obfuscated.buf, &len);
-  printf("vnc password len=%d\n", len); // ***
-  if (len == 8) {
-    CharArray password(9);
-    memcpy(password.buf, obfuscated.buf, 8);
-    vncAuthUnobfuscatePasswd(password.buf);
+char* VncAuthPasswdParameter::getVncAuthPasswd() {
+  ObfuscatedPasswd obfuscated;
+  getData((void**)&obfuscated.buf, &obfuscated.length);
+
+  if (obfuscated.length == 0) {
+    if (passwdFile) {
+      CharArray fname(passwdFile->getData());
+      if (!fname.buf[0]) {
+        vlog.info("neither %s nor %s params set", getName(), passwdFile->getName());
+        return 0;
+      }
+
+      FILE* fp = fopen(fname.buf, "r");
+      if (!fp) {
+        vlog.error("opening password file '%s' failed",fname.buf);
+        return 0;
+      }
+
+      vlog.debug("reading password file");
+      obfuscated.buf = new char[128];
+      obfuscated.length = fread(obfuscated.buf, 1, 128, fp);
+      fclose(fp);
+    } else {
+      vlog.info("%s parameter not set", getName());
+    }
+  }
+
+  try {
+    PlainPasswd password(obfuscated);
     return password.takeBuf();
-  }
-  return 0;
-}
-
-
-VncAuthPasswdFileParameter::VncAuthPasswdFileParameter()
-  : param("PasswordFile", "Password file for VNC authentication", "") {
-}
-
-char* VncAuthPasswdFileParameter::getVncAuthPasswd() {
-  CharArray fname(param.getData());
-  if (!fname.buf[0]) {
-    vlog.error("passwordFile parameter not set");
+  } catch (...) {
     return 0;
   }
-  FILE* fp = fopen(fname.buf, "r");
-  if (!fp) {
-    vlog.error("opening password file '%s' failed",fname.buf);
-    return 0;
-  }
-  CharArray passwd(9);
-  int len = fread(passwd.buf, 1, 9, fp);
-  fclose(fp);
-  if (len != 8) {
-    vlog.error("password file '%s' is the wrong length",fname.buf);
-    return 0;
-  }
-  vncAuthUnobfuscatePasswd(passwd.buf);
-  return passwd.takeBuf();
 }
 
+
diff --git a/rfb/SSecurityFactoryStandard.h b/rfb/SSecurityFactoryStandard.h
index 5fced04..165881e 100644
--- a/rfb/SSecurityFactoryStandard.h
+++ b/rfb/SSecurityFactoryStandard.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -44,31 +44,24 @@
 
 namespace rfb {
 
-  class VncAuthPasswdParameter : public VncAuthPasswdGetter {
+  class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter {
   public:
-    VncAuthPasswdParameter();
-    virtual ~VncAuthPasswdParameter() {}
+    VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_);
+    virtual char* getVncAuthPasswd();
+  protected:
+    StringParameter* passwdFile;
   };
 
   class SSecurityFactoryStandard : public SSecurityFactory {
   public:
-    virtual SSecurity* getSSecurity(int secType, bool noAuth);
-    static VncAuthPasswdParameter* vncAuthPasswd;
-  };
-
-  class VncAuthPasswdConfigParameter : public VncAuthPasswdParameter {
-  public:
-    VncAuthPasswdConfigParameter();
-    virtual char* getVncAuthPasswd();
+    virtual SSecurity* getSSecurity(rdr::U8 secType, bool reverse);
+    virtual void getSecTypes(std::list<rdr::U8>* secTypes, bool reverse);
+    static StringParameter sec_types;
+    static StringParameter rev_sec_types;
+    static StringParameter vncAuthPasswdFile;
+    static VncAuthPasswdParameter vncAuthPasswd;
   protected:
-    BinaryParameter passwdParam;
-  };
-
-  class VncAuthPasswdFileParameter : public VncAuthPasswdParameter {
-  public:
-    VncAuthPasswdFileParameter();
-    virtual char* getVncAuthPasswd();
-    StringParameter param;
+    virtual bool isSecTypeSupported(rdr::U8 secType);
   };
 
 }
diff --git a/rfb/SSecurityNone.h b/rfb/SSecurityNone.h
index 09b2db4..5c19f29 100644
--- a/rfb/SSecurityNone.h
+++ b/rfb/SSecurityNone.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -28,9 +28,7 @@
 
   class SSecurityNone : public SSecurity {
   public:
-    virtual bool processMsg(SConnection* sc, bool* done) {
-      *done = true; return true;
-    }
+    virtual bool processMsg(SConnection* sc) { return true; }
     virtual int getType() const {return secTypeNone;}
     virtual const char* getUserName() const {return 0;}
   };
diff --git a/rfb/SSecurityVncAuth.cxx b/rfb/SSecurityVncAuth.cxx
index 532d1a6..29a3b96 100644
--- a/rfb/SSecurityVncAuth.cxx
+++ b/rfb/SSecurityVncAuth.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -18,20 +18,27 @@
 //
 // SSecurityVncAuth
 //
+// XXX not thread-safe, because d3des isn't - do we need to worry about this?
+//
 
 #include <rfb/SSecurityVncAuth.h>
 #include <rdr/RandomStream.h>
 #include <rfb/SConnection.h>
-#include <rfb/vncAuth.h>
+#include <rfb/Password.h>
 #include <rfb/Configuration.h>
 #include <rfb/LogWriter.h>
 #include <rfb/util.h>
+#include <rfb/Exception.h>
 #include <string.h>
 #include <stdio.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+
 
 using namespace rfb;
 
-static LogWriter vlog("VncAuth");
+static LogWriter vlog("SVncAuth");
 
 
 SSecurityVncAuth::SSecurityVncAuth(VncAuthPasswdGetter* pg_)
@@ -39,9 +46,8 @@
 {
 }
 
-bool SSecurityVncAuth::processMsg(SConnection* sc, bool* done)
+bool SSecurityVncAuth::processMsg(SConnection* sc)
 {
-  *done = false;
   rdr::InStream* is = sc->getInStream();
   rdr::OutStream* os = sc->getOutStream();
 
@@ -51,33 +57,31 @@
     os->writeBytes(challenge, vncAuthChallengeSize);
     os->flush();
     sentChallenge = true;
-    return true;
+    return false;
   }
 
-  if (responsePos >= vncAuthChallengeSize) return false;
-  while (is->checkNoWait(1) && responsePos < vncAuthChallengeSize) {
+  while (responsePos < vncAuthChallengeSize && is->checkNoWait(1))
     response[responsePos++] = is->readU8();
-  }
 
-  if (responsePos < vncAuthChallengeSize) return true;
+  if (responsePos < vncAuthChallengeSize) return false;
 
-  CharArray passwd(pg->getVncAuthPasswd());
+  PlainPasswd passwd(pg->getVncAuthPasswd());
 
-  // Beyond this point, there is no more VNCAuth protocol to perform.
-  *done = true;
+  if (!passwd.buf)
+    throw AuthFailureException("No password configured for VNC Auth");
 
-  if (!passwd.buf) {
-    failureMessage_.buf = strDup("No password configured for VNC Auth");
-    vlog.error(failureMessage_.buf);
-    return false;
-  }
+  // Calculate the expected response
+  rdr::U8 key[8];
+  int pwdLen = strlen(passwd.buf);
+  for (int i=0; i<8; i++)
+    key[i] = i<pwdLen ? passwd.buf[i] : 0;
+  deskey(key, EN0);
+  for (int j = 0; j < vncAuthChallengeSize; j += 8)
+    des(challenge+j, challenge+j);
 
-  vncAuthEncryptChallenge(challenge, passwd.buf);
-  memset(passwd.buf, 0, strlen(passwd.buf));
-
-  if (memcmp(challenge, response, vncAuthChallengeSize) != 0) {
-    return false;
-  }
+  // Check the actual response
+  if (memcmp(challenge, response, vncAuthChallengeSize) != 0)
+    throw AuthFailureException();
 
   return true;
 }
diff --git a/rfb/SSecurityVncAuth.h b/rfb/SSecurityVncAuth.h
index edbd720..1d0a82d 100644
--- a/rfb/SSecurityVncAuth.h
+++ b/rfb/SSecurityVncAuth.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -26,7 +26,7 @@
 
 #include <rfb/SSecurity.h>
 #include <rfb/secTypes.h>
-#include <rfb/vncAuth.h>
+#include <rdr/types.h>
 
 namespace rfb {
 
@@ -40,10 +40,11 @@
   class SSecurityVncAuth : public SSecurity {
   public:
     SSecurityVncAuth(VncAuthPasswdGetter* pg);
-    virtual bool processMsg(SConnection* sc, bool* done);
+    virtual bool processMsg(SConnection* sc);
     virtual int getType() const {return secTypeVncAuth;}
     virtual const char* getUserName() const {return 0;}
   private:
+    enum {vncAuthChallengeSize = 16};
     rdr::U8 challenge[vncAuthChallengeSize];
     rdr::U8 response[vncAuthChallengeSize];
     bool sentChallenge;
diff --git a/rfb/ServerCore.cxx b/rfb/ServerCore.cxx
index fe61ecb..750daae 100644
--- a/rfb/ServerCore.cxx
+++ b/rfb/ServerCore.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -24,38 +24,29 @@
 #include <string.h>
 #include <rfb/util.h>
 #include <rfb/ServerCore.h>
-#include <rfb/vncAuth.h>
 
 rfb::IntParameter rfb::Server::idleTimeout
 ("IdleTimeout",
- "The number of seconds after which an idle VNC connection will be dropped",
- 0);
-
+ "The number of seconds after which an idle VNC connection will be dropped "
+ "(zero means no timeout)",
+ 0, 0);
 rfb::IntParameter rfb::Server::maxDisconnectionTime
 ("MaxDisconnectionTime",
  "Terminate when no client has been connected for s seconds", 
- 0);
+ 0, 0);
 rfb::IntParameter rfb::Server::maxConnectionTime
 ("MaxConnectionTime",
  "Terminate when a client has been connected for s seconds", 
- 0);
+ 0, 0);
 rfb::IntParameter rfb::Server::maxIdleTime
 ("MaxIdleTime",
  "Terminate after s seconds of user inactivity", 
- 0);
+ 0, 0);
 rfb::IntParameter rfb::Server::clientWaitTimeMillis
 ("ClientWaitTimeMillis",
  "The number of milliseconds to wait for a client which is no longer "
  "responding",
- 20000);
-rfb::StringParameter rfb::Server::sec_types
-("SecurityTypes",
- "Specify which security scheme to use for incoming connections (None, VncAuth)",
- "VncAuth");
-rfb::StringParameter rfb::Server::rev_sec_types
-("ReverseSecurityTypes",
- "Specify encryption scheme to use for reverse connections (None)",
- "None");
+ 20000, 0);
 rfb::BoolParameter rfb::Server::compareFB
 ("CompareFB",
  "Perform pixel comparison on framebuffer to reduce unnecessary updates",
@@ -101,8 +92,3 @@
 ("QueryConnect",
  "Prompt the local user to accept or reject incoming connections.",
  false);
-rfb::IntParameter rfb::Server::blacklistLevel
-("BlacklistLevel",
- "When to test whether particular host should be blacklisted.  (0 = Never, "
- "1 = Test before authentication, 2 = Test on connect)",
- 1);
diff --git a/rfb/ServerCore.h b/rfb/ServerCore.h
index b01fcfd..68d7b74 100644
--- a/rfb/ServerCore.h
+++ b/rfb/ServerCore.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -37,8 +37,6 @@
     static IntParameter maxConnectionTime;
     static IntParameter maxIdleTime;
     static IntParameter clientWaitTimeMillis;
-    static StringParameter sec_types;
-    static StringParameter rev_sec_types;
     static BoolParameter compareFB;
     static BoolParameter protocol3_3;
     static BoolParameter alwaysShared;
@@ -49,7 +47,6 @@
     static BoolParameter acceptCutText;
     static BoolParameter sendCutText;
     static BoolParameter queryConnect;
-    static IntParameter blacklistLevel;
 
   };
 
diff --git a/rfb/Threading.h b/rfb/Threading.h
index effc436..66b3aa0 100644
--- a/rfb/Threading.h
+++ b/rfb/Threading.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -25,7 +25,7 @@
 #define __RFB_THREADING_H__
 
 #ifdef WIN32
-#include <rfb/win32/Threading_win32.h>
+#include <rfb_win32/Threading.h>
 #endif
 
 #endif // __RFB_THREADING_H__
diff --git a/rfb/TransImageGetter.cxx b/rfb/TransImageGetter.cxx
index 0b494a9..82c291b 100644
--- a/rfb/TransImageGetter.cxx
+++ b/rfb/TransImageGetter.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/TransImageGetter.h b/rfb/TransImageGetter.h
index 60ab069..5328e6d 100644
--- a/rfb/TransImageGetter.h
+++ b/rfb/TransImageGetter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/TrueColourMap.h b/rfb/TrueColourMap.h
index c0d4907..1e87fa4 100644
--- a/rfb/TrueColourMap.h
+++ b/rfb/TrueColourMap.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/UpdateTracker.cxx b/rfb/UpdateTracker.cxx
index cc0fb10..14ac49d 100644
--- a/rfb/UpdateTracker.cxx
+++ b/rfb/UpdateTracker.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -30,34 +30,34 @@
 
 static LogWriter vlog("UpdateTracker");
 
-// -=- ClippedUpdateTracker
 
-void ClippedUpdateTracker::add_changed(const Region &region) {
-  child.add_changed(region.intersect(cliprgn));
+// -=- ClippingUpdateTracker
+
+void ClippingUpdateTracker::add_changed(const Region &region) {
+  ut->add_changed(region.intersect(clipRect));
 }
 
-void ClippedUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
   // Clip the destination to the display area
-  Region clipdest = dest.intersect(cliprgn);
+  Region clipdest = dest.intersect(clipRect);
   if (clipdest.is_empty())  return;
 
   // Clip the source to the screen
   Region tmp = clipdest;
   tmp.translate(delta.negate());
-  tmp.assign_intersect(cliprgn);
+  tmp.assign_intersect(clipRect);
   if (!tmp.is_empty()) {
     // Translate the source back to a destination region
     tmp.translate(delta);
 
     // Pass the copy region to the child tracker
-    child.add_copied(tmp, delta);
+    ut->add_copied(tmp, delta);
   }
 
   // And add any bits that we had to remove to the changed region
   tmp = clipdest.subtract(tmp);
-  if (!tmp.is_empty()) {
-    child.add_changed(tmp);
-  }
+  if (!tmp.is_empty())
+    ut->add_changed(tmp);
 }
 
 // SimpleUpdateTracker
@@ -140,7 +140,7 @@
   changed.assign_subtract(region);
 }
 
-void SimpleUpdateTracker::get_update(UpdateInfo* info, const Region& clip)
+void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
 {
   copied.assign_subtract(changed);
   info->changed = changed.intersect(clip);
@@ -148,25 +148,9 @@
   info->copy_delta = copy_delta;
 }
 
-void SimpleUpdateTracker::flush_update(UpdateTracker &info,
-                                       const Region &cliprgn)
-{
-  Region copied_clipped = copied.intersect(cliprgn);
-  Region changed_clipped = changed.intersect(cliprgn);
-  copied.assign_subtract(copied_clipped);
-  changed.assign_subtract(changed_clipped);
-  if (!copied_clipped.is_empty()) {
-    info.add_copied(copied_clipped, copy_delta);
-  }
-  if (!changed_clipped.is_empty())
-    info.add_changed(changed_clipped);
-}
-
-void SimpleUpdateTracker::get_update(UpdateTracker &to) const {
-  if (!copied.is_empty()) {
-    to.add_copied(copied, copy_delta);
-  }
-  if (!changed.is_empty()) {
-    to.add_changed(changed);
-  }
+void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
+  if (!copied.is_empty())
+    to->add_copied(copied, copy_delta);
+  if (!changed.is_empty())
+    to->add_changed(changed);
 }
diff --git a/rfb/UpdateTracker.h b/rfb/UpdateTracker.h
index 5015a25..5b51317 100644
--- a/rfb/UpdateTracker.h
+++ b/rfb/UpdateTracker.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -47,25 +47,24 @@
     virtual void add_copied(const Region &dest, const Point &delta) = 0;
   };
 
-  class ClippedUpdateTracker : public UpdateTracker {
+  class ClippingUpdateTracker : public UpdateTracker {
   public:
-    ClippedUpdateTracker(UpdateTracker &child_) : child(child_) {};
-    ClippedUpdateTracker(UpdateTracker &child_,
-      const Region &cliprgn_) : child(child_), cliprgn(cliprgn_) {};
-    virtual ~ClippedUpdateTracker() {};
-
-    virtual void set_clip_region(const Region cliprgn_) {cliprgn = cliprgn_;};
+    ClippingUpdateTracker() : ut(0) {}
+    ClippingUpdateTracker(UpdateTracker* ut_, const Rect& r=Rect()) : ut(ut_), clipRect(r) {}
+    
+    void setUpdateTracker(UpdateTracker* ut_) {ut = ut_;}
+    void setClipRect(const Rect& cr) {clipRect = cr;}
 
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
   protected:
-    UpdateTracker &child;
-    Region cliprgn;
+    UpdateTracker* ut;
+    Region clipRect;
   };
 
   class SimpleUpdateTracker : public UpdateTracker {
   public:
-    SimpleUpdateTracker(bool use_copyrect=false);
+    SimpleUpdateTracker(bool use_copyrect=true);
     virtual ~SimpleUpdateTracker();
 
     virtual void enable_copyrect(bool enable);
@@ -75,13 +74,10 @@
     virtual void subtract(const Region& region);
 
     // Fill the supplied UpdateInfo structure with update information
-    virtual void get_update(UpdateInfo* info, const Region& cliprgn);
+    virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
 
-    // Pass the current updates to the supplied tracker
-    virtual void get_update(UpdateTracker &to) const;
-
-    // Also removes the updates that are returned from this update tracker
-    virtual void flush_update(UpdateTracker &to, const Region &cliprgn);
+    // Copy the contained updates to another tracker
+    virtual void copyTo(UpdateTracker* to) const;
 
 
     // Get the changed/copied regions
diff --git a/rfb/UserPasswdGetter.h b/rfb/UserPasswdGetter.h
index c242ed0..18b0bae 100644
--- a/rfb/UserPasswdGetter.h
+++ b/rfb/UserPasswdGetter.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -20,12 +20,11 @@
 namespace rfb {
   class UserPasswdGetter {
   public:
-    // getUserPasswd gets the username and password.  This might
-    // involve a dialog, getpass(), etc.  The user buffer pointer
-    // can be null, in which case no user name will be retrieved.
-    // The caller MUST delete [] the result(s) iff the
-    // call succeeds (returns true), and ignore them if failed.
-    virtual bool getUserPasswd(char** user, char** password)=0;
+    // getUserPasswd gets the username and password.  This might involve a
+    // dialog, getpass(), etc.  The user buffer pointer can be null, in which
+    // case no user name will be retrieved.  The caller MUST delete [] the
+    // result(s).
+    virtual void getUserPasswd(char** user, char** password)=0;
   };
 }
 #endif
diff --git a/rfb/VNCSConnectionST.cxx b/rfb/VNCSConnectionST.cxx
index 9895761..37fb744 100644
--- a/rfb/VNCSConnectionST.cxx
+++ b/rfb/VNCSConnectionST.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -21,6 +21,7 @@
 #include <rfb/secTypes.h>
 #include <rfb/ServerCore.h>
 #include <rfb/ComparingUpdateTracker.h>
+#include <rfb/KeyRemapper.h>
 #define XK_MISCELLANY
 #define XK_XKB_KEYS
 #include <rfb/keysymdef.h>
@@ -31,8 +32,8 @@
 
 VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
                                    bool reverse)
-  : sock(s), reverseConnection(reverse), server(server_),
-    image_getter(server->useEconomicTranslate),
+  : SConnection(server_->securityFactory, reverse), sock(s), server(server_),
+    updates(false), image_getter(server->useEconomicTranslate),
     drawRenderedCursor(false), removeRenderedCursor(false),
     pointerEventTime(0), accessRights(AccessDefault),
     startTime(time(0))
@@ -41,21 +42,11 @@
   peerEndpoint.buf = sock->getPeerEndpoint();
   VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
 
+  // Configure the socket
   setSocketTimeouts();
   lastEventTime = time(0);
 
-  // Initialise security
-  CharArray sec_types_str;
-  if (reverseConnection)
-    sec_types_str.buf = rfb::Server::rev_sec_types.getData();
-  else
-    sec_types_str.buf = rfb::Server::sec_types.getData();
-  std::list<int> sec_types = parseSecTypes(sec_types_str.buf);
-  std::list<int>::iterator i;
-  for (i=sec_types.begin(); i!=sec_types.end(); i++) {
-    addSecType(*i);
-  }
-
+  // Add this client to the VNCServerST
   server->clients.push_front(this);
 }
 
@@ -64,7 +55,8 @@
 {
   // If we reach here then VNCServerST is deleting us!
   VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
-                                    peerEndpoint.buf, closeReason.buf);
+                                    peerEndpoint.buf,
+                                    (closeReason.buf) ? closeReason.buf : "");
 
   // Release any keys the client still had pressed
   std::set<rdr::U32>::iterator i;
@@ -103,16 +95,17 @@
       server->lastDisconnectTime = time(0);
   }
 
-  // Just shutdown the socket.  This will cause processMessages to
-  // eventually fail, causing us and our socket to be deleted.
+  // 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);
 }
 
 
-bool VNCSConnectionST::processMessages()
+void VNCSConnectionST::processMessages()
 {
-  if (state() == RFBSTATE_CLOSING) return false;
+  if (state() == RFBSTATE_CLOSING) return;
   try {
     // - Now set appropriate socket timeouts and process data
     setSocketTimeouts();
@@ -124,15 +117,11 @@
 
     if (!clientsReadyBefore && !requested.is_empty())
       server->desktop->framebufferUpdateRequest();
-
-    return true;
-
   } catch (rdr::EndOfStream&) {
     close("Clean disconnection");
   } catch (rdr::Exception &e) {
     close(e.str());
   }
-  return false;
 }
 
 void VNCSConnectionST::writeFramebufferUpdateOrClose()
@@ -170,9 +159,11 @@
 
       cp.width = server->pb->width();
       cp.height = server->pb->height();
-      if (!writer()->writeSetDesktopSize()) {
-        close("Client does not support desktop resize");
-        return;
+      if (state() == RFBSTATE_NORMAL) {
+        if (!writer()->writeSetDesktopSize()) {
+          close("Client does not support desktop resize");
+          return;
+        }
       }
     }
     // Just update the whole screen at the moment because we're too lazy to
@@ -248,13 +239,13 @@
     // now.
     vlog.info("Time has gone forwards - resetting idle timeout");
     lastEventTime = now;
-    return idleTimeout;
+    return secsToMillis(idleTimeout);
   }
   if (timeLeft <= 0) {
     close("Idle timeout");
     return 0;
   }
-  return timeLeft * 1000;
+  return secsToMillis(timeLeft);
 }
 
 // renderedCursorChange() is called whenever the server-side rendered cursor
@@ -302,29 +293,10 @@
 
 // -=- Callbacks from SConnection
 
-void VNCSConnectionST::versionReceived() {
-  CharArray address(sock->getPeerAddress());
-  if ((rfb::Server::blacklistLevel == 1) &&
-      server->blHosts->isBlackmarked(address.buf)) {
-    server->connectionsLog.error("blacklisted: %s", address.buf);
-    throwConnFailedException("Too many security failures");
-  }
-}
-
-SSecurity* VNCSConnectionST::getSSecurity(int secType) {
-  if (!server->securityFactory)
-    throw rdr::Exception("no SSecurityFactory registered!");
-  return server->securityFactory->getSSecurity(secType, reverseConnection);
-}
-
 void VNCSConnectionST::authSuccess()
 {
   lastEventTime = time(0);
 
-  // - Authentication succeeded - clear from blacklist
-  CharArray name; name.buf = sock->getPeerAddress();
-  server->blHosts->clearBlackmark(name.buf);
-
   server->startDesktop();
 
   // - Set the connection parameters appropriately
@@ -346,18 +318,36 @@
 
 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 ||
+  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 (qr == VNCServerST::PENDING)
+    return;
+
+  // - If server returns ACCEPT/REJECT then pass result to SConnection
   approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
 }
 
@@ -372,7 +362,8 @@
       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
+      // - Refuse this connection if there are existing clients, in addition to
+      // this one
       if (server->authClientCount() > 1) {
         close("Server is already in use");
         return;
@@ -392,14 +383,14 @@
   setCursor();
 }
 
-void VNCSConnectionST::pointerEvent(int x, int y, int buttonMask)
+void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
 {
   pointerEventTime = lastEventTime = time(0);
   server->lastUserInputTime = lastEventTime;
   if (!(accessRights & AccessPtrEvents)) return;
   if (!rfb::Server::acceptPointerEvents) return;
   if (!server->pointerClient || server->pointerClient == this) {
-    pointerEventPos = Point(x, y);
+    pointerEventPos = pos;
     if (buttonMask)
       server->pointerClient = this;
     else
@@ -432,6 +423,10 @@
   if (!(accessRights & AccessKeyEvents)) return;
   if (!rfb::Server::acceptKeyEvents) return;
 
+  // Remap the key if required
+  if (server->keyRemapper)
+    key = server->keyRemapper->remapKey(key);
+
   // Turn ISO_Left_Tab into shifted Tab.
   VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
   if (key == XK_ISO_Left_Tab) {
@@ -522,10 +517,9 @@
   image_getter.translatePixels(server->cursor.data, transData,
 			       server->cursor.area());
   writer()->writeSetCursor(server->cursor.width(),
-			   server->cursor.height(),
-			   server->cursor.hotspot.x,
-			   server->cursor.hotspot.y,
-			   transData, server->cursor.mask.buf);
+                           server->cursor.height(),
+                           server->cursor.hotspot,
+                           transData, server->cursor.mask.buf);
 }
 
 
@@ -574,7 +568,7 @@
     if (renderedCursorRect.is_empty()) {
       drawRenderedCursor = false;
     } else if (!updates.get_changed().union_(updates.get_copied())
-        .intersect(renderedCursorRect).is_empty()) {
+               .intersect(renderedCursorRect).is_empty()) {
       drawRenderedCursor = true;
     }
 
@@ -589,7 +583,7 @@
 
   UpdateInfo update;
   updates.enable_copyrect(cp.useCopyRect);
-  updates.get_update(&update, requested);
+  updates.getUpdateInfo(&update, requested);
   if (!update.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) {
     // Compute the number of rectangles. Tight encoder makes the things more
     // complicated as compared to the original RealVNC.
@@ -660,11 +654,9 @@
 void VNCSConnectionST::setSocketTimeouts()
 {
   int timeoutms = rfb::Server::clientWaitTimeMillis;
-  if (timeoutms == 0 || timeoutms > rfb::Server::idleTimeout * 1000) {
-    timeoutms = rfb::Server::idleTimeout * 1000;
-    if (timeoutms == 0)
-      timeoutms = -1;
-  }
+  soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
+  if (timeoutms == 0)
+    timeoutms = -1;
   sock->inStream().setTimeout(timeoutms);
   sock->outStream().setTimeout(timeoutms);
 }
diff --git a/rfb/VNCSConnectionST.h b/rfb/VNCSConnectionST.h
index 7813c04..a9a356c 100644
--- a/rfb/VNCSConnectionST.h
+++ b/rfb/VNCSConnectionST.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -56,9 +56,9 @@
 
     // processMessages() processes incoming messages from the client, invoking
     // various callbacks as a result.  It continues to process messages until
-    // reading might block.  Returns true if the client is still valid &
-    // active, or false if it has disconnected or an error has occurred.
-    bool processMessages();
+    // reading might block.  shutdown() will be called on the connection's
+    // Socket if an error occurs, via the close() call.
+    void processMessages();
 
     void writeFramebufferUpdateOrClose();
     void pixelBufferChange();
@@ -117,16 +117,14 @@
     // none of these methods should call any of the above methods which may
     // delete the SConnectionST object.
 
-    virtual void versionReceived();
-    virtual SSecurity* getSSecurity(int secType);
     virtual void authSuccess();
     virtual void queryConnection(const char* userName);
     virtual void clientInit(bool shared);
     virtual void setPixelFormat(const PixelFormat& pf);
-    virtual void pointerEvent(int x, int y, int buttonMask);
+    virtual void pointerEvent(const Point& pos, int buttonMask);
     virtual void keyEvent(rdr::U32 key, bool down);
-    virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
     virtual void clientCutText(const char* str, int len);
+    virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
     virtual void setInitialColourMap();
     virtual void supportsLocalCursor();
 
@@ -153,7 +151,6 @@
 
     network::Socket* sock;
     CharArray peerEndpoint;
-    bool reverseConnection;
     VNCServerST* server;
     SimpleUpdateTracker updates;
     TransImageGetter image_getter;
diff --git a/rfb/VNCServer.h b/rfb/VNCServer.h
index e80044c..df0fb0e 100644
--- a/rfb/VNCServer.h
+++ b/rfb/VNCServer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -69,11 +69,11 @@
     // significant bit represents the leftmost pixel, and the bytes are simply
     // in left-to-right order.  The server takes its own copy of the data in
     // cursorData and mask.
-    virtual void setCursor(int width, int height, int hotspotX, int hotspotY,
+    virtual void setCursor(int width, int height, const Point& hotspot,
                            void* cursorData, void* mask) = 0;
 
     // setCursorPos() tells the server the current position of the cursor.
-    virtual void setCursorPos(int x, int y) = 0;
+    virtual void setCursorPos(const Point& p) = 0;
 
     // setSSecurityFactory() tells the server which factory to use when
     // attempting to authenticate connections.
diff --git a/rfb/VNCServerST.cxx b/rfb/VNCServerST.cxx
index 0721a3c..7e3e0c6 100644
--- a/rfb/VNCServerST.cxx
+++ b/rfb/VNCServerST.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -32,25 +32,19 @@
 // reason for disconnecting clients is when the desktop size has changed as a
 // result of a call to setPixelBuffer().
 //
-// Because we don't want to mess up any data structures which the calling code
-// may maintain regarding sockets with data to process, we can't just delete a
-// socket when we decide to close the connection to a client.  Instead, we only
-// go as far as calling shutdown() on the socket.  This should ensure that
-// eventually the calling code will get round to calling processSocketEvent()
-// for that socket.  Then we can delete the VNCSConnectionST object and its
-// associated network::Socket object, and return false from that call to let
-// the calling code know that the socket has been deleted.  This is the only
-// way that these objects get deleted.
-//
-// It is possible that there are platforms where calling shutdown() cannot
-// guarantee that processSocketEvent() will be called - if so then it may be
-// necessary to introduce some kind of "socket closure callback", but we'll
-// only do that if it proves absolutely necessary.
+// The responsibility for creating and deleting sockets is entirely with the
+// calling code.  When VNCServerST wants to close a connection to a client it
+// calls the VNCSConnectionST's close() method which calls shutdown() on the
+// socket.  Eventually the calling code will notice that the socket has been
+// shut down and call removeSocket() so that we can delete the
+// VNCSConnectionST.  Note that the socket must not be deleted by the calling
+// code until after removeSocket() has been called.
 //
 // One minor complication is that we don't allocate a VNCSConnectionST object
 // for a blacklisted host (since we want to minimise the resources used for
-// dealing with such a connection).  So we maintain a separate list of
-// closingSockets for this purpose.
+// dealing with such a connection).  In order to properly implement the
+// getSockets function, we must maintain a separate closingSockets list,
+// otherwise blacklisted connections might be "forgotten".
 
 
 #include <rfb/ServerCore.h>
@@ -58,6 +52,7 @@
 #include <rfb/VNCSConnectionST.h>
 #include <rfb/ComparingUpdateTracker.h>
 #include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/KeyRemapper.h>
 #include <rfb/util.h>
 
 #include <rdr/types.h>
@@ -80,7 +75,8 @@
     name(strDup(name_)), pointerClient(0), comparer(0),
     renderedCursorInvalid(false),
     securityFactory(sf ? sf : &defaultSecurityFactory),
-    queryConnectionHandler(0), useEconomicTranslate(false),
+    queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
+    useEconomicTranslate(false),
     lastConnectionTime(0), disableclients(false)
 {
   lastUserInputTime = lastDisconnectTime = time(0);
@@ -97,13 +93,8 @@
   // 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()->getSock();
     delete clients.front();
   }
-  while (!closingSockets.empty()) {
-    delete closingSockets.front();
-    closingSockets.pop_front();
-  }
 
   // Stop the desktop object if active, *only* after deleting all clients!
   if (desktopStarted) {
@@ -117,18 +108,12 @@
 
 // SocketServer methods
 
-void VNCServerST::addClient(network::Socket* sock)
-{
-  addClient(sock, false);
-}
-
-void VNCServerST::addClient(network::Socket* sock, bool reverse)
+void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
 {
   // - Check the connection isn't black-marked
   // *** do this in getSecurity instead?
   CharArray address(sock->getPeerAddress());
-  if ((rfb::Server::blacklistLevel == 2) &&
-      blHosts->isBlackmarked(address.buf)) {
+  if (blHosts->isBlackmarked(address.buf)) {
     connectionsLog.error("blacklisted: %s", address.buf);
     try {
       SConnection::writeConnFailedFromScratch("Too many security failures",
@@ -144,37 +129,43 @@
     lastConnectionTime = time(0);
   }
 
-  VNCSConnectionST* client = new VNCSConnectionST(this, sock, reverse);
+  VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
   client->init();
 }
 
-bool VNCServerST::processSocketEvent(network::Socket* sock)
+void VNCServerST::removeSocket(network::Socket* sock) {
+  // - If the socket has resources allocated to it, delete them
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    if ((*ci)->getSock() == sock) {
+      // - Delete the per-Socket resources
+      delete *ci;
+
+      // - Check that the desktop object is still required
+      if (authClientCount() == 0 && desktopStarted) {
+        slog.debug("no authenticated clients - stopping desktop");
+        desktopStarted = false;
+        desktop->stop();
+      }
+      return;
+    }
+  }
+
+  // - If the Socket has no resources, it may have been a closingSocket
+  closingSockets.remove(sock);
+}
+
+void VNCServerST::processSocketEvent(network::Socket* sock)
 {
   // - Find the appropriate VNCSConnectionST and process the event
   std::list<VNCSConnectionST*>::iterator ci;
   for (ci = clients.begin(); ci != clients.end(); ci++) {
     if ((*ci)->getSock() == sock) {
-      if ((*ci)->processMessages())
-        return true;
-      // processMessages failed, so delete the client
-      delete *ci;
-      break;
+      (*ci)->processMessages();
+      return;
     }
   }
-
-  // - If no client is using the Socket then delete it
-  closingSockets.remove(sock);
-  delete sock;
-
-  // - Check that the desktop object is still required
-  if (authClientCount() == 0 && desktopStarted) {
-    slog.debug("no authenticated clients - stopping desktop");
-    desktopStarted = false;
-    desktop->stop();
-  }
-  
-  // - Inform the caller not to continue handling the Socket
-  return false;
+  throw rdr::Exception("invalid Socket in VNCServerST");
 }
 
 int VNCServerST::checkTimeouts()
@@ -342,11 +333,10 @@
   }
 }
 
-void VNCServerST::setCursor(int width, int height, int newHotspotX,
-                            int newHotspotY, void* data, void* mask)
+void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
+                            void* data, void* mask)
 {
-  cursor.hotspot.x = newHotspotX;
-  cursor.hotspot.y = newHotspotY;
+  cursor.hotspot = newHotspot;
   cursor.setSize(width, height);
   memcpy(cursor.data, data, cursor.dataLen());
   memcpy(cursor.mask.buf, mask, cursor.maskLen());
@@ -363,11 +353,10 @@
   }
 }
 
-void VNCServerST::setCursorPos(int x, int y)
+void VNCServerST::setCursorPos(const Point& pos)
 {
-  if (cursorPos.x != x || cursorPos.y != y) {
-    cursorPos.x = x;
-    cursorPos.y = y;
+  if (!cursorPos.equals(pos)) {
+    cursorPos = pos;
     renderedCursorInvalid = true;
     std::list<VNCSConnectionST*>::iterator ci;
     for (ci = clients.begin(); ci != clients.end(); ci++)
diff --git a/rfb/VNCServerST.h b/rfb/VNCServerST.h
index 3d25fca..162fa9a 100644
--- a/rfb/VNCServerST.h
+++ b/rfb/VNCServerST.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -39,6 +39,7 @@
   class VNCSConnectionST;
   class ComparingUpdateTracker;
   class PixelBuffer;
+  class KeyRemapper;
 
   class VNCServerST : public VNCServer, public network::SocketServer {
   public:
@@ -52,30 +53,25 @@
 
     // Methods overridden from SocketServer
 
-    // - Run a client connection on the supplied socket
-    //   This causes the server to allocate the required structures
-    //   to handle a client connection, and to initialise the RFB
-    //   protocol.
-    //   NB:  The server assumes ownership of the Socket object.
+    // addSocket
+    //   Causes the server to allocate an RFB-protocol management
+    //   structure for the socket & initialise it.
+    virtual void addSocket(network::Socket* sock, bool outgoing=false);
 
-    virtual void addClient(network::Socket* sock);
+    // removeSocket
+    //   Clean up any resources associated with the Socket
+    virtual void removeSocket(network::Socket* sock);
 
-    // - Process an input event on a particular Socket
-    //   The platform-specific side of the server implementation calls
-    //   this method whenever data arrives on one of the active
-    //   network sockets.
-    //   The method returns true if the Socket is still in use by the
-    //   server, or false if it is no longer required and has been
-    //   deleted.
-    //   NB:  If false is returned then the Socket is deleted and must
-    //   not be accessed again!
+    // processSocketEvent
+    //   Read more RFB data from the Socket.  If an error occurs during
+    //   processing then shutdown() is called on the Socket, causing
+    //   removeSocket() to be called by the caller at a later time.
+    virtual void processSocketEvent(network::Socket* sock);
 
-    virtual bool processSocketEvent(network::Socket* sock);
-
-    // - checkTimeouts() returns the number of milliseconds left until the next
-    //   idle timeout expires.  If any have already expired, the corresponding
-    //   connections are closed.  Zero is returned if there is no idle timeout.
-
+    // checkTimeouts
+    //   Returns the number of milliseconds left until the next idle timeout
+    //   expires.  If any have already expired, the corresponding connections
+    //   are closed.  Zero is returned if there is no idle timeout.
     virtual int checkTimeouts();
 
 
@@ -88,9 +84,9 @@
     virtual void add_copied(const Region &dest, const Point &delta);
     virtual bool clientsReadyForUpdate();
     virtual void tryUpdate();
-    virtual void setCursor(int width, int height, int hotspotX, int hotspotY,
+    virtual void setCursor(int width, int height, const Point& hotspot,
                            void* cursorData, void* mask);
-    virtual void setCursorPos(int x, int y);
+    virtual void setCursorPos(const Point& p);
     virtual void setSSecurityFactory(SSecurityFactory* f) {securityFactory=f;}
 
     virtual void bell();
@@ -101,17 +97,10 @@
 
     // VNCServerST-only methods
 
-    //   If a particular VNCSConnectionST* is specified then
-    //   that connection will NOT be closed.
+    // 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);
 
-    // addClient() with an extra flag to say if this is a reverse connection to
-    // a listening client.  Reverse connections are not authenticated and are
-    // always shared (unless the NeverShared parameter is set).
-
-    void addClient(network::Socket* sock, bool reverse);
-
-
     // getSockets() gets a list of sockets.  This can be used to generate an
     // fd_set for calling select().
 
@@ -183,11 +172,15 @@
     void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}
 
     // setEconomicTranslate() determines (for new connections) whether pixels
-    // should be translated for <=16bpp clients using a large lookup table (fast)
-    // or separate, smaller R, G and B tables (slower).  If set to true, small tables
-    // are used, to save memory.
+    // should be translated for <=16bpp clients using a large lookup table
+    // (fast) or separate, smaller R, G and B tables (slower).  If set to true,
+    // small tables are used, to save memory.
     void setEconomicTranslate(bool et) { useEconomicTranslate = et; }
 
+    // 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);
 
@@ -231,6 +224,7 @@
 
     SSecurityFactory* securityFactory;
     QueryConnectionHandler* queryConnectionHandler;
+    KeyRemapper* keyRemapper;
     bool useEconomicTranslate;
     
     time_t lastUserInputTime;
diff --git a/rfb/ZRLEDecoder.cxx b/rfb/ZRLEDecoder.cxx
index 2dd4a12..b7c6912 100644
--- a/rfb/ZRLEDecoder.cxx
+++ b/rfb/ZRLEDecoder.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/ZRLEDecoder.h b/rfb/ZRLEDecoder.h
index c8b1feb..fe96c73 100644
--- a/rfb/ZRLEDecoder.h
+++ b/rfb/ZRLEDecoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/ZRLEEncoder.h b/rfb/ZRLEEncoder.h
index 17222a3..7768917 100644
--- a/rfb/ZRLEEncoder.h
+++ b/rfb/ZRLEEncoder.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -34,7 +34,8 @@
     // can be used to stop the MemOutStream from growing too large.  The value
     // must be large enough to allow for at least one row of ZRLE tiles.  So
     // for example for a screen width of 2048 32-bit pixels this is 2K*4*64 =
-    // 512Kbytes plus a bit of overhead.
+    // 512Kbytes plus a bit of overhead (the overhead is about 1/16 of the
+    // width, in this example about 128 bytes).
     static void setMaxLen(int m) { maxLen = m; }
 
     // setSharedMos() sets a MemOutStream to be shared amongst all
diff --git a/rfb/d3des.c b/rfb/d3des.c
index 9227ddd..eaca581 100644
--- a/rfb/d3des.c
+++ b/rfb/d3des.c
@@ -173,14 +173,14 @@
 register unsigned long *outof;
 register unsigned char *into;
 {
-	*into++ = (*outof >> 24) & 0xffL;
-	*into++ = (*outof >> 16) & 0xffL;
-	*into++ = (*outof >>  8) & 0xffL;
-	*into++ =  *outof++	 & 0xffL;
-	*into++ = (*outof >> 24) & 0xffL;
-	*into++ = (*outof >> 16) & 0xffL;
-	*into++ = (*outof >>  8) & 0xffL;
-	*into	=  *outof	 & 0xffL;
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into++ = (unsigned char)(*outof++	 & 0xffL);
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into	=  (unsigned char)(*outof	 & 0xffL);
 	return;
 	}
 
diff --git a/rfb/encodings.cxx b/rfb/encodings.cxx
index d3b0ccb..6aa81c4 100644
--- a/rfb/encodings.cxx
+++ b/rfb/encodings.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/encodings.h b/rfb/encodings.h
index 20be0ae..51f6f1e 100644
--- a/rfb/encodings.h
+++ b/rfb/encodings.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/hextileConstants.h b/rfb/hextileConstants.h
index 272afbb..b8713cb 100644
--- a/rfb/hextileConstants.h
+++ b/rfb/hextileConstants.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/hextileDecode.h b/rfb/hextileDecode.h
index 0c5559a..77befc7 100644
--- a/rfb/hextileDecode.h
+++ b/rfb/hextileDecode.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -52,11 +52,11 @@
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
-    t.br.y = vncmin(r.br.y, t.tl.y + 16);
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
 
     for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
 
-      t.br.x = vncmin(r.br.x, t.tl.x + 16);
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
 
       int tileType = is->readU8();
 
diff --git a/rfb/hextileEncode.h b/rfb/hextileEncode.h
index 27c7e01..9f8bd55 100644
--- a/rfb/hextileEncode.h
+++ b/rfb/hextileEncode.h
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright (C) 2005 Constantin Kaplinsky.  All Rights Reserved.
- *    
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -61,11 +61,11 @@
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
-    t.br.y = vncmin(r.br.y, t.tl.y + 16);
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
 
     for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
 
-      t.br.x = vncmin(r.br.x, t.tl.x + 16);
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
 
       GET_IMAGE_INTO_BUF(t,buf);
 
diff --git a/rfb/hextileEncodeBetter.h b/rfb/hextileEncodeBetter.h
index 59df102..2b6b160 100644
--- a/rfb/hextileEncodeBetter.h
+++ b/rfb/hextileEncodeBetter.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
  * Copyright (C) 2005 Constantin Kaplinsky.  All Rights Reserved.
- *    
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -294,11 +294,11 @@
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
-    t.br.y = vncmin(r.br.y, t.tl.y + 16);
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
 
     for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
 
-      t.br.x = vncmin(r.br.x, t.tl.x + 16);
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
 
       GET_IMAGE_INTO_BUF(t,buf);
 
diff --git a/rfb/msgTypes.h b/rfb/msgTypes.h
index 2b05c75..f6f8d5c 100644
--- a/rfb/msgTypes.h
+++ b/rfb/msgTypes.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/rfb.dsp b/rfb/rfb.dsp
index 4e18c7b..315236d 100644
--- a/rfb/rfb.dsp
+++ b/rfb/rfb.dsp
@@ -202,6 +202,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=.\KeyRemapper.cxx

+# End Source File

+# Begin Source File

+

 SOURCE=.\Logger.cxx

 # End Source File

 # Begin Source File

@@ -218,6 +222,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=.\Password.cxx

+# End Source File

+# Begin Source File

+

 SOURCE=.\PixelBuffer.cxx

 # End Source File

 # Begin Source File

@@ -298,10 +306,6 @@
 # End Source File

 # Begin Source File

 

-SOURCE=.\win32\Threading_win32.cxx

-# End Source File

-# Begin Source File

-

 SOURCE=.\TightDecoder.cxx

 # ADD CPP /I "../jpeg"

 # End Source File

@@ -332,10 +336,6 @@
 # End Source File

 # Begin Source File

 

-SOURCE=.\vncAuth.cxx

-# End Source File

-# Begin Source File

-

 SOURCE=.\VNCSConnectionST.cxx

 # End Source File

 # Begin Source File

@@ -496,6 +496,14 @@
 # End Source File

 # Begin Source File

 

+SOURCE=.\InputHandler.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\KeyRemapper.h

+# End Source File

+# Begin Source File

+

 SOURCE=.\keysymdef.h

 # End Source File

 # Begin Source File

@@ -528,6 +536,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE=.\Password.h

+# End Source File

+# Begin Source File

+

 SOURCE=.\Pixel.h

 # End Source File

 # Begin Source File

@@ -640,10 +652,6 @@
 # End Source File

 # Begin Source File

 

-SOURCE=.\win32\Threading_win32.h

-# End Source File

-# Begin Source File

-

 SOURCE=.\tightDecode.h

 # End Source File

 # Begin Source File

@@ -696,14 +704,6 @@
 # End Source File

 # Begin Source File

 

-SOURCE=.\win32\util_win32.h

-# End Source File

-# Begin Source File

-

-SOURCE=.\vncAuth.h

-# End Source File

-# Begin Source File

-

 SOURCE=.\VNCSConnectionST.h

 # End Source File

 # Begin Source File

diff --git a/rfb/rreDecode.h b/rfb/rreDecode.h
index 9f69cee..1f5bdf8 100644
--- a/rfb/rreDecode.h
+++ b/rfb/rreDecode.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/rreEncode.h b/rfb/rreEncode.h
index 4877a12..3f83487 100644
--- a/rfb/rreEncode.h
+++ b/rfb/rreEncode.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/secTypes.cxx b/rfb/secTypes.cxx
index c850684..830d844 100644
--- a/rfb/secTypes.cxx
+++ b/rfb/secTypes.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -29,6 +29,8 @@
   if (strcasecmp(name, "Tight") == 0)      return secTypeTight;
   if (strcasecmp(name, "RA2") == 0)        return secTypeRA2;
   if (strcasecmp(name, "RA2ne") == 0)      return secTypeRA2ne;
+  if (strcasecmp(name, "SSPI") == 0)       return secTypeSSPI;
+  if (strcasecmp(name, "SSPIne") == 0)       return secTypeSSPIne;
   return secTypeInvalid;
 }
 
@@ -40,6 +42,8 @@
   case secTypeTight:      return "Tight";
   case secTypeRA2:        return "RA2";
   case secTypeRA2ne:      return "RA2ne";
+  case secTypeSSPI:       return "SSPI";
+  case secTypeSSPIne:     return "SSPIne";
   default:                return "[unknown secType]";
   }
 }
@@ -47,8 +51,11 @@
 bool rfb::secTypeEncrypts(int num)
 {
   switch (num) {
-  case secTypeRA2:        return true;
-  default:                return false;
+  case secTypeRA2:
+  case secTypeSSPI:
+    return true;
+  default:
+    return false;
   }
 }
 
diff --git a/rfb/secTypes.h b/rfb/secTypes.h
index f0b326e..3cf783b 100644
--- a/rfb/secTypes.h
+++ b/rfb/secTypes.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -32,6 +32,9 @@
   const int secTypeRA2     = 5;
   const int secTypeRA2ne   = 6;
 
+  const int secTypeSSPI    = 7;
+  const int secTypeSSPIne    = 8;
+
   const int secTypeTight   = 16;
   const int secTypeUltra   = 17;
   const int secTypeTLS     = 18;
diff --git a/rfb/transInitTempl.h b/rfb/transInitTempl.h
index 2658f9f..464cfdf 100644
--- a/rfb/transInitTempl.h
+++ b/rfb/transInitTempl.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/transTempl.h b/rfb/transTempl.h
index 907b839..09dc7f9 100644
--- a/rfb/transTempl.h
+++ b/rfb/transTempl.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/util.cxx b/rfb/util.cxx
index 94aa632..5745432 100644
--- a/rfb/util.cxx
+++ b/rfb/util.cxx
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
diff --git a/rfb/util.h b/rfb/util.h
index 02183d7..fa205f0 100644
--- a/rfb/util.h
+++ b/rfb/util.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -23,13 +23,7 @@
 #ifndef __RFB_UTIL_H__
 #define __RFB_UTIL_H__
 
-#ifndef vncmin
-#define vncmin(a,b)            (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef vncmax
-#define vncmax(a,b)            (((a) > (b)) ? (a) : (b))
-#endif
-
+#include <limits.h>
 #include <string.h>
 
 namespace rfb {
@@ -71,8 +65,36 @@
 
   // Copies src to dest, up to specified length-1, and guarantees termination
   void strCopy(char* dest, const char* src, int destlen);
+
+
+  // HELPER functions for timeout handling
+
+  // soonestTimeout() is a function to help work out the soonest of several
+  //   timeouts.
+  inline void soonestTimeout(int* timeout, int newTimeout) {
+    if (newTimeout && (!*timeout || newTimeout < *timeout))
+      *timeout = newTimeout;
+  }
+
+  // secsToMillis() turns seconds into milliseconds, capping the value so it
+  //   can't wrap round and become -ve
+  inline int secsToMillis(int secs) {
+    return (secs < 0 || secs > (INT_MAX/1000) ? INT_MAX : secs * 1000);
+  }
 }
 
+// Some platforms (e.g. Windows) include max() and min() macros in their
+// standard headers, but they are also standard C++ template functions, so some
+// C++ headers will undefine them.  So we steer clear of the names min and max
+// and define __rfbmin and __rfbmax instead.
+
+#ifndef __rfbmax
+#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef __rfbmin
+#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
 // Declare strcasecmp() and/or strncasecmp() if absent on this system.
 
 #if !defined(WIN32) && !defined(HAVE_STRCASECMP)
@@ -86,10 +108,4 @@
 }
 #endif
 
-#endif // __RFB_UTIL_H__
-
-// -=- PLATFORM SPECIFIC UTILITY FUNCTIONS/IMPLEMENTATIONS
-#ifdef WIN32
-#include "win32/util_win32.h"
 #endif
-
diff --git a/rfb/vncAuth.cxx b/rfb/vncAuth.cxx
deleted file mode 100644
index 6bd6a62..0000000
--- a/rfb/vncAuth.cxx
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
- * USA.
- */
-//
-// vncAuth
-//
-// XXX not thread-safe, because d3des isn't - do we need to worry about this?
-//
-
-#include <string.h>
-extern "C" {
-#include <rfb/d3des.h>
-}
-#include <rfb/vncAuth.h>
-
-using namespace rfb;
-
-void rfb::vncAuthEncryptChallenge(rdr::U8* challenge, const char* passwd)
-{
-  unsigned char key[8] = { 0, };
-  int len = strlen(passwd);
-  if (len > 8) len = 8;
-  for (int i = 0; i < len; i++)
-    key[i] = passwd[i];
-
-  deskey(key, EN0);
-
-  for (int j = 0; j < vncAuthChallengeSize; j += 8)
-    des(challenge+j, challenge+j);
-}
-
-static unsigned char obfuscationKey[] = {23,82,107,6,35,78,88,7};
-
-void rfb::vncAuthObfuscatePasswd(char* passwd)
-{
-  for (int i = strlen(passwd); i < 8; i++)
-    passwd[i] = 0;
-  deskey(obfuscationKey, EN0);
-  des((unsigned char*)passwd, (unsigned char*)passwd);
-}
-
-void rfb::vncAuthUnobfuscatePasswd(char* passwd)
-{
-  deskey(obfuscationKey, DE1);
-  des((unsigned char*)passwd, (unsigned char*)passwd);
-  passwd[8] = 0;
-}
diff --git a/rfb/win32/Threading_win32.cxx b/rfb/win32/Threading_win32.cxx
deleted file mode 100644
index 28cfdb7..0000000
--- a/rfb/win32/Threading_win32.cxx
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
- * USA.
- */
-
-// -=- Threading_win32.cxx
-// Win32 Threading interface implementation
-
-#include <malloc.h>
-
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
-#include <rfb/win32/Threading_win32.h>
-#include <rfb/util.h>
-
-using namespace rfb;
-
-static LogWriter vlog("Threading");
-
-static DWORD threadStorage = TlsAlloc();
-
-
-inline logAction(Thread* t, const char* action) {
-  vlog.debug("%-16.16s %s(%lx)", action, t->getName(), t);
-}
-
-inline logError(Thread* t, const char* err) {
-  vlog.error("%-16.16s %s(%lx):%s", "failed", t->getName(), t, err);
-}
-
-
-DWORD WINAPI
-Thread::threadProc(LPVOID lpParameter) {
-  Thread* thread = (Thread*) lpParameter;
-  TlsSetValue(threadStorage, thread);
-  logAction(thread, "started");
-  try {
-    thread->run();
-    logAction(thread, "stopped");
-  } catch (rdr::Exception& e) {
-    logError(thread, e.str());
-  }
-  bool deleteThread = false;
-  {
-    Lock l(thread->mutex);
-    thread->state = ThreadStopped;
-    thread->sig->signal();
-    deleteThread = thread->deleteAfterRun;
-  }
-  if (deleteThread)
-    delete thread;
-  return 0;
-}
-
-Thread::Thread(const char* name_) : sig(0), deleteAfterRun(false) {
-  sig = new Condition(mutex);
-  cond_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-  if (!name_)
-    name_ = "Unnamed";
-  name = strDup(name_);
-  thread = CreateThread(NULL, 0, threadProc, this, CREATE_SUSPENDED, &thread_id);
-  state = ThreadCreated;
-  logAction(this, "created");
-}
-
-Thread::Thread(HANDLE thread_, DWORD thread_id_) : sig(0), deleteAfterRun(false), thread(thread_), thread_id(thread_id_) {
-  sig = new Condition(mutex);
-  cond_event = CreateEvent(NULL, TRUE, FALSE, NULL);
-  name = strDup("Native");
-  state = ThreadNative;
-  logAction(this, "created");
-}
-
-Thread::~Thread() {
-  logAction(this, "destroying");
-  if (!deleteAfterRun) this->join();
-  if (sig)
-    delete sig;
-  if (cond_event)
-    CloseHandle(cond_event);
-  logAction(this, "destroyed");
-  strFree(name);
-}
-
-void
-Thread::run() {
-}
-
-void
-Thread::start() {
-  Lock l(mutex);
-  if (state == ThreadCreated) {
-    state = ThreadStarted;
-    sig->signal();
-    ResumeThread(thread);
-  }
-}
-
-Thread*
-Thread::join() {
-  if (deleteAfterRun)
-    throw rdr::Exception("attempt to join() with deleteAfterRun thread");
-  Lock l(mutex);
-  if (!thread) {
-    logAction(this, "already joined");
-  } else {
-    logAction(this, "joining");
-    while (state == ThreadStarted) {
-      sig->wait();
-      logAction(this, "checking");
-    }
-    CloseHandle(thread);
-    thread = 0;
-    logAction(this, "joined");
-  }
-  return this;
-}
-
-const char*
-Thread::getName() const {
-  return name;
-}
-
-ThreadState
-Thread::getState() const {
-  return state;
-}
-
-unsigned long
-Thread::getThreadId() const {
-  return thread_id;
-}
-
-Thread*
-Thread::self() {
-  Thread* thread = (Thread*) TlsGetValue(threadStorage);
-  if (!thread) {
-    thread = new Thread(GetCurrentThread(), GetCurrentThreadId());
-    TlsSetValue(threadStorage, thread);
-  }
-  return thread;
-}
\ No newline at end of file
diff --git a/rfb/win32/Threading_win32.h b/rfb/win32/Threading_win32.h
deleted file mode 100644
index e95e0f7..0000000
--- a/rfb/win32/Threading_win32.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
- * USA.
- */
-
-// -=- Threading_win32.h
-// Win32 Threading interface implementation
-
-#ifndef __RFB_THREADING_IMPL_WIN32
-#define __RFB_THREADING_IMPL_WIN32
-
-#define __RFB_THREADING_IMPL WIN32
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-#include <stdio.h>
-
-namespace rfb {
-
-  class Mutex {
-  public:
-    Mutex() {
-      InitializeCriticalSection(&crit);
-    }
-    ~Mutex() {
-      DeleteCriticalSection(&crit);
-    }
-    friend class Lock;
-    friend class Condition;
-  protected:
-    void enter() {EnterCriticalSection(&crit);}
-    void exit() {LeaveCriticalSection(&crit);}
-    CRITICAL_SECTION crit;
-  };
-
-  class Lock {
-  public:
-    Lock(Mutex& m) : mutex(m) {m.enter();}
-    ~Lock() {mutex.exit();}
-  protected:
-    Mutex& mutex;
-  };
-
-  enum ThreadState {ThreadCreated, ThreadStarted, ThreadStopped, ThreadNative};
-
-  class Thread {
-  public:
-    Thread(const char* name_=0);
-    virtual ~Thread();
-
-    virtual void run();
-
-    virtual void start();
-    virtual Thread* join();
-
-    const char* getName() const;
-    ThreadState getState() const;
-
-    // Determines whether the thread should delete itself when run() returns
-    // If you set this, you must NEVER call join()!
-    void setDeleteAfterRun() {deleteAfterRun = true;};
-
-    unsigned long getThreadId() const;
-
-    static Thread* self();
-
-    friend class Condition;
-
-  protected:
-    Thread(HANDLE thread_, DWORD thread_id_);
-    static DWORD WINAPI threadProc(LPVOID lpParameter);
-
-    HANDLE thread;
-    DWORD thread_id;
-    char* name;
-    ThreadState state;
-    Condition* sig;
-    Mutex mutex;
-
-    HANDLE cond_event;
-	  Thread* cond_next;
-
-    bool deleteAfterRun;
-  };
-
-  class Condition {
-  public:
-    Condition(Mutex& m) : mutex(m), waiting(0) {
-    }
-    ~Condition() {
-    }
-    void signal() {
-      Lock l(cond_lock);
-      if (waiting) {
-        SetEvent(waiting->cond_event);
-        waiting = waiting->cond_next;
-      }
-    }
-    // - MUST hold "mutex" to call wait()
-    // WIN32: if processMsg is true then wait will continue
-    // to process messages in the thread's queue.
-    // Avoid using this unless you have to!
-    void wait(bool processMsgs=false) {
-      Thread* self = Thread::self();
-      ResetEvent(self->cond_event);
-      { Lock l(cond_lock);
-        self->cond_next = waiting;
-        waiting = self;
-      }
-      mutex.exit();
-      if (processMsgs) {
-        while (1) {
-          DWORD result = MsgWaitForMultipleObjects(1, &self->cond_event, FALSE, INFINITE, QS_ALLINPUT);
-          if (result == WAIT_OBJECT_0)
-            break;
-          MSG msg;
-          while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
-            DispatchMessage(&msg);
-          }
-        }
-      } else {
-        WaitForSingleObject(self->cond_event, INFINITE);
-      }
-      mutex.enter();
-    }
-    
-  protected:
-    Mutex& mutex;
-    Mutex cond_lock;
-	  Thread* waiting;
-  };
-
-};
-
-#endif // __RFB_THREADING_IMPL
diff --git a/rfb/win32/util_win32.h b/rfb/win32/util_win32.h
deleted file mode 100644
index 4bde5ec..0000000
--- a/rfb/win32/util_win32.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
- * USA.
- */
-
-//
-// util_win32.h - miscellaneous useful bits for Win32 only
-//
-
-#ifndef __RFB_UTIL_WIN32_H__
-#define __RFB_UTIL_WIN32_H__
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-// *** #include <iostream.h>
-
-#include <rfb/LogWriter.h>
-#include <rfb/Exception.h>
-
-namespace rfb {
-
-  // WIN32-ONLY PROFILING CODE
-  //
-  // CpuTime and CpuTimer provide a simple way to profile particular
-  // sections of code
-  //
-  // Use one CpuTime object per task to be profiled.  CpuTime instances
-  // maintain a cumulative total of time spent in user and kernel space
-  // by threads.
-  // When a CpuTime object is created, a label must be specified to
-  // identify the task being profiled.
-  // When the object is destroyed, it will print debugging information
-  // containing the user and kernel times accumulated.
-  //
-  // Place a CpuTimer object in each section of code which is to be
-  // profiled.  When the object is created, it snapshots the current
-  // kernel and user times and stores them.  These are used when the
-  // object is destroyed to establish how much time has elapsed in the
-  // intervening period.  The accumulated time is then added to the
-  // associated CpuTime object.
-  //
-  // This code works only on platforms providing __int64
-
-	class CpuTime {
-	public:
-		CpuTime(const char *name)
-			: timer_name(strDup(name)),
-			  kernel_time(0), user_time(0), max_user_time(0), iterations(0) {}
-		~CpuTime() {
-      g_log_writer.info("timer %s : %I64ums (krnl), %I64ums (user), %I64uus (user-max) (%I64u its)\n",
-				timer_name, kernel_time/10000, user_time/10000, max_user_time/10,
-				iterations);
-			delete [] timer_name;
-		}
-    static LogWriter g_log_writer;
-		char* timer_name;
-		__int64 kernel_time;
-		__int64 user_time;
-		__int64 iterations;
-		__int64 max_user_time;
-	};
-
-	class CpuTimer {
-	public:
-		inline CpuTimer(CpuTime &ct) : cputime(ct) {
-			FILETIME create_time, end_time;
-			if (!GetThreadTimes(GetCurrentThread(),
-				&create_time, &end_time,
-				(LPFILETIME)&start_kernel_time,
-				(LPFILETIME)&start_user_time)) {
-        throw rdr::SystemException("rfb::CpuTimer failed to initialise", GetLastError());
-			}
-		}
-		inline ~CpuTimer() {
-			FILETIME create_time, end_time;
-			__int64 end_kernel_time, end_user_time;
-			if (!GetThreadTimes(GetCurrentThread(),
-				&create_time, &end_time,
-				(LPFILETIME)&end_kernel_time,
-				(LPFILETIME)&end_user_time)) {
-        throw rdr::SystemException("rfb::CpuTimer destructor failed", GetLastError());
-			}
-			cputime.kernel_time += end_kernel_time - start_kernel_time;
-			cputime.user_time += end_user_time - start_user_time;
-			if (end_user_time - start_user_time > cputime.max_user_time) {
-				cputime.max_user_time = end_user_time - start_user_time;
-			}
-			cputime.iterations++;
-		}
-	private:
-		CpuTime& cputime;
-		__int64 start_kernel_time;
-		__int64 start_user_time;
-	};
-
-};
-
-#endif // __RFB_UTIL_WIN32_H__
diff --git a/rfb/zrleDecode.h b/rfb/zrleDecode.h
index e1f85f7..15d2790 100644
--- a/rfb/zrleDecode.h
+++ b/rfb/zrleDecode.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -61,11 +61,11 @@
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
 
-    t.br.y = vncmin(r.br.y, t.tl.y + 64);
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
 
     for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
 
-      t.br.x = vncmin(r.br.x, t.tl.x + 64);
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
 
       int mode = zis->readU8();
       bool rle = mode & 128;
diff --git a/rfb/zrleEncode.h b/rfb/zrleEncode.h
index 42505a3..9b7263b 100644
--- a/rfb/zrleEncode.h
+++ b/rfb/zrleEncode.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -130,7 +130,7 @@
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
 
-    t.br.y = vncmin(r.br.y, t.tl.y + 64);
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
 
     if (os->length() + worstCaseLine > maxLen) {
       if (t.tl.y == r.tl.y)
@@ -143,7 +143,7 @@
 
     for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
 
-      t.br.x = vncmin(r.br.x, t.tl.x + 64);
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
 
       GET_IMAGE_INTO_BUF(t,buf);