Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/Blacklist.cxx b/common/rfb/Blacklist.cxx
new file mode 100644
index 0000000..4590bef
--- /dev/null
+++ b/common/rfb/Blacklist.cxx
@@ -0,0 +1,86 @@
+/* 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 <rfb/Blacklist.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+IntParameter Blacklist::threshold("BlacklistThreshold",
+                              "The number of unauthenticated connection attempts allowed from any "
+                              "individual host before that host is black-listed",
+                              5);
+IntParameter Blacklist::initialTimeout("BlacklistTimeout",
+                              "The initial timeout applied when a host is first black-listed.  "
+                              "The host cannot re-attempt a connection until the timeout expires.",
+                              10);
+
+
+Blacklist::Blacklist() {
+}
+
+Blacklist::~Blacklist() {
+  // Free the map keys
+  BlacklistMap::iterator i;
+  for (i=blm.begin(); i!=blm.end(); i++) {
+    strFree((char*)(*i).first);
+  }
+}
+
+bool Blacklist::isBlackmarked(const char* name) {
+  BlacklistMap::iterator i = blm.find(name);
+  if (i == blm.end()) {
+    // Entry is not already black-marked.
+    // Create the entry unmarked, unblocked,
+    // with suitable defaults set.
+    BlacklistInfo bi;
+    bi.marks = 1;
+    bi.blockUntil = 0;
+    bi.blockTimeout = initialTimeout;
+    blm[strDup(name)] = bi;
+    i = blm.find(name);
+  }
+
+  // Entry exists - has it reached the threshold yet?
+  if ((*i).second.marks >= threshold) {
+    // Yes - entry is blocked - has the timeout expired?        
+    time_t now = time(0);
+    if (now >= (*i).second.blockUntil) {
+      // Timeout has expired.  Reset timeout and allow
+      // a re-try.
+      (*i).second.blockUntil = now + (*i).second.blockTimeout;
+      (*i).second.blockTimeout = (*i).second.blockTimeout * 2;
+      return false;
+    }
+    // Blocked and timeout still in effect - reject!
+    return true;
+  }
+
+  // We haven't reached the threshold yet.
+  // Increment the black-mark counter but allow
+  // the entry to pass.
+  (*i).second.marks++;
+  return false;
+}
+
+void Blacklist::clearBlackmark(const char* name) {
+  BlacklistMap::iterator i = blm.find(name);
+  if (i != blm.end()) {
+    strFree((char*)(*i).first);
+    blm.erase(i);
+  }
+}
diff --git a/common/rfb/Blacklist.h b/common/rfb/Blacklist.h
new file mode 100644
index 0000000..0eb3846
--- /dev/null
+++ b/common/rfb/Blacklist.h
@@ -0,0 +1,91 @@
+/* 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.
+ */
+
+//
+// Blacklist.h - Handling of black-listed entities.
+// Just keeps a table mapping strings to timing information, including
+// how many times the entry has been black-listed and when to next
+// put it on probation (e.g. allow a connection in from the host, and
+// re-blacklist it if that fails). 
+//
+
+#ifndef __RFB_BLACKLIST_H__
+#define __RFB_BLACKLIST_H__
+
+#include <string.h>
+#include <time.h>
+#include <map>
+
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  //
+  // -=- Blacklist handler
+  //
+  // Parameters include a threshold after which to blacklist the named
+  // host, and a timeout after which to re-consider them.
+  //
+  // Threshold means that isBlackmarked can be called that number of times
+  // before it will return true.
+  //
+  // Timeout means that after that many seconds, the next call to isBlackmarked
+  // will return false.  At the same time, the timeout is doubled, so that the
+  // next calls will fail, until the timeout expires again or clearBlackmark is
+  // called.
+  //
+  // When clearBlackMark is called, the corresponding entry is completely
+  // removed, causing the next isBlackmarked call to return false.
+
+  // KNOWN BUG:  Client can keep making rejected requests, thus increasing
+  // their timeout.  If client does this for 30 years, timeout may wrap round
+  // to a very small value again.
+
+  // THIS CLASS IS NOT THREAD-SAFE!
+
+  class Blacklist {
+  public:
+    Blacklist();
+    ~Blacklist();
+
+    bool isBlackmarked(const char* name);
+    void clearBlackmark(const char* name);
+
+    static IntParameter threshold;
+    static IntParameter initialTimeout;
+
+  protected:
+    struct ltStr {
+      bool operator()(const char* s1, const char* s2) const {
+        return strcmp(s1, s2) < 0;
+      };
+    };
+    struct BlacklistInfo {
+      int marks;
+      time_t blockUntil;
+      unsigned int blockTimeout;
+    };
+    typedef std::map<const char*,BlacklistInfo,ltStr> BlacklistMap;
+    BlacklistMap blm;
+  };
+
+}
+
+#endif
+
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
new file mode 100644
index 0000000..36778f0
--- /dev/null
+++ b/common/rfb/CConnection.cxx
@@ -0,0 +1,276 @@
+/* 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 <string.h>
+#include <rfb/Exception.h>
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgWriterV3.h>
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+#include <rfb/CConnection.h>
+#include <rfb/util.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("CConnection");
+
+CConnection::CConnection()
+  : is(0), os(0), reader_(0), writer_(0),
+    shared(false), security(0), nSecTypes(0), clientSecTypeOrder(false),
+    state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false)
+{
+}
+
+CConnection::~CConnection()
+{
+  if (security) security->destroy();
+  deleteReaderAndWriter();
+}
+
+void CConnection::deleteReaderAndWriter()
+{
+  delete reader_;
+  reader_ = 0;
+  delete writer_;
+  writer_ = 0;
+}
+
+void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
+{
+  is = is_;
+  os = os_;
+}
+
+void CConnection::addSecType(rdr::U8 secType)
+{
+  if (nSecTypes == maxSecTypes)
+    throw Exception("too many security types");
+  secTypes[nSecTypes++] = secType;
+}
+
+void CConnection::setClientSecTypeOrder(bool clientOrder) {
+  clientSecTypeOrder = clientOrder;
+}
+
+void CConnection::initialiseProtocol()
+{
+  state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void CConnection::processMsg()
+{
+  switch (state_) {
+
+  case RFBSTATE_PROTOCOL_VERSION: processVersionMsg();       break;
+  case RFBSTATE_SECURITY_TYPES:   processSecurityTypesMsg(); break;
+  case RFBSTATE_SECURITY:         processSecurityMsg();      break;
+  case RFBSTATE_SECURITY_RESULT:  processSecurityResultMsg(); break;
+  case RFBSTATE_INITIALISATION:   processInitMsg();          break;
+  case RFBSTATE_NORMAL:           reader_->readMsg();        break;
+  case RFBSTATE_UNINITIALISED:
+    throw Exception("CConnection::processMsg: not initialised yet?");
+  default:
+    throw Exception("CConnection::processMsg: invalid state");
+  }
+}
+
+void CConnection::processVersionMsg()
+{
+  vlog.debug("reading protocol version");
+  bool done;
+  if (!cp.readVersion(is, &done)) {
+    state_ = RFBSTATE_INVALID;
+    throw Exception("reading version failed: not an RFB server?");
+  }
+  if (!done) return;
+
+  vlog.info("Server supports RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+
+  // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+  if (cp.beforeVersion(3,3)) {
+    char msg[256];
+    sprintf(msg,"Server gave unsupported RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+    vlog.error(msg);
+    state_ = RFBSTATE_INVALID;
+    throw Exception(msg);
+  } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
+    cp.setVersion(3,3);
+  } else if (cp.afterVersion(3,8)) {
+    cp.setVersion(3,8);
+  }
+
+  cp.writeVersion(os);
+  state_ = RFBSTATE_SECURITY_TYPES;
+
+  vlog.info("Using RFB protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+}
+
+
+void CConnection::processSecurityTypesMsg()
+{
+  vlog.debug("processing security types message");
+
+  int secType = secTypeInvalid;
+
+  if (cp.isVersion(3,3)) {
+
+    // legacy 3.3 server may only offer "vnc authentication" or "none"
+
+    secType = is->readU32();
+    if (secType == secTypeInvalid) {
+      throwConnFailedException();
+
+    } else if (secType == secTypeNone || secType == secTypeVncAuth) {
+      int j;
+      for (j = 0; j < nSecTypes; j++)
+        if (secTypes[j] == secType) break;
+      if (j == nSecTypes)
+        secType = secTypeInvalid;
+    } else {
+      vlog.error("Unknown 3.3 security type %d", secType);
+      throw Exception("Unknown 3.3 security type");
+    }
+
+  } else {
+
+    // >=3.7 server will offer us a list
+
+    int nServerSecTypes = is->readU8();
+    if (nServerSecTypes == 0)
+      throwConnFailedException();
+
+    int secTypePos = nSecTypes;
+    for (int i = 0; i < nServerSecTypes; i++) {
+      rdr::U8 serverSecType = is->readU8();
+      vlog.debug("Server offers security type %s(%d)",
+                 secTypeName(serverSecType),serverSecType);
+
+      // If we haven't already chosen a secType, try this one
+      // If we are using the client's preference for types,
+      // we keep trying types, to find the one that matches and
+      // which appears first in the client's list of supported types.
+      if (secType == secTypeInvalid || clientSecTypeOrder) {
+        for (int j = 0; j < nSecTypes; j++) {
+          if (secTypes[j] == serverSecType && j < secTypePos) {
+            secType = secTypes[j];
+            secTypePos = j;
+            break;
+          }
+        }
+        // NB: Continue reading the remaining server secTypes, but ignore them
+      }
+    }
+
+    // Inform the server of our decision
+    if (secType != secTypeInvalid) {
+      os->writeU8(secType);
+      os->flush();
+      vlog.debug("Choosing security type %s(%d)",secTypeName(secType),secType);
+    }
+  }
+
+  if (secType == secTypeInvalid) {
+    state_ = RFBSTATE_INVALID;
+    vlog.error("No matching security types");
+    throw Exception("No matching security types");
+  }
+
+  state_ = RFBSTATE_SECURITY;
+  security = getCSecurity(secType);
+  processSecurityMsg();
+}
+
+void CConnection::processSecurityMsg()
+{
+  vlog.debug("processing security message");
+  if (security->processMsg(this)) {
+    state_ = RFBSTATE_SECURITY_RESULT;
+    processSecurityResultMsg();
+  }
+}
+
+void CConnection::processSecurityResultMsg()
+{
+  vlog.debug("processing security result message");
+  int result;
+  if (cp.beforeVersion(3,8) && security->getType() == secTypeNone) {
+    result = secResultOK;
+  } else {
+    if (!is->checkNoWait(1)) return;
+    result = is->readU32();
+  }
+  switch (result) {
+  case secResultOK:
+    securityCompleted();
+    return;
+  case secResultFailed:
+    vlog.debug("auth failed");
+    break;
+  case secResultTooMany:
+    vlog.debug("auth failed - too many tries");
+    break;
+  default:
+    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()
+{
+  vlog.debug("reading server initialisation");
+  reader_->readServerInit();
+}
+
+void CConnection::throwConnFailedException()
+{
+  state_ = RFBSTATE_INVALID;
+  CharArray reason;
+  reason.buf = is->readString();
+  throw ConnFailedException(reason.buf);
+}
+
+void CConnection::securityCompleted()
+{
+  state_ = RFBSTATE_INITIALISATION;
+  reader_ = new CMsgReaderV3(this, is);
+  writer_ = new CMsgWriterV3(&cp, os);
+  vlog.debug("Authentication success!");
+  authSuccess();
+  writer_->writeClientInit(shared);
+}
+
+void CConnection::authSuccess()
+{
+}
+
+void CConnection::serverInit()
+{
+  state_ = RFBSTATE_NORMAL;
+  vlog.debug("initialisation done");
+}
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
new file mode 100644
index 0000000..79110eb
--- /dev/null
+++ b/common/rfb/CConnection.h
@@ -0,0 +1,183 @@
+/* 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.
+ */
+//
+// CConnection - class on the client side representing a connection to a
+// server.  A derived class should override methods appropriately.
+//
+
+#ifndef __RFB_CCONNECTION_H__
+#define __RFB_CCONNECTION_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  class CMsgReader;
+  class CMsgWriter;
+  class CSecurity;
+  class IdentityVerifier;
+
+  class CConnection : public CMsgHandler {
+  public:
+
+    CConnection();
+    virtual ~CConnection();
+
+    // 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
+    // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+    // streams).  Ownership of the streams remains with the caller
+    // (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
+    // client supports.  The order in which they're added is such that the
+    // first one is most preferred.
+    void addSecType(rdr::U8 secType);
+
+    // setClientSecTypeOrder() determines whether the client should obey
+    // the server's security type preference, by picking the first server security
+    // type that the client supports, or whether it should pick the first type
+    // that the server supports, from the client-supported list of types.
+    void setClientSecTypeOrder(bool clientOrder);
+
+    // setShared sets the value of the shared flag which will be sent to the
+    // server upon initialisation.
+    void setShared(bool s) { shared = s; }
+
+    // setProtocol3_3 configures whether or not the CConnection should
+    // only ever support protocol version 3.3
+    void setProtocol3_3(bool s) {useProtocol3_3 = s;}
+
+    // 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.
+    void initialiseProtocol();
+
+    // processMsg() should be called whenever there is either:
+    // - data available on the underlying network stream
+    //   In this case, processMsg may return without processing an RFB message,
+    //   if the available data does not result in an RFB message being ready
+    //   to handle. e.g. if data is encrypted.
+    // NB: This makes it safe to call processMsg() in response to select()
+    // - data available on the CConnection's current InStream
+    //   In this case, processMsg should always process the available RFB
+    //   message before returning.
+    // NB: In either case, you must have called initialiseProtocol() first.
+    void processMsg();
+
+
+    // Methods to be overridden in a derived class
+
+    // getCSecurity() gets the CSecurity object for the given type.  The type
+    // is guaranteed to be one of the secTypes passed in to addSecType().  The
+    // CSecurity object's destroy() method will be called by the CConnection
+    // from its destructor.
+    virtual CSecurity* getCSecurity(int secType)=0;
+
+    // getCurrentCSecurity() gets the CSecurity instance used for this connection.
+    const CSecurity* getCurrentCSecurity() const {return security;} 
+
+    // getIdVerifier() returns the identity verifier associated with the connection.
+    // Ownership of the IdentityVerifier is retained by the CConnection instance.
+    virtual IdentityVerifier* getIdentityVerifier() {return 0;}
+
+    // authSuccess() is called when authentication has succeeded.
+    virtual void authSuccess();
+
+    // serverInit() is called when the ServerInit message is received.  The
+    // derived class must call on to CConnection::serverInit().
+    virtual void serverInit();
+
+
+    // Other methods
+
+    // deleteReaderAndWriter() deletes the reader and writer associated with
+    // this connection.  This may be useful if you want to delete the streams
+    // before deleting the SConnection to make sure that no attempt by the
+    // SConnection is made to read or write.
+    // XXX Do we really need this at all???
+    void deleteReaderAndWriter();
+
+    CMsgReader* reader() { return reader_; }
+    CMsgWriter* writer() { return writer_; }
+
+    rdr::InStream* getInStream() { return is; }
+    rdr::OutStream* getOutStream() { return os; }
+
+    // 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,
+      RFBSTATE_PROTOCOL_VERSION,
+      RFBSTATE_SECURITY_TYPES,
+      RFBSTATE_SECURITY,
+      RFBSTATE_SECURITY_RESULT,
+      RFBSTATE_INITIALISATION,
+      RFBSTATE_NORMAL,
+      RFBSTATE_INVALID
+    };
+
+    stateEnum state() { return state_; }
+
+  protected:
+    void setState(stateEnum s) { state_ = s; }
+
+  private:
+    void processVersionMsg();
+    void processSecurityTypesMsg();
+    void processSecurityMsg();
+    void processSecurityResultMsg();
+    void processInitMsg();
+    void throwAuthFailureException();
+    void throwConnFailedException();
+    void securityCompleted();
+
+    rdr::InStream* is;
+    rdr::OutStream* os;
+    CMsgReader* reader_;
+    CMsgWriter* writer_;
+    bool deleteStreamsWhenDone;
+    bool shared;
+    CSecurity* security;
+    enum { maxSecTypes = 8 };
+    int nSecTypes;
+    rdr::U8 secTypes[maxSecTypes];
+    bool clientSecTypeOrder;
+    stateEnum state_;
+
+    CharArray serverName;
+
+    bool useProtocol3_3;
+  };
+}
+#endif
diff --git a/common/rfb/CFTMsgReader.cxx b/common/rfb/CFTMsgReader.cxx
new file mode 100644
index 0000000..5a17fc2
--- /dev/null
+++ b/common/rfb/CFTMsgReader.cxx
@@ -0,0 +1,162 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgReader.cxx
+
+#include <rfb/CFTMsgReader.h>
+
+using namespace rfb;
+
+CFTMsgReader::CFTMsgReader(rdr::InStream *pIS)
+{
+  m_pInStream = pIS;
+}
+
+CFTMsgReader::~CFTMsgReader()
+{
+
+}
+
+int 
+CFTMsgReader::readFileListData(FileInfo *pFileInfo)
+{
+  unsigned char flags = m_pInStream->readU8();
+  int numFiles = m_pInStream->readU16();
+  int dataSize = m_pInStream->readU16();
+  int compressedSize = m_pInStream->readU16();
+  
+  if (flags & 0x80) {
+    return -1;
+  } else {
+    if (numFiles > 0) {
+      char *pFilenames = new char[compressedSize];
+      SIZEDATAINFO *pSDI = new SIZEDATAINFO[numFiles];
+      for (int i = 0; i < numFiles; i++) {
+        pSDI[i].size = m_pInStream->readU32();
+        pSDI[i].data = m_pInStream->readU32();
+      }
+      m_pInStream->readBytes((void *)pFilenames, compressedSize);
+      createFileInfo(numFiles, pFileInfo, pSDI, pFilenames);
+      delete [] pSDI;
+      delete [] pFilenames;
+    }
+  }
+  return numFiles;
+}
+
+void * 
+CFTMsgReader::readFileDownloadData(unsigned int *pSize, unsigned int *pModTime)
+{
+  unsigned char compressLevel = m_pInStream->readU8();
+  int realSize = m_pInStream->readU16();
+  int compressedSize = m_pInStream->readU16();
+
+  if ((realSize == 0) && (compressedSize == 0)) {
+    *pSize = 0;
+    *pModTime = m_pInStream->readU32();
+    return NULL;
+  } else {
+    char *pFile = new char [compressedSize];
+    if (pFile == NULL) {
+      m_pInStream->skip(compressedSize);
+      *pModTime = 0;
+      return NULL;
+    } else {
+      m_pInStream->readBytes(pFile, compressedSize);
+      *pSize = compressedSize;
+      return pFile;
+    }
+  }
+}
+
+char * 
+CFTMsgReader::readFileUploadCancel(unsigned int *pReasonSize)
+{
+  m_pInStream->skip(1);
+  return readReasonMsg(pReasonSize);
+}
+
+char * 
+CFTMsgReader::readFileDownloadFailed(unsigned int *pReasonSize)
+{
+  m_pInStream->skip(1);
+  return readReasonMsg(pReasonSize);
+}
+
+int 
+CFTMsgReader::readFileDirSizeData(unsigned short *pDirSizeLow16, 
+                                 unsigned int *pDirSizeHigh32)
+{
+  m_pInStream->skip(1);
+  *pDirSizeLow16 = m_pInStream->readU16();
+  *pDirSizeHigh32 = m_pInStream->readU32();
+  return 1;
+}
+
+char * 
+CFTMsgReader::readFileLastRqstFailed(int *pTypeOfRequest, unsigned int *pReasonSize)
+{
+  *pTypeOfRequest = m_pInStream->readU8();
+  return readReasonMsg(pReasonSize);
+}
+
+bool 
+CFTMsgReader::createFileInfo(unsigned int numFiles, FileInfo *fi, 
+                             SIZEDATAINFO *pSDInfo, char *pFilenames)
+{
+  int pos = 0;
+  int size = 0;
+  for (unsigned int i = 0; i < numFiles; i++) {
+    size = pSDInfo[i].size;
+    if (size == FT_NET_ATTR_DIR) {
+      fi->add((pFilenames + pos), size, pSDInfo[i].data, FT_ATTR_DIR);
+    } else {
+      fi->add((pFilenames + pos), size, pSDInfo[i].data, FT_ATTR_FILE);
+    }
+    pos += strlen(pFilenames + pos) + 1;
+  }
+  return true;
+}
+
+char * 
+CFTMsgReader::readReasonMsg(unsigned int *pReasonSize)
+{
+  int reasonLen = m_pInStream->readU16();
+  int _reasonLen = reasonLen + 1;
+  char *pReason;
+  if (reasonLen == 0) {
+    *pReasonSize = 0;
+    return NULL;
+  } else {
+    pReason = new char [_reasonLen];
+    if (pReason == NULL) {
+      m_pInStream->skip(reasonLen);
+      *pReasonSize = 0;
+      return NULL;
+    }
+    m_pInStream->readBytes(pReason, reasonLen);
+    memset(((char *)pReason+reasonLen), '\0', 1);
+    return pReason;
+  }
+}
+
diff --git a/common/rfb/CFTMsgReader.h b/common/rfb/CFTMsgReader.h
new file mode 100644
index 0000000..aece3e7
--- /dev/null
+++ b/common/rfb/CFTMsgReader.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgReader.h
+
+#ifndef __RFB_CFTMSGREADER_H__
+#define __RFB_CFTMSGREADER_H__
+
+#include <rdr/InStream.h>
+#include <rfb/FileInfo.h>
+
+namespace rfb {
+  class CFTMsgReader
+  {
+  public:
+    CFTMsgReader(rdr::InStream *pIS);
+    ~CFTMsgReader();
+    
+    int readFileListData(FileInfo *pFileInfo);
+    int readFileDirSizeData(unsigned short *pDirSizeLow16, unsigned int *pDirSizeHigh32);
+    
+    char *readFileUploadCancel(unsigned int *pReasonSize);
+    char *readFileDownloadFailed(unsigned int *pReasonSize);
+    char *readFileLastRqstFailed(int *pTypeOfRequest, unsigned int *pReasonSize);
+    void *readFileDownloadData(unsigned int *pSize, unsigned int *pModTime);
+    
+  private:
+    rdr::InStream *m_pInStream;
+    
+    bool createFileInfo(unsigned int numFiles, FileInfo *fi, 
+                        SIZEDATAINFO *pSDInfo, char *pFilenames);
+    char *readReasonMsg(unsigned int *pReasonSize);
+  };
+}
+
+#endif // __RFB_CFTMSGREADER_H__
diff --git a/common/rfb/CFTMsgWriter.cxx b/common/rfb/CFTMsgWriter.cxx
new file mode 100644
index 0000000..5e6854e
--- /dev/null
+++ b/common/rfb/CFTMsgWriter.cxx
@@ -0,0 +1,182 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgWriter.cxx
+
+#include <rfb/CFTMsgWriter.h>
+
+using namespace rfb;
+
+CFTMsgWriter::CFTMsgWriter(rdr::OutStream *pOS)
+{
+  m_pOutStream = pOS;
+}
+
+CFTMsgWriter::~CFTMsgWriter()
+{
+}
+
+bool 
+CFTMsgWriter::writeFileListRqst(unsigned short dirnameLen, char *pDirName, 
+                                bool bDirOnly)
+{
+  if (dirnameLen >= FT_FILENAME_SIZE) return false;
+
+  unsigned char flags = 0;
+  if (bDirOnly) flags = 0x10;
+
+  m_pOutStream->writeU8(msgTypeFileListRequest);
+  m_pOutStream->writeU8(flags);
+  m_pOutStream->writeU16(dirnameLen);
+  m_pOutStream->writeBytes((void *)pDirName, dirnameLen);
+  m_pOutStream->flush();
+
+  return true;
+}
+
+
+bool 
+CFTMsgWriter::writeFileDownloadCancel(unsigned short reasonLen, char *pReason)
+{
+  m_pOutStream->writeU8(msgTypeFileDownloadCancel);
+  return writeU8U16StringMsg(reasonLen, pReason);
+}
+
+bool 
+CFTMsgWriter::writeFileDownloadRqst(unsigned short filenameLen, char *pFilename, 
+                                    unsigned int position)
+{
+  if (filenameLen >= FT_FILENAME_SIZE) return false;
+
+  m_pOutStream->writeU8(msgTypeFileDownloadRequest);
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(filenameLen);
+  m_pOutStream->writeU32(position);
+  m_pOutStream->writeBytes(pFilename, filenameLen);
+  m_pOutStream->flush();
+
+  return true;
+}
+
+bool 
+CFTMsgWriter::writeFileUploadData(unsigned short dataSize, char *pData)
+{
+  m_pOutStream->writeU8(msgTypeFileUploadData);
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(dataSize);
+  m_pOutStream->writeU16(dataSize);
+  m_pOutStream->writeBytes(pData, dataSize);
+  m_pOutStream->flush();
+
+  return true;
+}
+
+bool 
+CFTMsgWriter::writeFileUploadData(unsigned int modTime)
+{
+  m_pOutStream->writeU8(msgTypeFileUploadData);
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(0);
+  m_pOutStream->writeU16(0);
+  m_pOutStream->writeU32(modTime);
+  m_pOutStream->flush();
+
+  return true;
+}
+
+bool 
+CFTMsgWriter::writeFileUploadFailed(unsigned short reasonLen, char *pReason)
+{
+  m_pOutStream->writeU8(msgTypeFileUploadFailed);
+  return writeU8U16StringMsg(reasonLen, pReason);
+}
+
+bool 
+CFTMsgWriter::writeFileUploadRqst(unsigned short filenameLen, char *pFilename, 
+                                  unsigned int position)
+{
+  if (filenameLen >= FT_FILENAME_SIZE) return false;
+
+  m_pOutStream->writeU8(msgTypeFileUploadRequest);
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(filenameLen);
+  m_pOutStream->writeU32(position);
+  m_pOutStream->writeBytes((void *)pFilename, filenameLen);
+  m_pOutStream->flush();
+
+  return true;
+}
+
+bool 
+CFTMsgWriter::writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName)
+{
+  if (dirNameLen >= FT_FILENAME_SIZE) return false;
+
+  m_pOutStream->writeU8(msgTypeFileCreateDirRequest);
+  return writeU8U16StringMsg(dirNameLen, pDirName);
+}
+
+bool 
+CFTMsgWriter::writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName)
+{
+  if (dirNameLen >= FT_FILENAME_SIZE) return false;
+
+  m_pOutStream->writeU8(msgTypeFileDirSizeRequest);
+  return writeU8U16StringMsg(dirNameLen, pDirName);
+}
+
+bool 
+CFTMsgWriter::writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+                                  char *pOldName, char *pNewName)
+{
+  if ((oldNameLen >= FT_FILENAME_SIZE) || (newNameLen >= FT_FILENAME_SIZE)) return false;
+
+  m_pOutStream->writeU8(msgTypeFileRenameRequest);
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(oldNameLen);
+  m_pOutStream->writeU16(newNameLen);
+  m_pOutStream->writeBytes(pOldName, oldNameLen);
+  m_pOutStream->writeBytes(pNewName, newNameLen);
+  m_pOutStream->flush();
+  
+  return true;
+}
+
+bool 
+CFTMsgWriter::writeFileDeleteRqst(unsigned short nameLen, char *pName)
+{
+  if (nameLen >= FT_FILENAME_SIZE) return false;
+
+  m_pOutStream->writeU8(msgTypeFileDeleteRequest);
+  return writeU8U16StringMsg(nameLen, pName);
+}
+
+bool 
+CFTMsgWriter::writeU8U16StringMsg(unsigned short strLength, char *pString)
+{
+  m_pOutStream->writeU8(0);
+  m_pOutStream->writeU16(strLength);
+  m_pOutStream->writeBytes(pString, strLength);
+  m_pOutStream->flush();
+  return true;
+}
diff --git a/common/rfb/CFTMsgWriter.h b/common/rfb/CFTMsgWriter.h
new file mode 100644
index 0000000..e4cdc0b
--- /dev/null
+++ b/common/rfb/CFTMsgWriter.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- CFTMsgWriter.h
+
+#ifndef __RFB_CFTMSGWRITER_H__
+#define __RFB_CFTMSGWRITER_H__
+
+#include <rdr/types.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class CFTMsgWriter
+  {
+  public:
+    CFTMsgWriter(rdr::OutStream *pOS);
+    ~CFTMsgWriter();
+    
+    bool writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly);
+    
+    bool writeFileDownloadCancel(unsigned short reasonLen, char *pReason);
+    bool writeFileDownloadRqst(unsigned short filenameLen, char *pFilename, 
+                               unsigned int position);
+    
+    bool writeFileUploadData(unsigned short dataSize, char *pData);
+    bool writeFileUploadData(unsigned int modTime);
+    bool writeFileUploadFailed(unsigned short reasonLen, char *pReason);
+    bool writeFileUploadRqst(unsigned short filenameLen, char *pFilename, 
+                             unsigned int position);
+    
+    bool writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName);
+    bool writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName);
+    
+    bool writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+                             char *pOldName, char *pNewName);
+    bool writeFileDeleteRqst(unsigned short nameLen, char *pName);
+    
+  private:
+    rdr::OutStream *m_pOutStream;
+    
+    bool writeU8U16StringMsg(unsigned short strLength, char *pString);
+  };
+}
+
+#endif // __RFB_CFTMSGWRITER_H__
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
new file mode 100644
index 0000000..bbc1176
--- /dev/null
+++ b/common/rfb/CMsgHandler.cxx
@@ -0,0 +1,103 @@
+/* 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 <rfb/Exception.h>
+#include <rfb/CMsgHandler.h>
+
+using namespace rfb;
+
+CMsgHandler::CMsgHandler()
+{
+}
+
+CMsgHandler::~CMsgHandler()
+{
+}
+
+void CMsgHandler::setDesktopSize(int width, int height)
+{
+  cp.width = width;
+  cp.height = height;
+}
+
+void CMsgHandler::setCursor(int w, int h, const Point& hotspot, void* data, void* mask)
+{
+}
+
+void CMsgHandler::setPixelFormat(const PixelFormat& pf)
+{
+  cp.setPF(pf);
+}
+
+void CMsgHandler::setName(const char* name)
+{
+  cp.setName(name);
+}
+
+void CMsgHandler::serverInit()
+{
+  throw Exception("CMsgHandler::serverInit called");
+}
+
+void CMsgHandler::framebufferUpdateStart()
+{
+}
+
+void CMsgHandler::framebufferUpdateEnd()
+{
+}
+
+void CMsgHandler::beginRect(const Rect& r, unsigned int encoding)
+{
+}
+
+void CMsgHandler::endRect(const Rect& r, unsigned int encoding)
+{
+}
+
+
+void CMsgHandler::setColourMapEntries(int firstColour, int nColours,
+                                      rdr::U16* rgbs)
+{
+  throw Exception("CMsgHandler::setColourMapEntries called");
+}
+
+void CMsgHandler::bell()
+{
+}
+
+void CMsgHandler::serverCutText(const char* str, int len)
+{
+}
+
+void CMsgHandler::fillRect(const Rect& r, Pixel pix)
+{
+}
+
+void CMsgHandler::imageRect(const Rect& r, void* pixels)
+{
+}
+
+void CMsgHandler::copyRect(const Rect& r, int srcX, int srcY)
+{
+}
+
+bool CMsgHandler::processFTMsg(int type)
+{
+  return false;
+}
+
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
new file mode 100644
index 0000000..6c86df0
--- /dev/null
+++ b/common/rfb/CMsgHandler.h
@@ -0,0 +1,71 @@
+/* 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.
+ */
+//
+// CMsgHandler - class to handle incoming messages on the client side.
+//
+
+#ifndef __RFB_CMSGHANDLER_H__
+#define __RFB_CMSGHANDLER_H__
+
+#include <rdr/types.h>
+#include <rfb/Pixel.h>
+#include <rfb/ConnParams.h>
+#include <rfb/Rect.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+  class CMsgHandler {
+  public:
+    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(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();
+
+    virtual void framebufferUpdateStart();
+    virtual void framebufferUpdateEnd();
+    virtual void beginRect(const Rect& r, unsigned int encoding);
+    virtual void endRect(const Rect& r, unsigned int encoding);
+
+    virtual void setColourMapEntries(int firstColour, int nColours,
+				     rdr::U16* rgbs);
+    virtual void bell();
+    virtual void serverCutText(const char* str, int len);
+
+    virtual void fillRect(const Rect& r, Pixel pix);
+    virtual void imageRect(const Rect& r, void* pixels);
+    virtual void copyRect(const Rect& r, int srcX, int srcY);
+
+    virtual bool processFTMsg(int type);
+
+    ConnParams cp;
+  };
+}
+#endif
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
new file mode 100644
index 0000000..38547c0
--- /dev/null
+++ b/common/rfb/CMsgReader.cxx
@@ -0,0 +1,158 @@
+/* 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 <rdr/InStream.h>
+#include <rfb/Exception.h>
+#include <rfb/util.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/CMsgReader.h>
+
+using namespace rfb;
+
+CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
+  : imageBufIdealSize(0), handler(handler_), is(is_),
+    imageBuf(0), imageBufSize(0)
+{
+  for (unsigned int i = 0; i <= encodingMax; i++) {
+    decoders[i] = 0;
+  }
+}
+
+CMsgReader::~CMsgReader()
+{
+  for (unsigned int i = 0; i <= encodingMax; i++) {
+    delete decoders[i];
+  }
+  delete [] imageBuf;
+}
+
+void CMsgReader::readSetColourMapEntries()
+{
+  is->skip(1);
+  int firstColour = is->readU16();
+  int nColours = is->readU16();
+  rdr::U16Array rgbs(nColours * 3);
+  for (int i = 0; i < nColours * 3; i++)
+    rgbs.buf[i] = is->readU16();
+  handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
+}
+
+void CMsgReader::readBell()
+{
+  handler->bell();
+}
+
+void CMsgReader::readServerCutText()
+{
+  is->skip(3);
+  int len = is->readU32();
+  if (len > 256*1024) {
+    is->skip(len);
+    fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
+    return;
+  }
+  CharArray ca(len+1);
+  ca.buf[len] = 0;
+  is->readBytes(ca.buf, len);
+  handler->serverCutText(ca.buf, len);
+}
+
+void CMsgReader::readFramebufferUpdateStart()
+{
+  handler->framebufferUpdateStart();
+}
+
+void CMsgReader::readFramebufferUpdateEnd()
+{
+  handler->framebufferUpdateEnd();
+}
+
+void CMsgReader::readRect(const Rect& r, unsigned int encoding)
+{
+  if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
+    fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
+	    r.width(), r.height(), r.tl.x, r.tl.y,
+            handler->cp.width, handler->cp.height);
+    throw Exception("Rect too big");
+  }
+
+  if (r.is_empty())
+    fprintf(stderr, "Warning: zero size rect\n");
+
+  handler->beginRect(r, encoding);
+
+  if (encoding == encodingCopyRect) {
+    readCopyRect(r);
+  } else {
+    if (!decoders[encoding]) {
+      decoders[encoding] = Decoder::createDecoder(encoding, this);
+      if (!decoders[encoding]) {
+        fprintf(stderr, "Unknown rect encoding %d\n", encoding);
+        throw Exception("Unknown rect encoding");
+      }
+    }
+    decoders[encoding]->readRect(r, handler);
+  }
+
+  handler->endRect(r, encoding);
+}
+
+void CMsgReader::readCopyRect(const Rect& r)
+{
+  int srcX = is->readU16();
+  int srcY = is->readU16();
+  handler->copyRect(r, srcX, srcY);
+}
+
+void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
+{
+  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(width, height, hotspot, data.buf, mask.buf);
+}
+
+rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels)
+{
+  int requiredBytes = required * (handler->cp.pf().bpp / 8);
+  int requestedBytes = requested * (handler->cp.pf().bpp / 8);
+  int size = requestedBytes;
+  if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+  if (size < requiredBytes)
+    size = requiredBytes;
+
+  if (imageBufSize < size) {
+    imageBufSize = size;
+    delete [] imageBuf;
+    imageBuf = new rdr::U8[imageBufSize];
+  }
+  if (nPixels)
+    *nPixels = imageBufSize / (handler->cp.pf().bpp / 8);
+  return imageBuf;
+}
+
+int CMsgReader::bpp()
+{
+  return handler->cp.pf().bpp;
+}
diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h
new file mode 100644
index 0000000..7a611fc
--- /dev/null
+++ b/common/rfb/CMsgReader.h
@@ -0,0 +1,73 @@
+/* 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.
+ */
+//
+// CMsgReader - class for reading RFB messages on the server side
+// (i.e. messages from client to server).
+//
+
+#ifndef __RFB_CMSGREADER_H__
+#define __RFB_CMSGREADER_H__
+
+#include <rdr/types.h>
+#include <rfb/encodings.h>
+#include <rfb/Decoder.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+  class CMsgHandler;
+  struct Rect;
+
+  class CMsgReader {
+  public:
+    virtual ~CMsgReader();
+
+    virtual void readServerInit()=0;
+
+    // readMsg() reads a message, calling the handler as appropriate.
+    virtual void readMsg()=0;
+
+    rdr::InStream* getInStream() { return is; }
+    rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0);
+    int bpp();
+
+    int imageBufIdealSize;
+
+  protected:
+    virtual void readSetColourMapEntries();
+    virtual void readBell();
+    virtual void readServerCutText();
+
+    virtual void readFramebufferUpdateStart();
+    virtual void readFramebufferUpdateEnd();
+    virtual void readRect(const Rect& r, unsigned int encoding);
+
+    virtual void readCopyRect(const Rect& r);
+
+    virtual void readSetCursor(int width, int height, const Point& hotspot);
+
+    CMsgReader(CMsgHandler* handler, rdr::InStream* is);
+
+    CMsgHandler* handler;
+    rdr::InStream* is;
+    Decoder* decoders[encodingMax+1];
+    rdr::U8* imageBuf;
+    int imageBufSize;
+  };
+}
+#endif
diff --git a/common/rfb/CMsgReaderV3.cxx b/common/rfb/CMsgReaderV3.cxx
new file mode 100644
index 0000000..d0cfc89
--- /dev/null
+++ b/common/rfb/CMsgReaderV3.cxx
@@ -0,0 +1,107 @@
+/* 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 <rfb/PixelFormat.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rdr/InStream.h>
+#include <rfb/CMsgReaderV3.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/util.h>
+
+using namespace rfb;
+
+CMsgReaderV3::CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is)
+  : CMsgReader(handler, is), nUpdateRectsLeft(0)
+{
+}
+
+CMsgReaderV3::~CMsgReaderV3()
+{
+}
+
+void CMsgReaderV3::readServerInit()
+{
+  int width = is->readU16();
+  int height = is->readU16();
+  handler->setDesktopSize(width, height);
+  PixelFormat pf;
+  pf.read(is);
+  handler->setPixelFormat(pf);
+  CharArray name(is->readString());
+  handler->setName(name.buf);
+  handler->serverInit();
+}
+
+void CMsgReaderV3::readMsg()
+{
+  if (nUpdateRectsLeft == 0) {
+
+    int type = is->readU8();
+    switch (type) {
+    case msgTypeFramebufferUpdate:   readFramebufferUpdate(); break;
+    case msgTypeSetColourMapEntries: readSetColourMapEntries(); break;
+    case msgTypeBell:                readBell(); break;
+    case msgTypeServerCutText:       readServerCutText(); break;
+
+    case msgTypeFileListData:
+    case msgTypeFileDownloadData:
+    case msgTypeFileUploadCancel:
+    case msgTypeFileDownloadFailed:
+    case msgTypeFileDirSizeData:
+    case msgTypeFileLastRequestFailed:
+      handler->processFTMsg(type); break;
+
+    default:
+      fprintf(stderr, "unknown message type %d\n", type);
+      throw Exception("unknown message type");
+    }
+
+  } else {
+
+    int x = is->readU16();
+    int y = is->readU16();
+    int w = is->readU16();
+    int h = is->readU16();
+    unsigned int encoding = is->readU32();
+
+    switch (encoding) {
+    case pseudoEncodingDesktopSize:
+      handler->setDesktopSize(w, h);
+      break;
+    case pseudoEncodingCursor:
+      readSetCursor(w, h, Point(x,y));
+      break;
+    case pseudoEncodingLastRect:
+      nUpdateRectsLeft = 1;     // this rectangle is the last one
+      break;
+    default:
+      readRect(Rect(x, y, x+w, y+h), encoding);
+      break;
+    };
+
+    nUpdateRectsLeft--;
+    if (nUpdateRectsLeft == 0) handler->framebufferUpdateEnd();
+  }
+}
+
+void CMsgReaderV3::readFramebufferUpdate()
+{
+  is->skip(1);
+  nUpdateRectsLeft = is->readU16();
+  handler->framebufferUpdateStart();
+}
diff --git a/common/rfb/CMsgReaderV3.h b/common/rfb/CMsgReaderV3.h
new file mode 100644
index 0000000..689bb65
--- /dev/null
+++ b/common/rfb/CMsgReaderV3.h
@@ -0,0 +1,35 @@
+/* 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_CMSGREADERV3_H__
+#define __RFB_CMSGREADERV3_H__
+
+#include <rfb/CMsgReader.h>
+
+namespace rfb {
+  class CMsgReaderV3 : public CMsgReader {
+  public:
+    CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is);
+    virtual ~CMsgReaderV3();
+    virtual void readServerInit();
+    virtual void readMsg();
+  private:
+    void readFramebufferUpdate();
+    int nUpdateRectsLeft;
+  };
+}
+#endif
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
new file mode 100644
index 0000000..cdfb4e5
--- /dev/null
+++ b/common/rfb/CMsgWriter.cxx
@@ -0,0 +1,132 @@
+/* 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 <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/Rect.h>
+#include <rfb/ConnParams.h>
+#include <rfb/Decoder.h>
+#include <rfb/CMsgWriter.h>
+
+using namespace rfb;
+
+CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
+  : cp(cp_), os(os_)
+{
+}
+
+CMsgWriter::~CMsgWriter()
+{
+}
+
+void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
+{
+  startMsg(msgTypeSetPixelFormat);                                 
+  os->pad(3);
+  pf.write(os);
+  endMsg();
+}
+
+void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
+{
+  startMsg(msgTypeSetEncodings);
+  os->skip(1);
+  os->writeU16(nEncodings);
+  for (int i = 0; i < nEncodings; i++)
+    os->writeU32(encodings[i]);
+  endMsg();
+}
+
+// Ask for encodings based on which decoders are supported.  Assumes higher
+// encoding numbers are more desirable.
+
+void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
+{
+  int nEncodings = 0;
+  rdr::U32 encodings[encodingMax+3];
+  if (cp->supportsLocalCursor)
+    encodings[nEncodings++] = pseudoEncodingCursor;
+  if (cp->supportsDesktopResize)
+    encodings[nEncodings++] = pseudoEncodingDesktopSize;
+  if (Decoder::supported(preferredEncoding)) {
+    encodings[nEncodings++] = preferredEncoding;
+  }
+  if (useCopyRect) {
+    encodings[nEncodings++] = encodingCopyRect;
+  }
+  for (int i = encodingMax; i >= 0; i--) {
+    if (i != preferredEncoding && Decoder::supported(i)) {
+      encodings[nEncodings++] = i;
+    }
+  }
+  encodings[nEncodings++] = pseudoEncodingLastRect;
+  if (cp->customCompressLevel && cp->compressLevel >= 0 && cp->compressLevel <= 9)
+      encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
+  if (!cp->noJpeg && cp->qualityLevel >= 1 && cp->qualityLevel <= 9)
+      encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
+
+  writeSetEncodings(nEncodings, encodings);
+}
+  
+void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
+{
+  startMsg(msgTypeFramebufferUpdateRequest);
+  os->writeU8(incremental);
+  os->writeU16(r.tl.x);
+  os->writeU16(r.tl.y);
+  os->writeU16(r.width());
+  os->writeU16(r.height());
+  endMsg();
+}
+
+
+void CMsgWriter::keyEvent(rdr::U32 key, bool down)
+{
+  startMsg(msgTypeKeyEvent);
+  os->writeU8(down);
+  os->pad(2);
+  os->writeU32(key);
+  endMsg();
+}
+
+
+void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
+{
+  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(p.x);
+  os->writeU16(p.y);
+  endMsg();
+}
+
+
+void CMsgWriter::clientCutText(const char* str, int len)
+{
+  startMsg(msgTypeClientCutText);
+  os->pad(3);
+  os->writeU32(len);
+  os->writeBytes(str, len);
+  endMsg();
+}
diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h
new file mode 100644
index 0000000..19be8df
--- /dev/null
+++ b/common/rfb/CMsgWriter.h
@@ -0,0 +1,65 @@
+/* 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.
+ */
+//
+// CMsgWriter - class for writing RFB messages on the server side.
+//
+
+#ifndef __RFB_CMSGWRITER_H__
+#define __RFB_CMSGWRITER_H__
+
+#include <rfb/InputHandler.h>
+
+namespace rdr { class OutStream; }
+
+namespace rfb {
+
+  class PixelFormat;
+  class ConnParams;
+  struct Rect;
+
+  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);
+
+    // 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; }
+
+  protected:
+    CMsgWriter(ConnParams* cp, rdr::OutStream* os);
+
+    ConnParams* cp;
+    rdr::OutStream* os;
+  };
+}
+#endif
diff --git a/common/rfb/CMsgWriterV3.cxx b/common/rfb/CMsgWriterV3.cxx
new file mode 100644
index 0000000..a980795
--- /dev/null
+++ b/common/rfb/CMsgWriterV3.cxx
@@ -0,0 +1,49 @@
+/* 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 <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/CMsgWriterV3.h>
+
+using namespace rfb;
+
+CMsgWriterV3::CMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
+  : CMsgWriter(cp, os)
+{
+}
+
+CMsgWriterV3::~CMsgWriterV3()
+{
+}
+
+void CMsgWriterV3::writeClientInit(bool shared)
+{
+  os->writeU8(shared);
+  endMsg();
+}
+
+void CMsgWriterV3::startMsg(int type)
+{
+  os->writeU8(type);
+}
+
+void CMsgWriterV3::endMsg()
+{
+  os->flush();
+}
diff --git a/common/rfb/CMsgWriterV3.h b/common/rfb/CMsgWriterV3.h
new file mode 100644
index 0000000..0b2f9af
--- /dev/null
+++ b/common/rfb/CMsgWriterV3.h
@@ -0,0 +1,35 @@
+/* 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_CMSGWRITERV3_H__
+#define __RFB_CMSGWRITERV3_H__
+
+#include <rfb/CMsgWriter.h>
+
+namespace rfb {
+  class CMsgWriterV3 : public CMsgWriter {
+  public:
+    CMsgWriterV3(ConnParams* cp, rdr::OutStream* os);
+    virtual ~CMsgWriterV3();
+
+    virtual void writeClientInit(bool shared);
+    virtual void startMsg(int type);
+    virtual void endMsg();
+
+  };
+}
+#endif
diff --git a/common/rfb/CSecurity.h b/common/rfb/CSecurity.h
new file mode 100644
index 0000000..90a01d7
--- /dev/null
+++ b/common/rfb/CSecurity.h
@@ -0,0 +1,52 @@
+/* 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.
+ */
+//
+// 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.  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
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+//
+// description is a string describing the level of encryption applied to the
+// session, or null if no encryption will be used.
+
+#ifndef __RFB_CSECURITY_H__
+#define __RFB_CSECURITY_H__
+
+namespace rfb {
+  class CConnection;
+  class CSecurity {
+  public:
+    virtual ~CSecurity() {}
+    virtual bool processMsg(CConnection* cc)=0;
+    virtual void destroy() { delete this; }
+    virtual int getType() const = 0;
+    virtual const char* description() const = 0;
+  };
+}
+#endif
diff --git a/common/rfb/CSecurityNone.h b/common/rfb/CSecurityNone.h
new file mode 100644
index 0000000..54c1016
--- /dev/null
+++ b/common/rfb/CSecurityNone.h
@@ -0,0 +1,36 @@
+/* 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.
+ */
+//
+// CSecurityNone.h
+//
+
+#ifndef __CSECURITYNONE_H__
+#define __CSECURITYNONE_H__
+
+#include <rfb/CSecurity.h>
+
+namespace rfb {
+
+  class CSecurityNone : public CSecurity {
+  public:
+    virtual bool processMsg(CConnection* cc) { return true; }
+    virtual int getType() const {return secTypeNone;}
+    virtual const char* description() const {return "No Encryption";}
+  };
+}
+#endif
diff --git a/common/rfb/CSecurityVncAuth.cxx b/common/rfb/CSecurityVncAuth.cxx
new file mode 100644
index 0000000..ba5a30b
--- /dev/null
+++ b/common/rfb/CSecurityVncAuth.cxx
@@ -0,0 +1,74 @@
+/* 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.
+ */
+//
+// 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/Password.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/util.h>
+extern "C" {
+#include <rfb/d3des.h>
+}
+
+
+using namespace rfb;
+
+static const int vncAuthChallengeSize = 16;
+
+
+CSecurityVncAuth::CSecurityVncAuth(UserPasswdGetter* upg_)
+  : upg(upg_)
+{
+}
+
+CSecurityVncAuth::~CSecurityVncAuth()
+{
+}
+
+bool CSecurityVncAuth::processMsg(CConnection* cc)
+{
+  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);
+  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();
+  return true;
+}
diff --git a/common/rfb/CSecurityVncAuth.h b/common/rfb/CSecurityVncAuth.h
new file mode 100644
index 0000000..8d38d87
--- /dev/null
+++ b/common/rfb/CSecurityVncAuth.h
@@ -0,0 +1,39 @@
+/* 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_CSECURITYVNCAUTH_H__
+#define __RFB_CSECURITYVNCAUTH_H__
+
+#include <rfb/CSecurity.h>
+#include <rfb/secTypes.h>
+
+namespace rfb {
+
+  class UserPasswdGetter;
+
+  class CSecurityVncAuth : public CSecurity {
+  public:
+    CSecurityVncAuth(UserPasswdGetter* pg);
+    virtual ~CSecurityVncAuth();
+    virtual bool processMsg(CConnection* cc);
+    virtual int getType() const {return secTypeVncAuth;};
+    virtual const char* description() const {return "No Encryption";}
+  private:
+    UserPasswdGetter* upg;
+  };
+}
+#endif
diff --git a/common/rfb/ColourCube.h b/common/rfb/ColourCube.h
new file mode 100644
index 0000000..b83cbba
--- /dev/null
+++ b/common/rfb/ColourCube.h
@@ -0,0 +1,96 @@
+/* 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.
+ */
+//
+// ColourCube - structure to represent a colour cube.  The colour cube consists
+// of its dimensions (nRed x nGreen x nBlue) and a table mapping an (r,g,b)
+// triple to a pixel value.
+//
+// A colour cube is used in two cases.  The first is internally in a viewer
+// when it cannot use a trueColour format, nor can it have exclusive access to
+// a writable colour map.  This is most notably the case for an X viewer
+// wishing to use a PseudoColor X server's default colormap.
+//
+// The second use is on the server side when a client has asked for a colour
+// map and the server is trueColour.  Instead of setting an uneven trueColour
+// format like bgr233, it can set the client's colour map up with a 6x6x6
+// colour cube.  For this use the colour cube table has a null mapping, which
+// makes it easy to perform the reverse lookup operation from pixel value to
+// r,g,b values.
+
+#ifndef __RFB_COLOURCUBE_H__
+#define __RFB_COLOURCUBE_H__
+
+#include <rfb/Pixel.h>
+#include <rfb/ColourMap.h>
+
+namespace rfb {
+
+  class ColourCube : public ColourMap {
+  public:
+    ColourCube(int nr, int ng, int nb, Pixel* table_=0)
+      : nRed(nr), nGreen(ng), nBlue(nb), table(table_), deleteTable(false)
+    {
+      if (!table) {
+        table = new Pixel[size()];
+        deleteTable = true;
+        // set a null mapping by default
+        for (int i = 0; i < size(); i++)
+          table[i] = i;
+      }
+    }
+
+    ColourCube() : deleteTable(false) {}
+
+    virtual ~ColourCube() {
+      if (deleteTable) delete [] table;
+    }
+
+    void set(int r, int g, int b, Pixel p) {
+      table[(r * nGreen + g) * nBlue + b] = p;
+    }
+
+    Pixel lookup(int r, int g, int b) const {
+      return table[(r * nGreen + g) * nBlue + b];
+    }
+
+    int size()      const { return nRed*nGreen*nBlue; }
+    int redMult()   const { return nGreen*nBlue; }
+    int greenMult() const { return nBlue; }
+    int blueMult()  const { return 1; }
+
+    // ColourMap lookup() method.  Note that this only works when the table has
+    // the default null mapping.
+    virtual void lookup(int i, int* r, int* g, int* b) {
+      if (i >= size()) return;
+      *b = i % nBlue;
+      i /= nBlue;
+      *g = i % nGreen;
+      *r = i / nGreen;
+      *r = (*r * 65535 + (nRed-1)   / 2) / (nRed-1);
+      *g = (*g * 65535 + (nGreen-1) / 2) / (nGreen-1);
+      *b = (*b * 65535 + (nBlue-1)  / 2) / (nBlue-1);
+    }
+
+    int nRed;
+    int nGreen;
+    int nBlue;
+    Pixel* table;
+    bool deleteTable;
+  };
+}
+#endif
diff --git a/common/rfb/ColourMap.h b/common/rfb/ColourMap.h
new file mode 100644
index 0000000..da6cb12
--- /dev/null
+++ b/common/rfb/ColourMap.h
@@ -0,0 +1,34 @@
+/* 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_COLOURMAP_H__
+#define __RFB_COLOURMAP_H__
+namespace rfb {
+  struct Colour {
+    Colour() : r(0), g(0), b(0) {}
+    Colour(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
+    int r, g, b;
+    bool operator==(const Colour& c) const {return c.r == r && c.g == g && c.b == b;}
+    bool operator!=(const Colour& c) const {return !(c == *this);}
+  };
+
+  class ColourMap {
+  public:
+    virtual void lookup(int index, int* r, int* g, int* b)=0;
+  };
+}
+#endif
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
new file mode 100644
index 0000000..ce3d68a
--- /dev/null
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -0,0 +1,137 @@
+/* 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 <vector>
+#include <rdr/types.h>
+#include <rfb/Exception.h>
+#include <rfb/ComparingUpdateTracker.h>
+
+using namespace rfb;
+
+ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
+  : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
+{
+    changed.assign_union(fb->getRect());
+}
+
+ComparingUpdateTracker::~ComparingUpdateTracker()
+{
+}
+
+
+#define BLOCK_SIZE 16
+
+void ComparingUpdateTracker::compare()
+{
+  std::vector<Rect> rects;
+  std::vector<Rect>::iterator i;
+
+  if (firstCompare) {
+    // NB: We leave the change region untouched on this iteration,
+    // 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(), __rfbmin(fb->height(), y+BLOCK_SIZE));
+      int srcStride;
+      const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
+      oldFb.imageRect(pos, srcData, srcStride);
+    }
+    firstCompare = false;
+  } else {
+    copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
+    for (i = rects.begin(); i != rects.end(); i++)
+      oldFb.copyRect(*i, copy_delta);
+
+    Region to_check = changed.union_(copied);
+    to_check.get_rects(&rects);
+
+    Region newChanged;
+    for (i = rects.begin(); i != rects.end(); i++)
+      compareRect(*i, &newChanged);
+
+    copied.assign_subtract(newChanged);
+    changed = newChanged;
+  }
+}
+
+void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
+{
+  if (!r.enclosed_by(fb->getRect())) {
+    fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
+    return;
+  }
+
+  int bytesPerPixel = fb->getPF().bpp/8;
+  int oldStride;
+  rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
+  int oldStrideBytes = oldStride * bytesPerPixel;
+
+  std::vector<Rect> changedBlocks;
+
+  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, __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 = __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 = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
+      int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
+
+      for (int y = blockTop; y < blockBottom; y++)
+      {
+        if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
+        {
+          // A block has changed - copy the remainder to the oldFb
+          changedBlocks.push_back(Rect(blockLeft, blockTop,
+                                       blockRight, blockBottom));
+          for (int y2 = y; y2 < blockBottom; y2++)
+          {
+            memcpy(oldPtr, newPtr, blockWidthInBytes);
+            newPtr += newStrideBytes;
+            oldPtr += oldStrideBytes;
+          }
+          break;
+        }
+
+        newPtr += newStrideBytes;
+        oldPtr += oldStrideBytes;
+      }
+
+      oldBlockPtr += blockWidthInBytes;
+      newBlockPtr += blockWidthInBytes;
+    }
+
+    oldData += oldStrideBytes * BLOCK_SIZE;
+  }
+
+  if (!changedBlocks.empty()) {
+    Region temp;
+    temp.setOrderedRects(changedBlocks);
+    newChanged->assign_union(temp);
+  }
+}
diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h
new file mode 100644
index 0000000..5d2e5ed
--- /dev/null
+++ b/common/rfb/ComparingUpdateTracker.h
@@ -0,0 +1,43 @@
+/* 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_COMPARINGUPDATETRACKER_H__
+#define __RFB_COMPARINGUPDATETRACKER_H__
+
+#include <rfb/UpdateTracker.h>
+
+namespace rfb {
+
+  class ComparingUpdateTracker : public SimpleUpdateTracker {
+  public:
+    ComparingUpdateTracker(PixelBuffer* buffer);
+    ~ComparingUpdateTracker();
+
+    // compare() does the comparison and reduces its changed and copied regions
+    // as appropriate.
+
+    virtual void compare();
+  private:
+    void compareRect(const Rect& r, Region* newchanged);
+    PixelBuffer* fb;
+    ManagedPixelBuffer oldFb;
+    bool firstCompare;
+  };
+
+}
+#endif
diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx
new file mode 100644
index 0000000..9ebc20a
--- /dev/null
+++ b/common/rfb/Configuration.cxx
@@ -0,0 +1,466 @@
+/* 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
+ * (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.
+ */
+
+// -=- Configuration.cxx
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#endif
+
+#include <rfb/util.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb/Threading.h>
+
+#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>
+#include <rdr/HexInStream.h>
+
+using namespace rfb;
+
+static LogWriter vlog("Config");
+
+
+// -=- The Global Configuration object
+Configuration* Configuration::global_ = 0;
+Configuration* Configuration::global() {
+  if (!global_)
+    global_ = new Configuration("Global");
+  return global_;
+}
+
+
+// -=- 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;
+  while (current) {
+    if ((int)strlen(current->getName()) == len &&
+        strncasecmp(current->getName(), name, len) == 0)
+    {
+      bool b = current->setParam(val);
+      current->setHasBeenSet(); 
+      if (b && immutable) 
+	current->setImmutable();
+      return b;
+    }
+    current = current->_next;
+  }
+  return _next ? _next->set(name, len, val, immutable) : false;
+}
+
+bool Configuration::set(const char* config, bool immutable) {
+  bool hyphen = false;
+  if (config[0] == '-') {
+    hyphen = true;
+    config++;
+    if (config[0] == '-') config++; // allow gnu-style --<option>
+  }
+  const char* equal = strchr(config, '=');
+  if (equal) {
+    return set(config, equal-config, equal+1, immutable);
+  } else if (hyphen) {
+    VoidParameter* current = head;
+    while (current) {
+      if (strcasecmp(current->getName(), config) == 0) {
+        bool b = current->setParam();
+	current->setHasBeenSet(); 
+        if (b && immutable) 
+	  current->setImmutable();
+        return b;
+      }
+      current = current->_next;
+    }
+  }    
+  return _next ? _next->set(config, immutable) : false;
+}
+
+VoidParameter* Configuration::get(const char* param)
+{
+  VoidParameter* current = head;
+  while (current) {
+    if (strcasecmp(current->getName(), param) == 0)
+      return current;
+    current = current->_next;
+  }
+  return _next ? _next->get(param) : 0;
+}
+
+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();
+    fprintf(stderr,"  %-*s -", nameWidth, current->getName());
+    int column = strlen(current->getName());
+    if (column < nameWidth) column = nameWidth;
+    column += 4;
+    while (true) {
+      const char* s = strchr(desc, ' ');
+      int wordLen;
+      if (s) wordLen = s-desc;
+      else wordLen = strlen(desc);
+
+      if (column + wordLen + 1 > width) {
+        fprintf(stderr,"\n%*s",nameWidth+4,"");
+        column = nameWidth+4;
+      }
+      fprintf(stderr," %.*s",wordLen,desc);
+      column += wordLen + 1;
+      desc += wordLen + 1;
+      if (!s) break;
+    }
+
+    if (def_str) {
+      if (column + (int)strlen(def_str) + 11 > width)
+        fprintf(stderr,"\n%*s",nameWidth+4,"");
+      fprintf(stderr," (default=%s)\n",def_str);
+      strFree(def_str);
+    } else {
+      fprintf(stderr,"\n");
+    }
+    current = current->_next;
+  }
+
+  if (_next)
+    _next->list(width, nameWidth);
+}
+
+
+// -=- VoidParameter
+
+VoidParameter::VoidParameter(const char* name_, const char* desc_, Configuration* conf)
+  : immutable(false), _hasBeenSet(false), name(name_), description(desc_) {
+  if (!conf)
+    conf = Configuration::global();
+  _next = conf->head;
+  conf->head = this;
+}
+
+VoidParameter::~VoidParameter() {
+}
+
+const char*
+VoidParameter::getName() const {
+  return name;
+}
+
+const char*
+VoidParameter::getDescription() const {
+  return description;
+}
+
+bool VoidParameter::setParam() {
+  return false;
+}
+
+bool VoidParameter::isBool() const {
+  return false;
+}
+
+void
+VoidParameter::setImmutable() {
+  vlog.debug("set immutable %s", getName());
+  immutable = true;
+}
+
+void
+VoidParameter::setHasBeenSet() {
+  _hasBeenSet = true;
+} 
+
+bool
+VoidParameter::hasBeenSet() {
+  return _hasBeenSet;
+}
+
+// -=- AliasParameter
+
+AliasParameter::AliasParameter(const char* name_, const char* desc_,
+                               VoidParameter* param_, Configuration* conf)
+  : VoidParameter(name_, desc_, conf), param(param_) {
+}
+
+bool
+AliasParameter::setParam(const char* v) {
+  return param->setParam(v);
+}
+
+bool AliasParameter::setParam() {
+  return param->setParam();
+}
+
+char*
+AliasParameter::getDefaultStr() const {
+  return 0;
+}
+
+char* AliasParameter::getValueStr() const {
+  return param->getValueStr();
+}
+
+bool AliasParameter::isBool() const {
+  return param->isBool();
+}
+
+void
+AliasParameter::setImmutable() {
+  vlog.debug("set immutable %s (Alias)", getName());
+  param->setImmutable();
+}
+
+
+// -=- BoolParameter
+
+BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v, Configuration* conf)
+: VoidParameter(name_, desc_, conf), value(v), def_value(v) {
+}
+
+bool
+BoolParameter::setParam(const char* v) {
+  if (immutable) return true;
+
+  if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
+      || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
+    value = 1;
+  else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
+           || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
+    value = 0;
+  else {
+    vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
+    return false;
+  }
+
+  vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
+  return true;
+}
+
+bool BoolParameter::setParam() {
+  setParam(true);
+  return true;
+}
+
+void BoolParameter::setParam(bool b) {
+  if (immutable) return;
+  value = b;
+  vlog.debug("set %s(Bool) to %d", getName(), value);
+}
+
+char*
+BoolParameter::getDefaultStr() const {
+  return strDup(def_value ? "1" : "0");
+}
+
+char* BoolParameter::getValueStr() const {
+  return strDup(value ? "1" : "0");
+}
+
+bool BoolParameter::isBool() const {
+  return true;
+}
+
+BoolParameter::operator bool() const {
+  return value;
+}
+
+// -=- IntParameter
+
+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);
+  int i = atoi(v);
+  if (i < minValue || i > maxValue)
+    return false;
+  value = i;
+  return true;
+}
+
+bool
+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;
+}
+
+char*
+IntParameter::getDefaultStr() const {
+  char* result = new char[16];
+  sprintf(result, "%d", def_value);
+  return result;
+}
+
+char* IntParameter::getValueStr() const {
+  char* result = new char[16];
+  sprintf(result, "%d", value);
+  return result;
+}
+
+IntParameter::operator int() const {
+  return value;
+}
+
+// -=- StringParameter
+
+StringParameter::StringParameter(const char* name_, const char* desc_,
+                                 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_);
+    throw rfb::Exception("Default value <null> not allowed");
+  }
+}
+
+StringParameter::~StringParameter() {
+  strFree(value);
+}
+
+bool StringParameter::setParam(const char* v) {
+  LOCK_CONFIG;
+  if (immutable) return true;
+  if (!v)
+    throw rfb::Exception("setParam(<null>) not allowed");
+  vlog.debug("set %s(String) to %s", getName(), v);
+  CharArray oldValue(value);
+  value = strDup(v);
+  return value != 0;
+}
+
+char* StringParameter::getDefaultStr() const {
+  return strDup(def_value);
+}
+
+char* StringParameter::getValueStr() const {
+  LOCK_CONFIG;
+  return strDup(value);
+}
+
+// -=- BinaryParameter
+
+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;
+    memcpy(value, v, l);
+  }
+}
+BinaryParameter::~BinaryParameter() {
+  if (value)
+    delete [] value;
+}
+
+bool BinaryParameter::setParam(const char* v) {
+  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) {
+  LOCK_CONFIG;
+  if (immutable) return; 
+  vlog.debug("set %s(Binary)", getName());
+  delete [] value; value = 0;
+  if (len) {
+    value = new char[len];
+    length = len;
+    memcpy(value, v, len);
+  }
+}
+
+char* BinaryParameter::getDefaultStr() const {
+  return rdr::HexOutStream::binToHexStr(def_value, def_length);
+}
+
+char* BinaryParameter::getValueStr() const {
+  LOCK_CONFIG;
+  return rdr::HexOutStream::binToHexStr(value, length);
+}
+
+void BinaryParameter::getData(void** data_, int* length_) const {
+  LOCK_CONFIG;
+  if (length_) *length_ = length;
+  if (data_) {
+    *data_ = new char[length];
+    memcpy(*data_, value, length);
+  }
+}
diff --git a/common/rfb/Configuration.h b/common/rfb/Configuration.h
new file mode 100644
index 0000000..e3b85b8
--- /dev/null
+++ b/common/rfb/Configuration.h
@@ -0,0 +1,265 @@
+/* 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.
+ */
+
+// -=- Configuration.h
+//
+// This header defines a set of classes used to represent configuration
+// parameters of different types.  Instances of the different parameter
+// types are associated with instances of the Configuration class, and
+// are each given a unique name.  The Configuration class provides a
+// generic API through which parameters may be located by name and their
+// value set, thus removing the need to write platform-specific code.
+// Simply defining a new parameter and associating it with a Configuration
+// will allow it to be configured by the user.
+//
+// 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
+    bool set(const char* param, const char* value, bool immutable=false);
+
+    // - Set parameter to value (separated by "=")
+    bool set(const char* config, bool immutable=false);
+
+    // - Set named parameter to value, with name truncated at len
+    bool set(const char* name, int len,
+                  const char* val, bool immutable);
+
+    // - Get named parameter
+    VoidParameter* get(const char* param);
+
+    // - List the parameters of this Configuration group
+    void list(int width=79, int nameWidth=10);
+
+    // - 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
+  //     Configuration parameter base-class.
+
+  class VoidParameter {
+  public:
+    VoidParameter(const char* name_, const char* desc_, Configuration* conf=0);
+    virtual  ~VoidParameter();
+    const char* getName() const;
+    const char* getDescription() const;
+
+    virtual bool setParam(const char* value)  = 0;
+    virtual bool setParam();
+    virtual char* getDefaultStr() const = 0;
+    virtual char* getValueStr() const = 0;
+    virtual bool isBool() const;
+
+    virtual void setImmutable();
+    virtual void setHasBeenSet();
+    bool hasBeenSet();
+
+  protected:
+    friend class Configuration;
+    friend struct ParameterIterator;
+
+    VoidParameter* _next;
+    bool immutable;
+    bool _hasBeenSet;
+    const char* name;
+    const char* description;
+  };
+
+  class AliasParameter : public VoidParameter {
+  public:
+    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;
+    virtual char* getValueStr() const;
+    virtual bool isBool() const;
+    virtual void setImmutable();
+  private:
+    VoidParameter* param;
+  };
+
+  class BoolParameter : public VoidParameter {
+  public:
+    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);
+    virtual char* getDefaultStr() const;
+    virtual char* getValueStr() const;
+    virtual bool isBool() const;
+    operator bool() const;
+  protected:
+    bool value;
+    bool def_value;
+  };
+
+  class IntParameter : public VoidParameter {
+  public:
+    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;
+    virtual char* getValueStr() const;
+    operator int() const;
+  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, Configuration* conf=0);
+    virtual ~StringParameter();
+    virtual bool setParam(const char* value);
+    virtual char* getDefaultStr() const;
+    virtual char* getValueStr() const;
+
+    // getData() returns a copy of the data - it must be delete[]d by the
+    // caller.
+    char* getData() const { return getValueStr(); }
+  protected:
+    char* value;
+    const char* def_value;
+  };
+
+  class BinaryParameter : public VoidParameter {
+  public:
+    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:
+    char* value;
+    int length;
+    char* def_value;
+    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/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
new file mode 100644
index 0000000..d4ae589
--- /dev/null
+++ b/common/rfb/ConnParams.cxx
@@ -0,0 +1,125 @@
+/* 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 <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/Exception.h>
+#include <rfb/encodings.h>
+#include <rfb/Encoder.h>
+#include <rfb/ConnParams.h>
+#include <rfb/util.h>
+
+using namespace rfb;
+
+ConnParams::ConnParams()
+  : majorVersion(0), minorVersion(0), width(0), height(0), useCopyRect(false),
+    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("");
+}
+
+ConnParams::~ConnParams()
+{
+  delete [] name_;
+  delete [] encodings_;
+}
+
+bool ConnParams::readVersion(rdr::InStream* is, bool* done)
+{
+  if (verStrPos >= 12) return false;
+  while (is->checkNoWait(1) && verStrPos < 12) {
+    verStr[verStrPos++] = is->readU8();
+  }
+
+  if (verStrPos < 12) {
+    *done = false;
+    return true;
+  }
+  *done = true;
+  verStr[12] = 0;
+  return (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion,&minorVersion) == 2);
+}
+
+void ConnParams::writeVersion(rdr::OutStream* os)
+{
+  char str[13];
+  sprintf(str, "RFB %03d.%03d\n", majorVersion, minorVersion);
+  os->writeBytes(str, 12);
+  os->flush();
+}
+
+void ConnParams::setPF(const PixelFormat& pf)
+{
+  pf_ = pf;
+
+  if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
+    throw Exception("setPF: not 8, 16 or 32 bpp?");
+}
+
+void ConnParams::setName(const char* name)
+{
+  delete [] name_;
+  name_ = strDup(name);
+}
+
+void ConnParams::setEncodings(int nEncodings, const rdr::U32* encodings)
+{
+  if (nEncodings > nEncodings_) {
+    delete [] encodings_;
+    encodings_ = new rdr::U32[nEncodings];
+  }
+  nEncodings_ = nEncodings;
+  useCopyRect = false;
+  supportsLocalCursor = false;
+  supportsDesktopResize = false;
+  supportsLocalXCursor = false;
+  supportsLastRect = false;
+  customCompressLevel = false;
+  compressLevel = -1;
+  noJpeg = true;
+  qualityLevel = -1;
+  currentEncoding_ = encodingRaw;
+
+  for (int i = nEncodings-1; i >= 0; i--) {
+    encodings_[i] = encodings[i];
+
+    if (encodings[i] == encodingCopyRect)
+      useCopyRect = true;
+    else if (encodings[i] == pseudoEncodingCursor)
+      supportsLocalCursor = true;
+    else if (encodings[i] == pseudoEncodingXCursor)
+      supportsLocalXCursor = true;
+    else if (encodings[i] == pseudoEncodingDesktopSize)
+      supportsDesktopResize = true;
+    else if (encodings[i] == pseudoEncodingLastRect)
+      supportsLastRect = true;
+    else if (encodings[i] >= pseudoEncodingCompressLevel0 &&
+	     encodings[i] <= pseudoEncodingCompressLevel9) {
+      customCompressLevel = true;
+      compressLevel = encodings[i] - pseudoEncodingCompressLevel0;
+    } else if (encodings[i] >= pseudoEncodingQualityLevel0 &&
+	       encodings[i] <= pseudoEncodingQualityLevel9) {
+      noJpeg = false;
+      qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;
+    } else if (encodings[i] <= encodingMax && Encoder::supported(encodings[i]))
+      currentEncoding_ = encodings[i];
+  }
+}
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
new file mode 100644
index 0000000..47e6a5f
--- /dev/null
+++ b/common/rfb/ConnParams.h
@@ -0,0 +1,93 @@
+/* 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.
+ */
+//
+// ConnParams - structure containing the connection parameters.
+//
+
+#ifndef __RFB_CONNPARAMS_H__
+#define __RFB_CONNPARAMS_H__
+
+#include <rdr/types.h>
+#include <rfb/PixelFormat.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+  class ConnParams {
+  public:
+    ConnParams();
+    ~ConnParams();
+
+    bool readVersion(rdr::InStream* is, bool* done);
+    void writeVersion(rdr::OutStream* os);
+
+    int majorVersion;
+    int minorVersion;
+
+    void setVersion(int major, int minor) {
+      majorVersion = major; minorVersion = minor;
+    }
+    bool isVersion(int major, int minor) {
+      return majorVersion == major && minorVersion == minor;
+    }
+    bool beforeVersion(int major, int minor) {
+      return (majorVersion < major ||
+              (majorVersion == major && minorVersion < minor));
+    }
+    bool afterVersion(int major, int minor) {
+      return !beforeVersion(major,minor+1);
+    }
+
+    int width;
+    int height;
+
+    const PixelFormat& pf() { return pf_; }
+    void setPF(const PixelFormat& pf);
+
+    const char* name() { return name_; }
+    void setName(const char* name);
+
+    rdr::U32 currentEncoding() { return currentEncoding_; }
+    int nEncodings() { return nEncodings_; }
+    const rdr::U32* encodings() { return encodings_; }
+    void setEncodings(int nEncodings, const rdr::U32* encodings);
+    bool useCopyRect;
+
+    bool supportsLocalCursor;
+    bool supportsLocalXCursor;
+    bool supportsDesktopResize;
+    bool supportsLastRect;
+
+    bool customCompressLevel;
+    int compressLevel;
+    bool noJpeg;
+    int qualityLevel;
+
+  private:
+
+    PixelFormat pf_;
+    char* name_;
+    int nEncodings_;
+    rdr::U32* encodings_;
+    int currentEncoding_;
+    char verStr[13];
+    int verStrPos;
+  };
+}
+#endif
diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx
new file mode 100644
index 0000000..c8dc341
--- /dev/null
+++ b/common/rfb/Cursor.cxx
@@ -0,0 +1,179 @@
+/* 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 <string.h>
+#include <rfb/Cursor.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("Cursor");
+
+void Cursor::setSize(int w, int h) {
+  int oldMaskLen = maskLen();
+  ManagedPixelBuffer::setSize(w, h);
+  if (maskLen() > oldMaskLen) {
+    delete [] mask.buf;
+    mask.buf = new rdr::U8[maskLen()];
+  }
+}
+
+void Cursor::drawOutline(const Pixel& c)
+{
+  Cursor outlined;
+
+  // Create a mirror of the existing cursor
+  outlined.setPF(getPF());
+  outlined.setSize(width(), height());
+  outlined.hotspot = hotspot;
+
+  // Clear the mirror's background to the outline colour
+  outlined.fillRect(getRect(), c);
+
+  // Blit the existing cursor, using its mask
+  outlined.maskRect(getRect(), data, mask.buf);
+
+  // Now just adjust the mask to add the outline.  The outline pixels
+  // will already be the right colour. :)
+  int maskBytesPerRow = (width() + 7) / 8;
+  for (int y = 0; y < height(); y++) {
+    for (int byte=0; byte<maskBytesPerRow; byte++) {
+      rdr::U8 m8 = mask.buf[y*maskBytesPerRow + byte];
+
+      // Handle above & below outline
+      if (y > 0) m8 |= mask.buf[(y-1)*maskBytesPerRow + byte];
+      if (y < height()-1) m8 |= mask.buf[(y+1)*maskBytesPerRow + byte];
+
+      // Left outline
+      m8 |= mask.buf[y*maskBytesPerRow + byte] << 1;
+      if (byte < maskBytesPerRow-1)
+        m8 |= (mask.buf[y*maskBytesPerRow + byte + 1] >> 7) & 1;
+
+      // Right outline
+      m8 |= mask.buf[y*maskBytesPerRow + byte] >> 1;
+      if (byte > 0)
+        m8 |= (mask.buf[y*maskBytesPerRow + byte - 1] << 7) & 128;
+
+      outlined.mask.buf[y*maskBytesPerRow + byte] = m8;
+    }
+  }
+
+  // Replace the existing cursor & mask with the new one
+  delete [] data;
+  delete [] mask.buf;
+  data = outlined.data; outlined.data = 0;
+  mask.buf = outlined.mask.buf; outlined.mask.buf = 0;
+}
+
+rdr::U8* Cursor::getBitmap(Pixel* pix0, Pixel* pix1)
+{
+  bool gotPix0 = false;
+  bool gotPix1 = false;
+  *pix0 = *pix1 = 0;
+  rdr::U8Array source(maskLen());
+  memset(source.buf, 0, maskLen());
+
+  int maskBytesPerRow = (width() + 7) / 8;
+  for (int y = 0; y < height(); y++) {
+    for (int x = 0; x < width(); x++) {
+      int byte = y * maskBytesPerRow + x / 8;
+      int bit = 7 - x % 8;
+      if (mask.buf[byte] & (1 << bit)) {
+        Pixel pix=0;
+        switch (getPF().bpp) {
+        case 8:  pix = ((rdr::U8*) data)[y * width() + x]; break;
+        case 16: pix = ((rdr::U16*)data)[y * width() + x]; break;
+        case 32: pix = ((rdr::U32*)data)[y * width() + x]; break;
+        }
+        if (!gotPix0 || pix == *pix0) {
+          gotPix0 = true;
+          *pix0 = pix;
+        } else if (!gotPix1 || pix == *pix1) {
+          gotPix1 = true;
+          *pix1 = pix;
+          source.buf[byte] |= (1 << bit);
+        } else {
+          // not a bitmap
+          return 0;
+        }
+      }
+    }
+  }
+  return source.takeBuf();
+}
+
+// crop() determines the "busy" rectangle for the cursor - the minimum bounding
+// rectangle containing actual pixels.  This isn't the most efficient algorithm
+// but it's short.  For sanity, we make sure that the busy rectangle always
+// includes the hotspot (the hotspot is unsigned on the wire so otherwise it
+// would cause problems if it was above or left of the actual pixels)
+
+void Cursor::crop()
+{
+  Rect busy = getRect().intersect(Rect(hotspot.x, hotspot.y,
+                                       hotspot.x+1, hotspot.y+1));
+  int maskBytesPerRow = (width() + 7) / 8;
+  int x, y;
+  for (y = 0; y < height(); y++) {
+    for (x = 0; x < width(); x++) {
+      int byte = y * maskBytesPerRow + x / 8;
+      int bit = 7 - x % 8;
+      if (mask.buf[byte] & (1 << bit)) {
+        if (x < busy.tl.x) busy.tl.x = x;
+        if (x+1 > busy.br.x) busy.br.x = x+1;
+        if (y < busy.tl.y) busy.tl.y = y;
+        if (y+1 > busy.br.y) busy.br.y = y+1;
+      }
+    }
+  }
+
+  if (width() == busy.width() && height() == busy.height()) return;
+
+  vlog.debug("cropping %dx%d to %dx%d", width(), height(),
+             busy.width(), busy.height());
+
+  // Copy the pixel data
+  int newDataLen = busy.area() * (getPF().bpp/8);
+  rdr::U8* newData = new rdr::U8[newDataLen];
+  getImage(newData, busy);
+
+  // Copy the mask
+  int newMaskBytesPerRow = (busy.width()+7)/8;
+  int newMaskLen = newMaskBytesPerRow * busy.height();
+  rdr::U8* newMask = new rdr::U8[newMaskLen];
+  memset(newMask, 0, newMaskLen);
+  for (y = 0; y < busy.height(); y++) {
+    int newByte, newBit;
+    for (x = 0; x < busy.width(); x++) {
+      int oldByte = (y+busy.tl.y) * maskBytesPerRow + (x+busy.tl.x) / 8;
+      int oldBit = 7 - (x+busy.tl.x) % 8;
+      newByte = y * newMaskBytesPerRow + x / 8;
+      newBit = 7 - x % 8;
+      if (mask.buf[oldByte] & (1 << oldBit))
+        newMask[newByte] |= (1 << newBit);
+    }
+  }
+
+  // Set the size and data to the new, cropped cursor.
+  setSize(busy.width(), busy.height());
+  hotspot = hotspot.subtract(busy.tl);
+  delete [] data;
+  delete [] mask.buf;
+  datasize = newDataLen;
+  data = newData;
+  mask.buf = newMask;
+}
diff --git a/common/rfb/Cursor.h b/common/rfb/Cursor.h
new file mode 100644
index 0000000..7d94d70
--- /dev/null
+++ b/common/rfb/Cursor.h
@@ -0,0 +1,56 @@
+/* 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.
+ */
+//
+// Cursor - structure containing information describing
+//          the current cursor shape
+//
+
+#ifndef __RFB_CURSOR_H__
+#define __RFB_CURSOR_H__
+
+#include <rfb/PixelBuffer.h>
+
+namespace rfb {
+
+  class Cursor : public ManagedPixelBuffer {
+  public:
+    Cursor() {}
+    rdr::U8Array mask;
+    Point hotspot;
+
+    int maskLen() { return (width() + 7) / 8 * height(); }
+
+    // setSize() resizes the cursor.  The contents of the data and mask are
+    // undefined after this call.
+    virtual void setSize(int w, int h);
+
+    // drawOutline() adds an outline to the cursor in the given colour.
+    void drawOutline(const Pixel& c);
+
+    // getBitmap() tests whether the cursor is monochrome, and if so returns a
+    // bitmap together with background and foreground colours.  The size and
+    // layout of the bitmap are the same as the mask.
+    rdr::U8* getBitmap(Pixel* pix0, Pixel* pix1);
+
+    // crop() crops the cursor down to the smallest possible size, based on the
+    // mask.
+    void crop();
+  };
+
+}
+#endif
diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx
new file mode 100644
index 0000000..b6e4fd5
--- /dev/null
+++ b/common/rfb/Decoder.cxx
@@ -0,0 +1,70 @@
+/* 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/Exception.h>
+#include <rfb/Decoder.h>
+#include <rfb/RawDecoder.h>
+#include <rfb/RREDecoder.h>
+#include <rfb/HextileDecoder.h>
+#include <rfb/ZRLEDecoder.h>
+#include <rfb/TightDecoder.h>
+
+using namespace rfb;
+
+Decoder::~Decoder()
+{
+}
+
+DecoderCreateFnType Decoder::createFns[encodingMax+1] = { 0 };
+
+bool Decoder::supported(unsigned int encoding)
+{
+  return encoding <= encodingMax && createFns[encoding];
+}
+
+Decoder* Decoder::createDecoder(unsigned int encoding, CMsgReader* reader)
+{
+  if (encoding <= encodingMax && createFns[encoding])
+    return (*createFns[encoding])(reader);
+  return 0;
+}
+
+void Decoder::registerDecoder(unsigned int encoding,
+                              DecoderCreateFnType createFn)
+{
+  if (encoding > encodingMax)
+    throw Exception("Decoder::registerDecoder: encoding out of range");
+
+  if (createFns[encoding])
+    fprintf(stderr,"Replacing existing decoder for encoding %s (%d)\n",
+            encodingName(encoding), encoding);
+  createFns[encoding] = createFn;
+}
+
+int DecoderInit::count = 0;
+
+DecoderInit::DecoderInit()
+{
+  if (count++ != 0) return;
+
+  Decoder::registerDecoder(encodingRaw, RawDecoder::create);
+  Decoder::registerDecoder(encodingRRE, RREDecoder::create);
+  Decoder::registerDecoder(encodingHextile, HextileDecoder::create);
+  Decoder::registerDecoder(encodingZRLE, ZRLEDecoder::create);
+  Decoder::registerDecoder(encodingTight, TightDecoder::create);
+}
diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h
new file mode 100644
index 0000000..3fdba53
--- /dev/null
+++ b/common/rfb/Decoder.h
@@ -0,0 +1,52 @@
+/* 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_DECODER_H__
+#define __RFB_DECODER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/encodings.h>
+
+namespace rfb {
+  class CMsgReader;
+  class CMsgHandler;
+  class Decoder;
+  typedef Decoder* (*DecoderCreateFnType)(CMsgReader*);
+
+  class Decoder {
+  public:
+    virtual ~Decoder();
+    virtual void readRect(const Rect& r, CMsgHandler* handler)=0;
+
+    static bool supported(unsigned int encoding);
+    static Decoder* createDecoder(unsigned int encoding, CMsgReader* reader);
+    static void registerDecoder(unsigned int encoding,
+                                DecoderCreateFnType createFn);
+  private:
+    static DecoderCreateFnType createFns[encodingMax+1];
+  };
+
+  class DecoderInit {
+    static int count;
+  public:
+    DecoderInit();
+  };
+
+  static DecoderInit decoderInitObj;
+}
+
+#endif
diff --git a/common/rfb/DirManager.h b/common/rfb/DirManager.h
new file mode 100644
index 0000000..c820f64
--- /dev/null
+++ b/common/rfb/DirManager.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- DirManager.cxx
+
+#ifndef __RFB_DIRMANAGER_H__
+#define __RFB_DIRMANAGER_H__
+
+#include <rfb/FileInfo.h>
+
+namespace rfb {
+  class DirManager {
+  public:
+    virtual bool createDir(char *pFullPath) = 0;
+    virtual bool renameIt(char *pOldName, char *pNewName) = 0;
+    virtual bool deleteIt(char *pFullPath) = 0;
+
+    virtual bool getDirInfo(char *pPath, FileInfo *pFileInfo, unsigned int dirOnly) = 0;
+  };
+}
+
+#endif // __RFB_DIRMANAGER_H__
\ No newline at end of file
diff --git a/common/rfb/Encoder.cxx b/common/rfb/Encoder.cxx
new file mode 100644
index 0000000..53cb170
--- /dev/null
+++ b/common/rfb/Encoder.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.
+ */
+#include <stdio.h>
+#include <rfb/Exception.h>
+#include <rfb/Encoder.h>
+#include <rfb/RawEncoder.h>
+#include <rfb/RREEncoder.h>
+#include <rfb/HextileEncoder.h>
+#include <rfb/ZRLEEncoder.h>
+#include <rfb/TightEncoder.h>
+
+using namespace rfb;
+
+Encoder::~Encoder()
+{
+}
+
+EncoderCreateFnType Encoder::createFns[encodingMax+1] = { 0 };
+
+bool Encoder::supported(unsigned int encoding)
+{
+  return encoding <= encodingMax && createFns[encoding];
+}
+
+Encoder* Encoder::createEncoder(unsigned int encoding, SMsgWriter* writer)
+{
+  if (encoding <= encodingMax && createFns[encoding])
+    return (*createFns[encoding])(writer);
+  return 0;
+}
+
+void Encoder::registerEncoder(unsigned int encoding,
+                              EncoderCreateFnType createFn)
+{
+  if (encoding > encodingMax)
+    throw Exception("Encoder::registerEncoder: encoding out of range");
+
+  if (createFns[encoding])
+    fprintf(stderr,"Replacing existing encoder for encoding %s (%d)\n",
+            encodingName(encoding), encoding);
+  createFns[encoding] = createFn;
+}
+
+void Encoder::unregisterEncoder(unsigned int encoding)
+{
+  if (encoding > encodingMax)
+    throw Exception("Encoder::unregisterEncoder: encoding out of range");
+  createFns[encoding] = 0;
+}
+
+int EncoderInit::count = 0;
+
+EncoderInit::EncoderInit()
+{
+  if (count++ != 0) return;
+
+  Encoder::registerEncoder(encodingRaw, RawEncoder::create);
+  Encoder::registerEncoder(encodingRRE, RREEncoder::create);
+  Encoder::registerEncoder(encodingHextile, HextileEncoder::create);
+  Encoder::registerEncoder(encodingZRLE, ZRLEEncoder::create);
+  Encoder::registerEncoder(encodingTight, TightEncoder::create);
+}
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h
new file mode 100644
index 0000000..df50dd6
--- /dev/null
+++ b/common/rfb/Encoder.h
@@ -0,0 +1,61 @@
+/* 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_ENCODER_H__
+#define __RFB_ENCODER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/encodings.h>
+
+namespace rfb {
+  class SMsgWriter;
+  class Encoder;
+  class ImageGetter;
+  typedef Encoder* (*EncoderCreateFnType)(SMsgWriter*);
+
+  class Encoder {
+  public:
+    virtual ~Encoder();
+
+    virtual void setCompressLevel(int level) {};
+    virtual void setQualityLevel(int level) {};
+    virtual int getNumRects(const Rect &r) { return 1; }
+
+    // writeRect() tries to write the given rectangle.  If it is unable to
+    // write the whole rectangle it returns false and sets actual to the actual
+    // rectangle which was updated.
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual)=0;
+
+    static bool supported(unsigned int encoding);
+    static Encoder* createEncoder(unsigned int encoding, SMsgWriter* writer);
+    static void registerEncoder(unsigned int encoding,
+                                EncoderCreateFnType createFn);
+    static void unregisterEncoder(unsigned int encoding);
+  private:
+    static EncoderCreateFnType createFns[encodingMax+1];
+  };
+
+  class EncoderInit {
+    static int count;
+  public:
+    EncoderInit();
+  };
+
+  static EncoderInit encoderInitObj;
+}
+
+#endif
diff --git a/common/rfb/Exception.h b/common/rfb/Exception.h
new file mode 100644
index 0000000..7c2cbca
--- /dev/null
+++ b/common/rfb/Exception.h
@@ -0,0 +1,37 @@
+/* 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_EXCEPTION_H__
+#define __RFB_EXCEPTION_H__
+
+#include <rdr/Exception.h>
+
+namespace rfb {
+  typedef rdr::Exception Exception;
+  struct AuthFailureException : public Exception {
+    AuthFailureException(const char* s="Authentication failure")
+      : Exception(s) {}
+  };
+  struct AuthCancelledException : public rfb::Exception {
+    AuthCancelledException(const char* s="Authentication cancelled")
+      : Exception(s) {}
+  };
+  struct ConnFailedException : public Exception {
+    ConnFailedException(const char* s="Connection failed") : Exception(s) {}
+  };
+}
+#endif
diff --git a/common/rfb/FileInfo.cxx b/common/rfb/FileInfo.cxx
new file mode 100644
index 0000000..e97e0ad
--- /dev/null
+++ b/common/rfb/FileInfo.cxx
@@ -0,0 +1,244 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+#include <rfb/FileInfo.h>
+#include <rfb/util.h>
+
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
+using namespace rfb;
+
+// FIXME: Under Unix, file names are case-sensitive.
+
+int 
+CompareFileInfo(const void *F, const void *S)
+{
+  FILEINFO *pF = (FILEINFO *) F;
+  FILEINFO *pS = (FILEINFO *) S;
+  if (pF->info.flags == pS->info.flags) {
+    return strcasecmp(pF->name, pS->name);
+  } else {
+	if (pF->info.flags == FT_ATTR_DIR) return -1;
+	if (pS->info.flags == FT_ATTR_DIR)
+      return 1;
+	else
+      return strcasecmp(pF->name, pS->name);
+  }
+  
+  return 0;
+}
+
+FileInfo::FileInfo()
+{
+  m_numEntries = 0;
+  m_pEntries = NULL;
+}
+
+FileInfo::~FileInfo()
+{
+  free();
+}
+
+void 
+FileInfo::add(FileInfo *pFI)
+{
+  m_numEntries = pFI->getNumEntries();
+  FILEINFO *pTemporary = new FILEINFO[m_numEntries];
+  memcpy(pTemporary, pFI->getNameAt(0), m_numEntries * sizeof(FILEINFO));
+  
+  m_pEntries = pTemporary;
+  pTemporary = NULL;
+}
+
+void 
+FileInfo::add(FILEINFO *pFIStruct)
+{
+  add(pFIStruct->name, pFIStruct->info.size, pFIStruct->info.data, pFIStruct->info.flags);
+}
+
+void 
+FileInfo::add(char *pName, unsigned int size, unsigned int data, unsigned int flags)
+{
+  FILEINFO *pTemporary = new FILEINFO[m_numEntries + 1];
+  if (m_numEntries != 0) 
+    memcpy(pTemporary, m_pEntries, m_numEntries * sizeof(FILEINFO));
+  strcpy(pTemporary[m_numEntries].name, pName);
+  pTemporary[m_numEntries].info.size = size;
+  pTemporary[m_numEntries].info.data = data;
+  pTemporary[m_numEntries].info.flags = flags;
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  m_pEntries = pTemporary;
+  pTemporary = NULL;
+  m_numEntries++;
+}
+
+char *
+FileInfo::getNameAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].name;
+  }
+  return NULL;
+}
+
+bool 
+FileInfo::setNameAt(unsigned int number, char *pName)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    strcpy(m_pEntries[number].name, pName);
+    return true;
+  }
+  return false;
+}
+
+unsigned int
+FileInfo::getSizeAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].info.size;
+  }
+  return 0;
+}
+
+unsigned int
+FileInfo::getDataAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].info.data;
+  }
+  return 0;
+}
+
+unsigned int
+FileInfo::getFlagsAt(unsigned int number)
+{
+	if ((number >= 0) && (number < m_numEntries)) {
+		return m_pEntries[number].info.flags;
+	}
+	return 0;
+}
+
+FILEINFO * 
+FileInfo::getFullDataAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return &m_pEntries[number];
+  }
+  return NULL;
+}
+	
+bool 
+FileInfo::setSizeAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.size = value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+FileInfo::setDataAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.data = value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+FileInfo::setFlagsAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.flags = value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+FileInfo::deleteAt(unsigned int number)
+{
+  if ((number >= m_numEntries) || (number < 0)) return false;
+  
+  FILEINFO *pTemporary = new FILEINFO[m_numEntries - 1];
+  
+  if (number == 0) {
+    memcpy(pTemporary, &m_pEntries[1], (m_numEntries - 1) * sizeof(FILEINFO));
+  } else {
+    memcpy(pTemporary, m_pEntries, number * sizeof(FILEINFO));
+    if (number != (m_numEntries - 1)) 
+      memcpy(&pTemporary[number], &m_pEntries[number + 1], (m_numEntries - number - 1) * sizeof(FILEINFO));
+  }
+  
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  m_pEntries = pTemporary;
+  pTemporary = NULL;
+  m_numEntries--;
+  return true;
+}
+
+unsigned int 
+FileInfo::getNumEntries()
+{
+  return m_numEntries;
+}
+
+void 
+FileInfo::sort()
+{
+  qsort(m_pEntries, m_numEntries, sizeof(FILEINFO), CompareFileInfo);
+}
+
+void 
+FileInfo::free()
+{
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  m_numEntries = 0;
+}
+
+unsigned int
+FileInfo::getFilenamesSize()
+{
+  if (getNumEntries() == 0) return 0;
+
+  unsigned int filenamesSize = 0;
+
+  for (unsigned int i = 0; i < getNumEntries(); i++) {
+    filenamesSize += strlen(getNameAt(i));
+  }
+
+  return filenamesSize;
+}
diff --git a/common/rfb/FileInfo.h b/common/rfb/FileInfo.h
new file mode 100644
index 0000000..270eeee
--- /dev/null
+++ b/common/rfb/FileInfo.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileInfo.
+
+#ifndef __RFB_FILEINFO_H__
+#define __RFB_FILEINFO_H__
+
+#include <stdlib.h>
+
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class FileInfo  
+  {
+  public:
+    void add(FileInfo *pFI);
+    void add(FILEINFO *pFIStruct);
+    void add(char *pName, unsigned int size, unsigned int data, unsigned int flags);
+    
+    char *getNameAt(unsigned int number);
+    
+    bool setNameAt(unsigned int number, char *pName);
+    
+    unsigned int getSizeAt(unsigned int number);
+    unsigned int getDataAt(unsigned int number);
+    unsigned int getFlagsAt(unsigned int number);
+    
+    FILEINFO *getFullDataAt(unsigned int number);
+    
+    bool setSizeAt(unsigned int number, unsigned int value);
+    bool setDataAt(unsigned int number, unsigned int value);
+    bool setFlagsAt(unsigned int number, unsigned int value);
+    
+    bool deleteAt(unsigned int number);
+    
+    unsigned int getNumEntries();
+
+    unsigned int getFilenamesSize();
+    
+    void sort();
+    void free();
+    
+    FileInfo();
+    ~FileInfo();
+    
+  private:
+    FILEINFO *m_pEntries;
+    unsigned int m_numEntries;
+
+  };
+}
+
+#endif // __RFB_FILEINFO_H__
diff --git a/common/rfb/FileManager.cxx b/common/rfb/FileManager.cxx
new file mode 100644
index 0000000..74cbd45
--- /dev/null
+++ b/common/rfb/FileManager.cxx
@@ -0,0 +1,81 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileManager.cxx
+
+#include <rfb/FileManager.h>
+
+using namespace rfb;
+
+FileManager::FileManager()
+{
+  m_pFile = NULL;
+}
+
+FileManager::~FileManager()
+{
+  close();
+}
+
+bool 
+FileManager::create(char *pFilename)
+{
+  if (m_pFile != NULL) return false;
+  
+  strcpy(m_szFilename, pFilename);
+
+  m_pFile = fopen(m_szFilename, m_szMode);
+
+  if (m_pFile == NULL) {
+    return false;
+  } else {
+    return true;
+  }
+}
+
+bool 
+FileManager::close()
+{
+  if (m_pFile == NULL) return false;
+  
+  int result = fclose(m_pFile);
+  
+  if (result != 0) {
+    return false;
+  } else {
+    m_pFile = NULL;
+    return true;
+  }
+}
+
+bool 
+FileManager::isCreated()
+{
+  if (m_pFile != NULL) return true; else return false;
+}
+
+char *
+FileManager::getFilename()
+{
+  return m_szFilename;
+}
diff --git a/common/rfb/FileManager.h b/common/rfb/FileManager.h
new file mode 100644
index 0000000..4fd736f
--- /dev/null
+++ b/common/rfb/FileManager.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileManager.
+
+#ifndef __RFB_FILEMANAGER_H__
+#define __RFB_FILEMANAGER_H__
+
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class FileManager {
+  public:
+    FileManager();
+    ~FileManager();
+    
+    bool create(char *pFilename);
+    bool close();
+    
+    bool isCreated();
+
+    char *getFilename();
+
+  protected:
+    FILE *m_pFile;
+    char m_szMode[4];
+    char m_szFilename[FT_FILENAME_SIZE];
+  };
+}
+#endif // __RFB_FILEMANAGER_H__
diff --git a/common/rfb/FileReader.cxx b/common/rfb/FileReader.cxx
new file mode 100644
index 0000000..a8cd272
--- /dev/null
+++ b/common/rfb/FileReader.cxx
@@ -0,0 +1,51 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileReader.cxx
+
+#include <rfb/FileReader.h>
+
+using namespace rfb;
+
+FileReader::FileReader()
+{
+  strcpy(m_szMode, "rb");
+}
+
+bool 
+FileReader::read(void *pBuf, unsigned int count, unsigned int *pBytesRead)
+{
+  if (!isCreated()) return false;
+
+  *pBytesRead = fread(pBuf, 1, count, m_pFile);
+  
+  if (ferror(m_pFile)) return false;
+ 
+  return true;
+}
+
+unsigned int 
+FileReader::getTime()
+{
+  return 0;
+}
diff --git a/common/rfb/FileReader.h b/common/rfb/FileReader.h
new file mode 100644
index 0000000..0c985d8
--- /dev/null
+++ b/common/rfb/FileReader.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileReader.h
+
+#ifndef __RFB_FILEREADER_H__
+#define __RFB_FILEREADER_H__
+
+#include <rfb/FileManager.h>
+
+namespace rfb {
+  class FileReader : public FileManager {
+  public:
+    FileReader();
+
+    bool read(void *pBuf, unsigned int count, unsigned int *pBytesRead);
+
+    unsigned int getTime();
+  };
+}
+#endif // __RFB_FILEREADER_H__
diff --git a/common/rfb/FileWriter.cxx b/common/rfb/FileWriter.cxx
new file mode 100644
index 0000000..2bed576
--- /dev/null
+++ b/common/rfb/FileWriter.cxx
@@ -0,0 +1,52 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileWriter.cxx
+
+#include <rfb/FileWriter.h>
+
+using namespace rfb;
+
+FileWriter::FileWriter()
+{
+  strcpy(m_szMode, "wb");
+}
+
+bool 
+FileWriter::write(const void *pBuf, unsigned int count, unsigned int *pBytesWritten)
+{
+  if (!isCreated()) return false;
+
+  unsigned int bytesWritten = fwrite(pBuf, 1, count, m_pFile);
+
+  if (ferror(m_pFile)) return false;
+
+  *pBytesWritten = bytesWritten;
+  return true;
+}
+
+bool 
+FileWriter::setTime(unsigned int modTime)
+{
+  return false;
+}
diff --git a/common/rfb/FileWriter.h b/common/rfb/FileWriter.h
new file mode 100644
index 0000000..73094a7
--- /dev/null
+++ b/common/rfb/FileWriter.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileWriter.h
+
+#ifndef __RFB_FILEWRITER_H__
+#define __RFB_FILEWRITER_H__
+
+#include <rfb/FileManager.h>
+
+namespace rfb {
+  class FileWriter : public FileManager {
+  public:
+    FileWriter();
+
+    bool write(const void *pBuf, unsigned int count, unsigned int *pBytesWritten);
+    bool setTime(unsigned int modTime);
+  };
+}
+
+#endif // __RFB_FILEWRITER_H__
diff --git a/common/rfb/HTTPServer.cxx b/common/rfb/HTTPServer.cxx
new file mode 100644
index 0000000..e40d480
--- /dev/null
+++ b/common/rfb/HTTPServer.cxx
@@ -0,0 +1,411 @@
+/* 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 <rfb/HTTPServer.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rdr/MemOutStream.h>
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+
+using namespace rfb;
+using namespace rdr;
+
+static LogWriter vlog("HTTPServer");
+
+const int clientWaitTimeMillis = 20000;
+const int idleTimeoutSecs = 5 * 60;
+
+
+//
+// -=- LineReader
+//     Helper class which is repeatedly called until a line has been read
+//     (lines end in \n or \r\n).
+//     Returns true when line complete, and resets internal state so that
+//     next read() call will start reading a new line.
+//     Only one buffer is kept - process line before reading next line!
+//
+
+class LineReader : public CharArray {
+public:
+  LineReader(InStream& is_, int l)
+    : CharArray(l), is(is_), pos(0), len(l), bufferOverrun(false) {}
+
+  // Returns true if line complete, false otherwise
+  bool read() {
+    while (is.checkNoWait(1)) {
+      char c = is.readU8();
+
+      if (c == '\n') {
+        if (pos && (buf[pos-1] == '\r'))
+          pos--;
+        bufferOverrun = false;
+        buf[pos++] = 0;
+        pos = 0;
+        return true;
+      }
+
+      if (pos == (len-1)) {
+        bufferOverrun = true;
+        buf[pos] = 0;
+        return true;
+      }
+
+      buf[pos++] = c;
+    }
+
+    return false;
+  }
+  bool didBufferOverrun() const {return bufferOverrun;}
+protected:
+  InStream& is;
+  int pos, len;
+  bool bufferOverrun;
+};
+
+
+//
+// -=- HTTPServer::Session
+//     Manages the internal state for an HTTP session.
+//     processHTTP returns true when request has completed,
+//     indicating that socket & session data can be deleted.
+//
+
+class rfb::HTTPServer::Session {
+public:
+  Session(network::Socket& s, rfb::HTTPServer& srv)
+    : contentType(0), contentLength(-1), lastModified(-1),
+      line(s.inStream(), 256), sock(s),
+      server(srv), state(ReadRequestLine), lastActive(time(0)) {
+  }
+  ~Session() {
+  }
+
+  void writeResponse(int result, const char* text);
+  bool writeResponse(int code);
+
+  bool processHTTP();
+
+  network::Socket* getSock() const {return &sock;}
+
+  int checkIdleTimeout();
+protected:
+  CharArray uri;
+  const char* contentType;
+  int contentLength;
+  time_t lastModified;
+  LineReader line;
+  network::Socket& sock;
+  rfb::HTTPServer& server;
+  enum {ReadRequestLine, ReadHeaders, WriteResponse} state;
+  enum {GetRequest, HeadRequest} request;
+  time_t lastActive;
+};
+
+
+// - Internal helper routines
+
+void
+copyStream(InStream& is, OutStream& os) {
+  try {
+    while (1) {
+      os.writeU8(is.readU8());
+    }
+  } catch (rdr::EndOfStream) {
+  }
+}
+
+void writeLine(OutStream& os, const char* text) {
+  os.writeBytes(text, strlen(text));
+  os.writeBytes("\r\n", 2);
+}
+
+
+// - Write an HTTP-compliant response to the client
+
+
+void
+HTTPServer::Session::writeResponse(int result, const char* text) {
+  char buffer[1024];
+  if (strlen(text) > 512)
+    throw new rdr::Exception("Internal error - HTTP response text too big");
+  sprintf(buffer, "%s %d %s", "HTTP/1.1", result, text);
+  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) {
+    if (!contentType)
+      contentType = guessContentType(uri.buf, "text/html");
+    os.writeBytes(contentType, strlen(contentType));
+  } else {
+    os.writeBytes("text/html", 9);
+  }
+  os.writeBytes("\r\n", 2);
+  writeLine(os, "");
+  if (result != 200) {
+    writeLine(os, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">");
+    writeLine(os, "<HTML><HEAD>");
+    sprintf(buffer, "<TITLE>%d %s</TITLE>", result, text);
+    writeLine(os, buffer);
+    writeLine(os, "</HEAD><BODY><H1>");
+    writeLine(os, text);
+    writeLine(os, "</H1></BODY></HTML>");
+    sock.outStream().flush();
+  }
+}
+
+bool
+HTTPServer::Session::writeResponse(int code) {
+  switch (code) {
+  case 200: writeResponse(code, "OK"); break;
+  case 400: writeResponse(code, "Bad Request"); break;
+  case 404: writeResponse(code, "Not Found"); break;
+  case 501: writeResponse(code, "Not Implemented"); break;
+  default: writeResponse(500, "Unknown Error"); break;
+  };
+
+  // This return code is passed straight out of processHTTP().
+  // true indicates that the request has been completely processed.
+  return true;
+}
+
+// - Main HTTP request processing routine
+
+bool
+HTTPServer::Session::processHTTP() {
+  lastActive = time(0);
+
+  while (sock.inStream().checkNoWait(1)) {
+
+    switch (state) {
+
+      // Reading the Request-Line
+    case ReadRequestLine:
+
+      // Either read a line, or run out of incoming data
+      if (!line.read())
+        return false;
+
+      // We have read a line!  Skip it if it's blank
+      if (strlen(line.buf) == 0)
+        continue;
+
+      // The line contains a request to process.
+      {
+        char method[16], path[128], version[16];
+        int matched = sscanf(line.buf, "%15s%127s%15s",
+          method, path, version);
+        if (matched != 3)
+          return writeResponse(400);
+
+        // Store the required "method"
+        if (strcmp(method, "GET") == 0)
+          request = GetRequest;
+        else if (strcmp(method, "HEAD") == 0)
+          request = HeadRequest;
+        else
+          return writeResponse(501);
+
+        // Store the URI to the "document"
+        uri.buf = strDup(path);
+      }
+
+      // Move on to reading the request headers
+      state = ReadHeaders;
+      break;
+
+      // Reading the request headers
+    case ReadHeaders:
+
+      // Try to read a line
+      if (!line.read())
+        return false;
+
+      // Skip headers until we hit a blank line
+      if (strlen(line.buf) != 0)
+        continue;
+
+      // Headers ended - write the response!
+      {
+        CharArray address(sock.getPeerAddress());
+        vlog.info("getting %s for %s", uri.buf, address.buf);
+        contentLength = -1;
+        lastModified = -1;
+        InStream* data = server.getFile(uri.buf, &contentType, &contentLength,
+                                        &lastModified);
+        if (!data)
+          return writeResponse(404);
+
+        try {
+          writeResponse(200);
+          if (request == GetRequest)
+            copyStream(*data, sock.outStream());
+          sock.outStream().flush();
+        } catch (rdr::Exception& e) {
+          vlog.error("error writing HTTP document:%s", e.str());
+        }
+        delete data;
+      }
+
+      // The operation is complete!
+      return true;
+
+    default:
+      throw rdr::Exception("invalid HTTPSession state!");
+    };
+
+  }
+
+  // Indicate that we're still processing the HTTP request.
+  return false;
+}
+
+int HTTPServer::Session::checkIdleTimeout() {
+  time_t now = time(0);
+  int timeout = (lastActive + idleTimeoutSecs) - now;
+  if (timeout > 0)
+    return secsToMillis(timeout);
+  sock.shutdown();
+  return 0;
+}
+
+// -=- Constructor / destructor
+
+HTTPServer::HTTPServer() {
+}
+
+HTTPServer::~HTTPServer() {
+  std::list<Session*>::iterator i;
+  for (i=sessions.begin(); i!=sessions.end(); i++)
+    delete *i;
+}
+
+
+// -=- SocketServer interface implementation
+
+void
+HTTPServer::addSocket(network::Socket* sock, bool) {
+  Session* s = new Session(*sock, *this);
+  if (!s) {
+    sock->shutdown();
+  } else {
+    sock->inStream().setTimeout(clientWaitTimeMillis);
+    sock->outStream().setTimeout(clientWaitTimeMillis);
+    sessions.push_front(s);
+  }
+}
+
+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++) {
+    if ((*i)->getSock() == sock) {
+      try {
+        if ((*i)->processHTTP()) {
+          vlog.info("completed HTTP request");
+          sock->shutdown();
+        }
+      } catch (rdr::Exception& e) {
+        vlog.error("untrapped: %s", e.str());
+        sock->shutdown();
+      }
+      return;
+    }
+  }
+  throw rdr::Exception("invalid Socket in HTTPServer");
+}
+
+void HTTPServer::getSockets(std::list<network::Socket*>* sockets)
+{
+  sockets->clear();
+  std::list<Session*>::iterator ci;
+  for (ci = sessions.begin(); ci != sessions.end(); ci++) {
+    sockets->push_back((*ci)->getSock());
+  }
+}
+
+int HTTPServer::checkTimeouts() {
+  std::list<Session*>::iterator ci;
+  int timeout = 0;
+  for (ci = sessions.begin(); ci != sessions.end(); ci++) {
+    soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
+  }
+  return timeout;
+}
+
+
+// -=- Default getFile implementation
+
+InStream*
+HTTPServer::getFile(const char* name, const char** contentType,
+                    int* contentLength, time_t* lastModified)
+{
+  return 0;
+}
+
+const char*
+HTTPServer::guessContentType(const char* name, const char* defType) {
+  CharArray file, ext;
+  if (!strSplit(name, '.', &file.buf, &ext.buf))
+    return defType;
+  if (strcasecmp(ext.buf, "html") == 0 ||
+    strcasecmp(ext.buf, "htm") == 0) {
+    return "text/html";
+  } else if (strcasecmp(ext.buf, "txt") == 0) {
+    return "text/plain";
+  } else if (strcasecmp(ext.buf, "gif") == 0) {
+    return "image/gif";
+  } else if (strcasecmp(ext.buf, "jpg") == 0) {
+    return "image/jpeg";
+  } else if (strcasecmp(ext.buf, "jar") == 0) {
+    return "application/java-archive";
+  } else if (strcasecmp(ext.buf, "exe") == 0) {
+    return "application/octet-stream";
+  }
+  return defType;
+}
diff --git a/common/rfb/HTTPServer.h b/common/rfb/HTTPServer.h
new file mode 100644
index 0000000..6412946
--- /dev/null
+++ b/common/rfb/HTTPServer.h
@@ -0,0 +1,110 @@
+/* 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.
+ */
+
+// -=- HTTPServer.h
+
+// Single-threaded HTTP server implementation.
+// All I/O is handled by the processSocketEvent routine,
+// which is called by the main-loop of the VNC server whenever
+// there is an event on an HTTP socket.
+
+#ifndef __RFB_HTTP_SERVER_H__
+#define __RFB_HTTP_SERVER_H__
+
+#include <list>
+
+#include <rdr/MemInStream.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/Configuration.h>
+#include <network/Socket.h>
+#include <time.h>
+
+namespace rfb {
+
+  class HTTPServer : public network::SocketServer {
+  public:
+    // -=- Constructors
+
+    // - HTTPServer(files)
+    //   Create an HTTP server which will use the getFile method
+    //   to satisfy HTTP GET requests.
+    HTTPServer();
+
+    virtual ~HTTPServer();
+
+    // SocketServer interface
+
+    // addSocket()
+    //   This causes the server to perform HTTP protocol on the
+    //   supplied socket.
+    virtual void addSocket(network::Socket* sock, bool outgoing=false);
+
+    // removeSocket()
+    //   Could clean up socket-specific resources here.
+    virtual void removeSocket(network::Socket* sock);
+
+    // processSocketEvent()
+    //   The platform-specific side of the server implementation calls
+    //   this method whenever data arrives on one of the active
+    //   network sockets.
+    virtual void processSocketEvent(network::Socket* sock);
+
+    // 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().
+
+    virtual void getSockets(std::list<network::Socket*>* sockets);
+
+
+    // -=- File interface
+
+    // - getFile is passed the path portion of a URL and returns an
+    //   InStream containing the data to return.  If the requested
+    //   file is available then the contentType should be set to the
+    //   type of the file, or left untouched if the file type is to
+    //   be determined automatically by HTTPServer.
+    //   If the file is not available then null is returned.
+    //   Overridden getFile functions should call the default version
+    //   if they do not recognise a path name.
+    //   NB: The caller assumes ownership of the returned InStream.
+    //   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,
+                                   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.
+
+    static const char* guessContentType(const char* name, const char* defType);
+
+  protected:
+    class Session;
+    std::list<Session*> sessions;
+  };
+}
+
+#endif
+
diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx
new file mode 100644
index 0000000..e817c73
--- /dev/null
+++ b/common/rfb/HextileDecoder.cxx
@@ -0,0 +1,59 @@
+/* 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 <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/HextileDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/hextileDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/hextileDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/hextileDecode.h>
+#undef BPP
+
+Decoder* HextileDecoder::create(CMsgReader* reader)
+{
+  return new HextileDecoder(reader);
+}
+
+HextileDecoder::HextileDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+HextileDecoder::~HextileDecoder()
+{
+}
+
+void HextileDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+  rdr::InStream* is = reader->getInStream();
+  rdr::U8* buf = reader->getImageBuf(16 * 16 * 4);
+  switch (reader->bpp()) {
+  case 8:  hextileDecode8 (r, is, (rdr::U8*) buf, handler); break;
+  case 16: hextileDecode16(r, is, (rdr::U16*)buf, handler); break;
+  case 32: hextileDecode32(r, is, (rdr::U32*)buf, handler); break;
+  }
+}
diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h
new file mode 100644
index 0000000..e7dd3d5
--- /dev/null
+++ b/common/rfb/HextileDecoder.h
@@ -0,0 +1,35 @@
+/* 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_HEXTILEDECODER_H__
+#define __RFB_HEXTILEDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+  class HextileDecoder : public Decoder {
+  public:
+    static Decoder* create(CMsgReader* reader);
+    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual ~HextileDecoder();
+  private:
+    HextileDecoder(CMsgReader* reader);
+    CMsgReader* reader;
+  };
+}
+#endif
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
new file mode 100644
index 0000000..ba71d56
--- /dev/null
+++ b/common/rfb/HextileEncoder.cxx
@@ -0,0 +1,90 @@
+/* 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
+ * (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 <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/HextileEncoder.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+BoolParameter improvedHextile("ImprovedHextile",
+                              "Use improved compression algorithm for Hextile "
+                              "encoding which achieves better compression "
+                              "ratios by the cost of using more CPU time",
+                              true);
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+#define BPP 16
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+#define BPP 32
+#include <rfb/hextileEncode.h>
+#include <rfb/hextileEncodeBetter.h>
+#undef BPP
+
+Encoder* HextileEncoder::create(SMsgWriter* writer)
+{
+  return new HextileEncoder(writer);
+}
+
+HextileEncoder::HextileEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+HextileEncoder::~HextileEncoder()
+{
+}
+
+bool HextileEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  writer->startRect(r, encodingHextile);
+  rdr::OutStream* os = writer->getOutStream();
+  switch (writer->bpp()) {
+  case 8:
+    if (improvedHextile) {
+      hextileEncodeBetter8(r, os, ig);
+    } else {
+      hextileEncode8(r, os, ig);
+    }
+    break;
+  case 16:
+    if (improvedHextile) {
+      hextileEncodeBetter16(r, os, ig);
+    } else {
+      hextileEncode16(r, os, ig);
+    }
+    break;
+  case 32:
+    if (improvedHextile) {
+      hextileEncodeBetter32(r, os, ig);
+    } else {
+      hextileEncode32(r, os, ig);
+    }
+    break;
+  }
+  writer->endRect();
+  return true;
+}
diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h
new file mode 100644
index 0000000..c78107a
--- /dev/null
+++ b/common/rfb/HextileEncoder.h
@@ -0,0 +1,35 @@
+/* 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_HEXTILEENCODER_H__
+#define __RFB_HEXTILEENCODER_H__
+
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+  class HextileEncoder : public Encoder {
+  public:
+    static Encoder* create(SMsgWriter* writer);
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual ~HextileEncoder();
+  private:
+    HextileEncoder(SMsgWriter* writer);
+    SMsgWriter* writer;
+  };
+}
+#endif
diff --git a/common/rfb/Hostname.h b/common/rfb/Hostname.h
new file mode 100644
index 0000000..ebdf816
--- /dev/null
+++ b/common/rfb/Hostname.h
@@ -0,0 +1,55 @@
+/* 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_HOSTNAME_H__
+#define __RFB_HOSTNAME_H__
+
+#include <stdlib.h>
+#include <rdr/Exception.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  static void getHostAndPort(const char* hi, char** host, int* port, int basePort=5900) {
+    CharArray portBuf;
+    CharArray hostBuf;
+    if (hi[0] == '[') {
+      if (!strSplit(&hi[1], ']', &hostBuf.buf, &portBuf.buf))
+        throw rdr::Exception("unmatched [ in host");
+    } else {
+      portBuf.buf = strDup(hi);
+    }
+    if (strSplit(portBuf.buf, ':', hostBuf.buf ? 0 : &hostBuf.buf, &portBuf.buf)) {
+      if (portBuf.buf[0] == ':') {
+        *port = atoi(&portBuf.buf[1]);
+      } else {
+        *port = atoi(portBuf.buf);
+        if (*port < 100) *port += basePort;
+      }
+    } else {
+      *port = basePort;
+    }
+    if (strlen(hostBuf.buf) == 0)
+      *host = strDup("localhost");
+    else
+      *host = hostBuf.takeBuf();
+  }
+
+};
+
+#endif // __RFB_HOSTNAME_H__
diff --git a/common/rfb/ImageGetter.h b/common/rfb/ImageGetter.h
new file mode 100644
index 0000000..290249f
--- /dev/null
+++ b/common/rfb/ImageGetter.h
@@ -0,0 +1,30 @@
+/* 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_IMAGEGETTER_H__
+#define __RFB_IMAGEGETTER_H__
+
+#include <rfb/Rect.h>
+
+namespace rfb {
+  class ImageGetter {
+  public:
+    virtual void getImage(void* imageBuf,
+                          const Rect& r, int stride=0) = 0;
+  };
+}
+#endif
diff --git a/common/rfb/InputHandler.h b/common/rfb/InputHandler.h
new file mode 100644
index 0000000..b5e5e87
--- /dev/null
+++ b/common/rfb/InputHandler.h
@@ -0,0 +1,40 @@
+/* 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.
+ */
+//
+// 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 {
+
+  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) {}
+  };
+
+}
+#endif
diff --git a/common/rfb/KeyRemapper.cxx b/common/rfb/KeyRemapper.cxx
new file mode 100644
index 0000000..05f0763
--- /dev/null
+++ b/common/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/common/rfb/KeyRemapper.h b/common/rfb/KeyRemapper.h
new file mode 100644
index 0000000..a4b7aa0
--- /dev/null
+++ b/common/rfb/KeyRemapper.h
@@ -0,0 +1,39 @@
+/* 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_KEYREMAPPER_H__
+#define __RFB_KEYREMAPPER_H__
+
+#include <map>
+#include <rdr/types.h>
+
+namespace rfb {
+
+  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;
+  };
+
+};
+
+#endif // __RFB_KEYREMAPPER_H__
diff --git a/common/rfb/ListConnInfo.h b/common/rfb/ListConnInfo.h
new file mode 100644
index 0000000..cabcbc7
--- /dev/null
+++ b/common/rfb/ListConnInfo.h
@@ -0,0 +1,122 @@
+/* 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.
+ */
+
+
+#ifndef __RFB_LISTCONNINFO_INCLUDED__
+#define __RFB_LISTCONNINFO_INCLUDED__
+
+namespace rfb {
+
+  struct ListConnInfo  {
+    ListConnInfo() : disableClients(false) {}
+
+    void Clear() {
+      conn.clear();
+      IP_address.clear();
+      time_conn.clear();
+      status.clear();
+    }
+
+    bool Empty() { return conn.empty();}
+
+    void iBegin() {
+      ci = conn.begin();
+      Ii = IP_address.begin();
+      ti = time_conn.begin();
+      si = status.begin();
+    }
+
+    bool iEnd() { return ci == conn.end();}
+
+    void iNext() {
+      ci++;
+      Ii++;
+      ti++;
+      si++;
+    }
+
+    void addInfo(void* Conn, char* IP, char* Time, int Status) {
+      conn.push_back(Conn);
+      IP_address.push_back(strDup(IP));
+      time_conn.push_back(strDup(Time));
+      status.push_back(Status);
+    }
+
+    void iGetCharInfo(char* buf[3]) {
+      buf[0] = *Ii;
+      buf[1] = *ti;
+      switch (*si) {
+      case 0:
+        buf[2] = strDup("Full control");
+        break;
+      case 1:
+        buf[2] = strDup("View only");
+        break;
+      case 2:
+        buf[2] = strDup("Stop updating");
+        break;
+      default:
+        buf[2] = strDup("Unknown");
+      }
+    }
+
+    void* iGetConn() { return *ci;}
+
+    int iGetStatus() { return *si;}
+
+    void iSetStatus( int status) { *si = status;}
+
+    void Copy(ListConnInfo* InputList) {
+      Clear();
+      if (InputList->Empty()) return;
+      for (InputList->iBegin(); !InputList->iEnd(); InputList->iNext()) {
+        iAdd(InputList);
+      }
+      setDisable(InputList->getDisable());
+    }
+
+    void iAdd (ListConnInfo* InputList) {
+      char* buf[3];
+      InputList->iGetCharInfo(buf);
+      addInfo(InputList->iGetConn(), buf[0], buf[1], InputList->iGetStatus());
+    }
+
+    void setDisable(bool disable) {disableClients = disable;}
+
+    bool getDisable() {return disableClients;}
+
+    void setAllStatus(int stat) {
+      std::list<int>::iterator st;
+      for (st = status.begin(); st != status.end(); st++)
+        *st = stat;
+    }
+
+  private:
+    std::list<void*> conn;
+    std::list<char*> IP_address;
+    std::list<char*> time_conn;
+    std::list<int> status;
+    std::list<void*>::iterator ci;
+    std::list<char*>::iterator Ii;
+    std::list<char*>::iterator ti;
+    std::list<int>::iterator si;
+    bool disableClients;
+  };
+};
+#endif
+
diff --git a/common/rfb/LogWriter.cxx b/common/rfb/LogWriter.cxx
new file mode 100644
index 0000000..c6461d1
--- /dev/null
+++ b/common/rfb/LogWriter.cxx
@@ -0,0 +1,137 @@
+/* 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.
+ */
+
+// -=- LogWriter.cxx - client-side logging interface
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+
+#include <rfb/LogWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+#include <stdlib.h>
+
+rfb::LogParameter rfb::logParams;
+
+using namespace rfb;
+
+
+LogWriter::LogWriter(const char* name) : m_name(name), m_level(0), m_log(0), m_next(log_writers) {
+  log_writers = this;
+}
+
+LogWriter::~LogWriter() {
+  // *** Should remove this logger here!
+}
+
+void LogWriter::setLog(Logger *logger) {
+  m_log = logger;
+}
+
+void LogWriter::setLevel(int level) {
+  m_level = level;
+}
+
+void
+LogWriter::listLogWriters(int width) {
+  // *** make this respect width...
+  LogWriter* current = log_writers;
+  fprintf(stderr, "  ");
+  while (current) {
+    fprintf(stderr, "%s", current->m_name);
+    current = current->m_next;
+    if (current) fprintf(stderr, ", ");
+  }
+  fprintf(stderr, "\n");
+}
+
+LogWriter* LogWriter::log_writers;
+
+LogWriter*
+LogWriter::getLogWriter(const char* name) {
+  LogWriter* current = log_writers;
+  while (current) {
+    if (strcasecmp(name, current->m_name) == 0) return current;
+      current = current->m_next;
+    }
+  return 0;
+}
+
+bool LogWriter::setLogParams(const char* params) {
+  CharArray logwriterName, loggerName, logLevel;
+  if (!strSplit(params, ':', &logwriterName.buf, &loggerName.buf) ||
+    !strSplit(loggerName.buf, ':', &loggerName.buf, &logLevel.buf)) {
+    fprintf(stderr,"failed to parse log params:%s\n",params);
+    return false;
+  }
+  int level = atoi(logLevel.buf);
+  Logger* logger = 0;
+  if (strcmp("", loggerName.buf) != 0) {
+    logger = Logger::getLogger(loggerName.buf);
+    if (!logger) fprintf(stderr,"no logger found! %s\n",loggerName.buf);
+  }
+  if (strcmp("*", logwriterName.buf) == 0) {
+    LogWriter* current = log_writers;
+    while (current) {
+      current->setLog(logger);
+      current->setLevel(level);
+      current = current->m_next;
+    }
+    return true;
+  } else {
+    LogWriter* logwriter = getLogWriter(logwriterName.buf);
+    if (!logwriter) {
+      fprintf(stderr,"no logwriter found! %s\n",logwriterName.buf);
+    } else {
+      logwriter->setLog(logger);
+      logwriter->setLevel(level);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+LogParameter::LogParameter()
+  : StringParameter("Log",
+    "Specifies which log output should be directed to "
+    "which target logger, and the level of output to log. "
+    "Format is <log>:<target>:<level>[, ...].",
+    "") {
+}
+
+bool LogParameter::setParam(const char* v) {
+  if (immutable) return true;
+  LogWriter::setLogParams("*::0");
+  StringParameter::setParam(v);
+  CharArray logParam;
+  CharArray params(getData());
+  while (params.buf) {
+    strSplit(params.buf, ',', &logParam.buf, &params.buf);
+    if (strlen(logParam.buf) && !LogWriter::setLogParams(logParam.buf))
+      return false;
+  }
+  return true;
+}
+
+void LogParameter::setDefault(const char* d) {
+  def_value = d;
+  setParam(def_value);
+}
diff --git a/common/rfb/LogWriter.h b/common/rfb/LogWriter.h
new file mode 100644
index 0000000..124c58e
--- /dev/null
+++ b/common/rfb/LogWriter.h
@@ -0,0 +1,106 @@
+/* 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.
+ */
+
+// -=- LogWriter.h - The Log writer class.
+
+#ifndef __RFB_LOG_WRITER_H__
+#define __RFB_LOG_WRITER_H__
+
+#include <stdarg.h>
+#include <rfb/Logger.h>
+#include <rfb/Configuration.h>
+
+// Each log writer instance has a unique textual name,
+// and is attached to a particular Log instance and
+// is assigned a particular log level.
+
+#define DEF_LOGFUNCTION(name, level) \
+  inline void name(const char* fmt, ...) { \
+    if (m_log && (level <= m_level)) {     \
+      va_list ap; va_start(ap, fmt);       \
+      m_log->write(level, m_name, fmt, ap);\
+      va_end(ap);                          \
+    }                                      \
+  }
+
+namespace rfb {
+
+  class LogWriter;
+
+  class LogWriter {
+  public:
+    LogWriter(const char* name);
+    ~LogWriter();
+
+    const char *getName() {return m_name;}
+
+    void setLog(Logger *logger);
+    void setLevel(int level);
+
+    inline void write(int level, const char* format, ...) {
+      if (m_log && (level <= m_level)) {
+        va_list ap;
+        va_start(ap, format);
+        m_log->write(level, m_name, format, ap);
+        va_end(ap);
+      }
+    }
+
+    DEF_LOGFUNCTION(error, 0)
+    DEF_LOGFUNCTION(status, 10)
+    DEF_LOGFUNCTION(info, 30)
+    DEF_LOGFUNCTION(debug, 100)
+
+    // -=- DIAGNOSTIC & HELPER ROUTINES
+
+    static void listLogWriters(int width=79);
+
+    // -=- CLASS FIELDS & FUNCTIONS
+
+    static LogWriter* log_writers;
+
+    static LogWriter* getLogWriter(const char* name);
+
+    static bool setLogParams(const char* params);
+
+  private:
+    const char* m_name;
+    int m_level;
+    Logger* m_log;
+    LogWriter* m_next;
+  };
+
+  class LogParameter : public StringParameter {
+  public:
+    LogParameter();
+    virtual bool setParam(const char* v);
+
+    // Call this to set a suitable default value.
+    // Can't use the normal default mechanism for
+    // this because there is no guarantee on C++
+    // constructor ordering - some LogWriters may
+    // not exist when LogParameter gets constructed.
+    // NB: The default value must exist for the
+    //     lifetime of the process!
+    void setDefault(const char* v);
+  };
+  extern LogParameter logParams;
+
+};
+
+#endif // __RFB_LOG_WRITER_H__
diff --git a/common/rfb/Logger.cxx b/common/rfb/Logger.cxx
new file mode 100644
index 0000000..52d3308
--- /dev/null
+++ b/common/rfb/Logger.cxx
@@ -0,0 +1,118 @@
+/* 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.
+ */
+
+// -=- Logger.cxx - support for the Logger and LogWriter classes
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define vsnprintf _vsnprintf
+#define HAVE_VSNPRINTF
+#endif
+
+#include <rfb/Logger.h>
+#include <rfb/LogWriter.h>
+#include <rfb/util.h>
+#include <rfb/Threading.h>
+
+using namespace rfb;
+
+#ifndef HAVE_VSNPRINTF
+#ifdef __RFB_THREADING_IMPL
+static Mutex fpLock;
+#endif
+static FILE* fp = 0;
+int vsnprintf(char *str, size_t n, const char *format, va_list ap)
+{
+  str[0] = 0;
+  if (!fp) {
+    // Safely create a FILE* for /dev/null if there isn't already one
+#ifdef __RFB_THREADING_IMPL
+    Lock l(fpLock);
+#endif
+    if (!fp)
+      fp = fopen("/dev/null","w");
+    if (!fp) return 0;
+  }
+  int len = vfprintf(fp, format, ap);
+  if (len <= 0) return 0;
+
+  CharArray s(len+1);
+  vsprintf(s.buf, format, ap);
+
+  int written = __rfbmin(len, (int)n-1);
+  memcpy(str, s.buf, written);
+  str[written] = 0;
+  return len;
+}
+#endif
+
+
+Logger* Logger::loggers = 0;
+
+Logger::Logger(const char* name) : registered(false), m_name(name), m_next(0) {
+}
+
+Logger::~Logger() {
+  // *** Should remove this logger here!
+}
+
+void Logger::write(int level, const char *logname, const char* format,
+                   va_list ap)
+{
+  // - Format the supplied data, and pass it to the
+  //   actual log_message function
+  //   The log level is included as a hint for loggers capable of representing
+  //   different log levels in some way.
+  char buf1[4096];
+  vsnprintf(buf1, sizeof(buf1)-1, format, ap);
+  buf1[sizeof(buf1)-1] = 0;
+  write(level, logname, buf1);
+}
+
+void
+Logger::registerLogger() {
+  if (!registered) {
+    registered = true;
+    m_next = loggers;
+    loggers=this;
+  }
+}
+    
+Logger*
+Logger::getLogger(const char* name) {
+  Logger* current = loggers;
+  while (current) {
+    if (strcasecmp(name, current->m_name) == 0) return current;
+    current = current->m_next;
+  }
+  return 0;
+}
+
+void
+Logger::listLoggers() {
+  Logger* current = loggers;
+  while (current) {
+    printf("  %s\n", current->m_name);
+    current = current->m_next;
+  }
+}
+
+
diff --git a/common/rfb/Logger.h b/common/rfb/Logger.h
new file mode 100644
index 0000000..e53764b
--- /dev/null
+++ b/common/rfb/Logger.h
@@ -0,0 +1,70 @@
+/* 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.
+ */
+
+// -=- Logger.h - The Logger class.
+
+#ifndef __RFB_LOGGER_H__
+#define __RFB_LOGGER_H__
+
+#include <stdarg.h>
+#include <stdio.h>
+
+// Each log writer instance has a unique textual name,
+// and is attached to a particular Logger instance and
+// is assigned a particular log level.
+
+namespace rfb {
+
+  class Logger {
+  public:
+
+    // -=- Create / Destroy a logger
+
+    Logger(const char* name);
+    virtual ~Logger();
+
+    // -=- Get the name of a logger
+
+    const char *getName() {return m_name;}
+
+    // -=- Write data to a log
+
+    virtual void write(int level, const char *logname, const char *text) = 0;
+    void write(int level, const char *logname, const char* format, va_list ap);
+
+    // -=- Register a logger
+
+    void registerLogger();
+
+    // -=- CLASS FIELDS & FUNCTIONS
+
+    static Logger* loggers;
+
+    static Logger* getLogger(const char* name);
+
+    static void listLoggers();
+
+  private:
+    bool registered;
+    const char *m_name;
+    Logger *m_next;
+  };
+
+};
+
+#endif // __RFB_LOGGER_H__
diff --git a/common/rfb/Logger_file.cxx b/common/rfb/Logger_file.cxx
new file mode 100644
index 0000000..8a109e4
--- /dev/null
+++ b/common/rfb/Logger_file.cxx
@@ -0,0 +1,127 @@
+/* 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.
+ */
+
+// -=- Logger_file.cxx - Logger instance for a file
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rfb/util.h>
+#include <rfb/Logger_file.h>
+#include <rfb/Threading.h>
+
+using namespace rfb;
+
+
+// If threading is available then protect the write() operation
+// from concurrent accesses
+#ifdef __RFB_THREADING_IMPL
+static Mutex logLock;
+#endif
+
+
+Logger_File::Logger_File(const char* loggerName)
+  : Logger(loggerName), indent(13), width(79), m_filename(0), m_file(0),
+    m_lastLogTime(0)
+{
+}
+
+Logger_File::~Logger_File()
+{
+  closeFile();
+}
+
+void Logger_File::write(int level, const char *logname, const char *message)
+{
+#ifdef __RFB_THREADING_IMPL
+  Lock l(logLock);
+#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;
+  }
+
+#ifndef _WIN32_WCE
+  time_t current = time(0);
+  if (current != m_lastLogTime) {
+    m_lastLogTime = current;
+    fprintf(m_file, "\n%s", ctime(&m_lastLogTime));
+  }
+#endif
+
+  fprintf(m_file," %s:", logname);
+  int column = strlen(logname) + 2;
+  if (column < indent) {
+    fprintf(m_file,"%*s",indent-column,"");
+    column = indent;
+  }
+  while (true) {
+    const char* s = strchr(message, ' ');
+    int wordLen;
+    if (s) wordLen = s-message;
+    else wordLen = strlen(message);
+
+    if (column + wordLen + 1 > width) {
+      fprintf(m_file,"\n%*s",indent,"");
+      column = indent;
+    }
+    fprintf(m_file," %.*s",wordLen,message);
+    column += wordLen + 1;
+    message += wordLen + 1;
+    if (!s) break;
+  }
+  fprintf(m_file,"\n");
+  fflush(m_file);
+}
+
+void Logger_File::setFilename(const char* filename)
+{
+  closeFile();
+  m_filename = strDup(filename);
+}
+
+void Logger_File::setFile(FILE* file)
+{
+  closeFile();
+  m_file = file;
+}
+
+void Logger_File::closeFile()
+{
+  if (m_filename) {
+    if (m_file) {
+      fclose(m_file);
+      m_file = 0;
+    }
+    strFree(m_filename);
+    m_filename = 0;
+  }
+}
+
+static Logger_File logger("file");
+
+bool rfb::initFileLogger(const char* filename) {
+  logger.setFilename(filename);
+  logger.registerLogger();
+  return true;
+}
diff --git a/common/rfb/Logger_file.h b/common/rfb/Logger_file.h
new file mode 100644
index 0000000..5e0c917
--- /dev/null
+++ b/common/rfb/Logger_file.h
@@ -0,0 +1,51 @@
+/* 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.
+ */
+
+// -=- Logger_file - log to a file
+
+#ifndef __RFB_LOGGER_FILE_H__
+#define __RFB_LOGGER_FILE_H__
+
+#include <time.h>
+#include <rfb/Logger.h>
+
+namespace rfb {
+
+  class Logger_File : public Logger {
+  public:
+    Logger_File(const char* loggerName);
+    ~Logger_File();
+
+    virtual void write(int level, const char *logname, const char *message);
+    void setFilename(const char* filename);
+    void setFile(FILE* file);
+
+    int indent;
+    int width;
+
+  protected:
+    void closeFile();
+    char* m_filename;
+    FILE* m_file;
+    time_t m_lastLogTime;
+  };
+
+  bool initFileLogger(const char* filename);
+};
+
+#endif
diff --git a/common/rfb/Logger_stdio.cxx b/common/rfb/Logger_stdio.cxx
new file mode 100644
index 0000000..581dcd5
--- /dev/null
+++ b/common/rfb/Logger_stdio.cxx
@@ -0,0 +1,32 @@
+/* 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.
+ */
+
+// -=- Logger_stdio.cxx - Logger instances for stderr and stdout
+
+#include <rfb/Logger_stdio.h>
+
+using namespace rfb;
+
+static Logger_StdIO logStdErr("stderr", stderr);
+static Logger_StdIO logStdOut("stdout", stdout);
+
+bool rfb::initStdIOLoggers() {
+  logStdErr.registerLogger();
+  logStdOut.registerLogger();
+  return true;
+}
diff --git a/common/rfb/Logger_stdio.h b/common/rfb/Logger_stdio.h
new file mode 100644
index 0000000..a1d17a0
--- /dev/null
+++ b/common/rfb/Logger_stdio.h
@@ -0,0 +1,39 @@
+/* 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.
+ */
+
+// -=- Logger_stdio - standard output logger instances
+
+#ifndef __RFB_LOGGER_STDIO_H__
+#define __RFB_LOGGER_STDIO_H__
+
+#include <rfb/Logger_file.h>
+
+namespace rfb {
+
+  class Logger_StdIO : public Logger_File {
+  public:
+    Logger_StdIO(const char *name, FILE* file) : Logger_File(name) {
+      setFile(file);
+    }
+  };
+
+  bool initStdIOLoggers();
+
+};
+
+#endif
diff --git a/common/rfb/Makefile.in b/common/rfb/Makefile.in
new file mode 100644
index 0000000..835e188
--- /dev/null
+++ b/common/rfb/Makefile.in
@@ -0,0 +1,80 @@
+
+CXXSRCS = \
+  Blacklist.cxx \
+  CConnection.cxx \
+  CMsgHandler.cxx \
+  CMsgReader.cxx \
+  CMsgReaderV3.cxx \
+  CMsgWriter.cxx \
+  CMsgWriterV3.cxx \
+  CSecurityVncAuth.cxx \
+  ComparingUpdateTracker.cxx \
+  Configuration.cxx \
+  ConnParams.cxx \
+  Cursor.cxx \
+  Decoder.cxx \
+  Encoder.cxx \
+  FileInfo.cxx \
+  FileManager.cxx \
+  FileReader.cxx \
+  FileWriter.cxx \
+  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 \
+  RREDecoder.cxx \
+  RawDecoder.cxx \
+  RawEncoder.cxx \
+  Region.cxx \
+  SConnection.cxx \
+  SFTMsgReader.cxx \
+  SFTMsgWriter.cxx \
+  SFileTransfer.cxx \
+  SFileTransferManager.cxx \
+  SMsgHandler.cxx \
+  SMsgReader.cxx \
+  SMsgReaderV3.cxx \
+  SMsgWriter.cxx \
+  SMsgWriterV3.cxx \
+  ServerCore.cxx \
+  SSecurityFactoryStandard.cxx \
+  SSecurityVncAuth.cxx \
+  Timer.cxx \
+  TightDecoder.cxx \
+  TightEncoder.cxx \
+  TightPalette.cxx \
+  TransImageGetter.cxx \
+  TransferQueue.cxx \
+  UpdateTracker.cxx \
+  VNCSConnectionST.cxx \
+  VNCServerST.cxx \
+  ZRLEEncoder.cxx \
+  ZRLEDecoder.cxx \
+  encodings.cxx \
+  secTypes.cxx \
+  util.cxx
+
+SRCS = d3des.c $(CXXSRCS)
+
+OBJS = d3des.o $(CXXSRCS:.cxx=.o)
+
+DIR_CPPFLAGS = -I$(top_srcdir) @ZLIB_INCLUDE@ @JPEG_INCLUDE@ @VSNPRINTF_DEFINE@
+
+library = librfb.a
+
+all:: $(library)
+
+$(library): $(OBJS)
+	rm -f $(library)
+	$(AR) $(library) $(OBJS)
+	$(RANLIB) $(library)
+
+# followed by boilerplate.mk
diff --git a/common/rfb/Password.cxx b/common/rfb/Password.cxx
new file mode 100644
index 0000000..9127862
--- /dev/null
+++ b/common/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/common/rfb/Password.h b/common/rfb/Password.h
new file mode 100644
index 0000000..ab26903
--- /dev/null
+++ b/common/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/common/rfb/Pixel.h b/common/rfb/Pixel.h
new file mode 100644
index 0000000..4e9d164
--- /dev/null
+++ b/common/rfb/Pixel.h
@@ -0,0 +1,26 @@
+/* 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_PIXEL_H__
+#define __RFB_PIXEL_H__
+
+#include <rdr/types.h>
+
+namespace rfb {
+  typedef rdr::U32 Pixel; // must be big enough to hold any pixel value
+}
+#endif
diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx
new file mode 100644
index 0000000..d093426
--- /dev/null
+++ b/common/rfb/PixelBuffer.cxx
@@ -0,0 +1,309 @@
+/* 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.
+ */
+
+// -=- PixelBuffer.cxx
+//
+// The PixelBuffer class encapsulates the PixelFormat and dimensions
+// of a block of pixel data.
+
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+#include <rfb/PixelBuffer.h>
+
+using namespace rfb;
+using namespace rdr;
+
+static LogWriter vlog("PixelBuffer");
+
+
+// -=- Generic pixel buffer class
+
+PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h, ColourMap* cm)
+  : format(pf), width_(w), height_(h), colourmap(cm) {}
+PixelBuffer::PixelBuffer() : width_(0), height_(0), colourmap(0) {}
+
+PixelBuffer::~PixelBuffer() {}
+
+
+void PixelBuffer::setPF(const PixelFormat &pf) {format = pf;}
+const PixelFormat& PixelBuffer::getPF() const {return format;}
+ColourMap* PixelBuffer::getColourMap() const {return colourmap;}
+
+
+void
+PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) {
+  int inStride;
+  const U8* data = getPixelsR(r, &inStride);
+  // We assume that the specified rectangle is pre-clipped to the buffer
+  int bytesPerPixel = format.bpp/8;
+  int inBytesPerRow = inStride * bytesPerPixel;
+  if (!outStride) outStride = r.width();
+  int outBytesPerRow = outStride * bytesPerPixel;
+  int bytesPerMemCpy = r.width() * bytesPerPixel;
+  U8* imageBufPos = (U8*)imageBuf;
+  const U8* end = data + (inBytesPerRow * r.height());
+  while (data < end) {
+    memcpy(imageBufPos, data, bytesPerMemCpy);
+    imageBufPos += outBytesPerRow;
+    data += inBytesPerRow;
+  }
+}
+
+/* ***
+Pixel PixelBuffer::getPixel(const Point& p) {
+  int stride;
+  Rect r = Rect(p.x, p.y, p.x+1, p.y+1);
+  switch(format.bpp) {
+  case 8: return *((rdr::U8*)getDataAt(r, &stride));
+  case 16: return *((rdr::U16*)getDataAt(r, &stride));
+  case 32: return *((rdr::U32*)getDataAt(r, &stride));
+  default: return 0;
+  };
+}
+*/
+
+
+FullFramePixelBuffer::FullFramePixelBuffer(const PixelFormat& pf, int w, int h,
+                                           rdr::U8* data_, ColourMap* cm)
+  : PixelBuffer(pf, w, h, cm), data(data_)
+{
+}
+
+FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {}
+
+FullFramePixelBuffer::~FullFramePixelBuffer() {}
+
+
+int FullFramePixelBuffer::getStride() const { return width(); }
+
+rdr::U8* FullFramePixelBuffer::getPixelsRW(const Rect& r, int* stride)
+{
+  *stride = getStride();
+  return &data[(r.tl.x + (r.tl.y * *stride)) * format.bpp/8];
+}
+
+
+void FullFramePixelBuffer::fillRect(const Rect& r, Pixel pix) {
+  int stride;
+  U8* data = getPixelsRW(r, &stride);
+  int bytesPerPixel = getPF().bpp/8;
+  int bytesPerRow = bytesPerPixel * stride;
+  int bytesPerFill = bytesPerPixel * r.width();
+
+  U8* end = data + (bytesPerRow * r.height());
+  while (data < end) {
+    switch (bytesPerPixel) {
+    case 1:
+      memset(data, pix, bytesPerFill);
+      break;
+    case 2:
+      {
+        U16* optr = (U16*)data;
+        U16* eol = optr + r.width();
+        while (optr < eol)
+          *optr++ = pix;
+      }
+      break;
+    case 4:
+      {
+        U32* optr = (U32*)data;
+        U32* eol = optr + r.width();
+        while (optr < eol)
+          *optr++ = pix;
+      }
+      break;
+    }
+    data += bytesPerRow;
+  }
+}
+
+void FullFramePixelBuffer::imageRect(const Rect& r, const void* pixels, int srcStride) {
+  int bytesPerPixel = getPF().bpp/8;
+  int destStride;
+  U8* dest = getPixelsRW(r, &destStride);
+  int bytesPerDestRow = bytesPerPixel * destStride;
+  if (!srcStride) srcStride = r.width();
+  int bytesPerSrcRow = bytesPerPixel * srcStride;
+  int bytesPerFill = bytesPerPixel * r.width();
+  const U8* src = (const U8*)pixels;
+  U8* end = dest + (bytesPerDestRow * r.height());
+  while (dest < end) {
+    memcpy(dest, src, bytesPerFill);
+    dest += bytesPerDestRow;
+    src += bytesPerSrcRow;
+  }
+}
+
+void FullFramePixelBuffer::maskRect(const Rect& r, const void* pixels, const void* mask_) {
+  Rect cr = getRect().intersect(r);
+  if (cr.is_empty()) return;
+  int stride;
+  U8* data = getPixelsRW(cr, &stride);
+  U8* mask = (U8*) mask_;
+  int w = cr.width();
+  int h = cr.height();
+  int bpp = getPF().bpp;
+  int pixelStride = r.width();
+  int maskStride = (r.width() + 7) / 8;
+
+  Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
+  mask += offset.y * maskStride;
+  for (int y = 0; y < h; y++) {
+    int cy = offset.y + y;
+    for (int x = 0; x < w; x++) {
+      int cx = offset.x + x;
+      U8* byte = mask + (cx / 8);
+      int bit = 7 - cx % 8;
+      if ((*byte) & (1 << bit)) {
+        switch (bpp) {
+        case 8:
+          ((U8*)data)[y * stride + x] = ((U8*)pixels)[cy * pixelStride + cx];
+          break;
+        case 16:
+          ((U16*)data)[y * stride + x] = ((U16*)pixels)[cy * pixelStride + cx];
+          break;
+        case 32:
+          ((U32*)data)[y * stride + x] = ((U32*)pixels)[cy * pixelStride + cx];
+          break;
+        }
+      }
+    }
+    mask += maskStride;
+  }
+}
+
+void FullFramePixelBuffer::maskRect(const Rect& r, Pixel pixel, const void* mask_) {
+  Rect cr = getRect().intersect(r);
+  if (cr.is_empty()) return;
+  int stride;
+  U8* data = getPixelsRW(cr, &stride);
+  U8* mask = (U8*) mask_;
+  int w = cr.width();
+  int h = cr.height();
+  int bpp = getPF().bpp;
+  int maskStride = (r.width() + 7) / 8;
+
+  Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
+  mask += offset.y * maskStride;
+  for (int y = 0; y < h; y++) {
+    for (int x = 0; x < w; x++) {
+      int cx = offset.x + x;
+      U8* byte = mask + (cx / 8);
+      int bit = 7 - cx % 8;
+      if ((*byte) & (1 << bit)) {
+        switch (bpp) {
+        case 8:
+          ((U8*)data)[y * stride + x] = pixel;
+          break;
+        case 16:
+          ((U16*)data)[y * stride + x] = pixel;
+          break;
+        case 32:
+          ((U32*)data)[y * stride + x] = pixel;
+          break;
+        }
+      }
+    }
+    mask += maskStride;
+  }
+}
+
+void FullFramePixelBuffer::copyRect(const Rect &rect, const Point &move_by_delta) {
+  int stride;
+  U8* data = getPixelsRW(getRect(), &stride);
+  // We assume that the specified rectangle is pre-clipped to the buffer
+  unsigned int bytesPerPixel, bytesPerRow, bytesPerMemCpy;
+  Rect srect = rect.translate(move_by_delta.negate());
+  bytesPerPixel = getPF().bpp/8;
+  bytesPerRow = stride * bytesPerPixel;
+  bytesPerMemCpy = rect.width() * bytesPerPixel;
+  if (move_by_delta.y <= 0) {
+    U8* dest = data + rect.tl.x*bytesPerPixel + rect.tl.y*bytesPerRow;
+    U8* src = data + srect.tl.x*bytesPerPixel + srect.tl.y*bytesPerRow;
+    for (int i=rect.tl.y; i<rect.br.y; i++) {
+      memmove(dest, src, bytesPerMemCpy);
+      dest += bytesPerRow;
+      src += bytesPerRow;
+    }
+  } else {
+    U8* dest = data + rect.tl.x*bytesPerPixel + (rect.br.y-1)*bytesPerRow;
+    U8* src = data + srect.tl.x*bytesPerPixel + (srect.br.y-1)*bytesPerRow;
+    for (int i=rect.tl.y; i<rect.br.y; i++) {
+      memmove(dest, src, bytesPerMemCpy);
+      dest -= bytesPerRow;
+      src -= bytesPerRow;
+    }
+  }
+}
+
+
+// -=- Managed pixel buffer class
+// Automatically allocates enough space for the specified format & area
+
+ManagedPixelBuffer::ManagedPixelBuffer()
+  : datasize(0), own_colourmap(false)
+{
+  checkDataSize();
+};
+
+ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h)
+  : FullFramePixelBuffer(pf, w, h, 0, 0), datasize(0), own_colourmap(false)
+{
+  checkDataSize();
+};
+
+ManagedPixelBuffer::~ManagedPixelBuffer() {
+  if (data) delete [] data;
+  if (colourmap && own_colourmap) delete colourmap;
+};
+
+
+void
+ManagedPixelBuffer::setPF(const PixelFormat &pf) {
+  format = pf; checkDataSize();
+};
+void
+ManagedPixelBuffer::setSize(int w, int h) {
+  width_ = w; height_ = h; checkDataSize();
+};
+
+
+void
+ManagedPixelBuffer::setColourMap(ColourMap* cm, bool own_cm) {
+  if (colourmap && own_colourmap) delete colourmap;
+  colourmap = cm;
+  own_colourmap = own_cm;
+}
+
+inline void
+ManagedPixelBuffer::checkDataSize() {
+  unsigned long new_datasize = width_ * height_ * (format.bpp/8);
+  if (datasize < new_datasize) {
+    vlog.debug("reallocating managed buffer (%dx%d)", width_, height_);
+    if (data) {
+      delete [] data;
+      datasize = 0; data = 0;
+    }
+    if (new_datasize) {
+      data = new U8[new_datasize];
+      if (!data)
+        throw Exception("rfb::ManagedPixelBuffer unable to allocate buffer");
+      datasize = new_datasize;
+    }
+  }
+};
diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h
new file mode 100644
index 0000000..4a13923
--- /dev/null
+++ b/common/rfb/PixelBuffer.h
@@ -0,0 +1,172 @@
+/* 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.
+ */
+
+// -=- PixelBuffer.h
+//
+// The PixelBuffer class encapsulates the PixelFormat and dimensions
+// of a block of pixel data.
+
+#ifndef __RFB_PIXEL_BUFFER_H__
+#define __RFB_PIXEL_BUFFER_H__
+
+#include <rfb/ImageGetter.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ColourMap.h>
+#include <rfb/Rect.h>
+#include <rfb/Pixel.h>
+
+namespace rfb {
+
+  class Region;
+
+  class PixelBuffer : public ImageGetter {
+  public:
+    PixelBuffer(const PixelFormat& pf, int width, int height, ColourMap* cm);
+    virtual ~PixelBuffer();
+
+    ///////////////////////////////////////////////
+    // Format / Layout
+    //
+
+    // Set/get pixel format & colourmap
+    virtual void setPF(const PixelFormat &pf);
+    virtual const PixelFormat &getPF() const;
+    virtual ColourMap* getColourMap() const;
+
+    // Get width, height and number of pixels
+    int width()  const { return width_; }
+    int height() const { return height_; }
+    int area() const { return width_ * height_; }
+
+    // Get rectangle encompassing this buffer
+    //   Top-left of rectangle is either at (0,0), or the specified point.
+    Rect getRect() const { return Rect(0, 0, width_, height_); }
+    Rect getRect(const Point& pos) const {
+      return Rect(pos, pos.translate(Point(width_, height_)));
+    }
+
+    ///////////////////////////////////////////////
+    // Access to pixel data
+    //
+
+    // Get a pointer into the buffer
+    //   The pointer is to the top-left pixel of the specified Rect.
+    //   The buffer stride (in pixels) is returned.
+    virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) = 0;
+
+    // Get pixel data for a given part of the buffer
+    //   Data is copied into the supplied buffer, with the specified
+    //   stride.
+    virtual void getImage(void* imageBuf, const Rect& r, int stride=0);
+
+    // Get the data at (x,y) as a Pixel.
+    //   VERY INEFFICIENT!!!
+    // *** Pixel getPixel(const Point& p);
+
+    ///////////////////////////////////////////////
+    // Framebuffer update methods
+    //
+
+    // Ensure that the specified rectangle of buffer is up to date.
+    //   Overridden by derived classes implementing framebuffer access
+    //   to copy the required display data into place.
+    virtual void grabRegion(const Region& region) {}
+
+  protected:
+    PixelBuffer();
+    PixelFormat format;
+    int width_, height_;
+    ColourMap* colourmap;
+  };
+
+  // FullFramePixelBuffer
+
+  class FullFramePixelBuffer : public PixelBuffer {
+  public:
+    FullFramePixelBuffer(const PixelFormat& pf, int width, int height,
+                         rdr::U8* data_, ColourMap* cm);
+    virtual ~FullFramePixelBuffer();
+
+    // - Get the number of pixels per row in the actual pixel buffer data area
+    //   This may in some cases NOT be the same as width().
+    virtual int getStride() const;
+
+    // Get a pointer to specified pixel data
+    virtual rdr::U8* getPixelsRW(const Rect& r, int* stride);
+    virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) {
+      return getPixelsRW(r, stride);
+    }
+
+    ///////////////////////////////////////////////
+    // Basic rendering operations
+    // These operations DO NOT clip to the pixelbuffer area, or trap overruns.
+
+    // Fill a rectangle
+    virtual void fillRect(const Rect &dest, Pixel pix);
+
+    // Copy pixel data to the buffer
+    virtual void imageRect(const Rect &dest, const void* pixels, int stride=0);
+
+    // Copy pixel data from one PixelBuffer location to another
+    virtual void copyRect(const Rect &dest, const Point &move_by_delta);
+
+    // Copy pixel data to the buffer through a mask
+    //   pixels is a pointer to the pixel to be copied to r.tl.
+    //   maskPos specifies the pixel offset in the mask to start from.
+    //   mask_ is a pointer to the mask bits at (0,0).
+    //   pStride and mStride are the strides of the pixel and mask buffers.
+    virtual void maskRect(const Rect& r, const void* pixels, const void* mask_);
+
+    //   pixel is the Pixel value to be used where mask_ is set
+    virtual void maskRect(const Rect& r, Pixel pixel, const void* mask_);
+
+    // *** Should this be visible?
+    rdr::U8* data;
+
+  protected:
+    FullFramePixelBuffer();
+  };
+
+  // -=- Managed pixel buffer class
+  // Automatically allocates enough space for the specified format & area
+
+  class ManagedPixelBuffer : public FullFramePixelBuffer {
+  public:
+    ManagedPixelBuffer();
+    ManagedPixelBuffer(const PixelFormat& pf, int width, int height);
+    virtual ~ManagedPixelBuffer();
+
+    // Manage the pixel buffer layout
+    virtual void setPF(const PixelFormat &pf);
+    virtual void setSize(int w, int h);
+
+    // Assign a colour map to the buffer
+    virtual void setColourMap(ColourMap* cm, bool own_cm);
+
+    // Return the total number of bytes of pixel data in the buffer
+    int dataLen() const { return width_ * height_ * (format.bpp/8); }
+
+  protected:
+    unsigned long datasize;
+    bool own_colourmap;
+    void checkDataSize();
+  };
+
+};
+
+#endif // __RFB_PIXEL_BUFFER_H__
diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx
new file mode 100644
index 0000000..74b6837
--- /dev/null
+++ b/common/rfb/PixelFormat.cxx
@@ -0,0 +1,239 @@
+/* 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 <string.h>
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/util.h>
+
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+
+using namespace rfb;
+
+PixelFormat::PixelFormat(int b, int d, bool e, bool t,
+                         int rm, int gm, int bm, int rs, int gs, int bs)
+  : bpp(b), depth(d), bigEndian(e), trueColour(t),
+    redMax(rm), greenMax(gm), blueMax(bm),
+    redShift(rs), greenShift(gs), blueShift(bs)
+{
+}
+
+PixelFormat::PixelFormat()
+  : bpp(8), depth(8), bigEndian(false), trueColour(true),
+    redMax(7), greenMax(7), blueMax(3),
+    redShift(0), greenShift(3), blueShift(6)
+{
+}
+
+bool PixelFormat::equal(const PixelFormat& other) const
+{
+  return (bpp == other.bpp &&
+          depth == other.depth &&
+          (bigEndian == other.bigEndian || bpp == 8) &&
+          trueColour == other.trueColour &&
+          (!trueColour || (redMax == other.redMax &&
+                           greenMax == other.greenMax &&
+                           blueMax == other.blueMax &&
+                           redShift == other.redShift &&
+                           greenShift == other.greenShift &&
+                           blueShift == other.blueShift)));
+}
+
+void PixelFormat::read(rdr::InStream* is)
+{
+  bpp = is->readU8();
+  depth = is->readU8();
+  bigEndian = is->readU8();
+  trueColour = is->readU8();
+  redMax = is->readU16();
+  greenMax = is->readU16();
+  blueMax = is->readU16();
+  redShift = is->readU8();
+  greenShift = is->readU8();
+  blueShift = is->readU8();
+  is->skip(3);
+}
+
+void PixelFormat::write(rdr::OutStream* os) const
+{
+  os->writeU8(bpp);
+  os->writeU8(depth);
+  os->writeU8(bigEndian);
+  os->writeU8(trueColour);
+  os->writeU16(redMax);
+  os->writeU16(greenMax);
+  os->writeU16(blueMax);
+  os->writeU8(redShift);
+  os->writeU8(greenShift);
+  os->writeU8(blueShift);
+  os->pad(3);
+}
+
+Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue,
+                                ColourMap* cm) const
+{
+  if (trueColour) {
+    rdr::U32 r = ((rdr::U32)red   * redMax   + 32767) / 65535;
+    rdr::U32 g = ((rdr::U32)green * greenMax + 32767) / 65535;
+    rdr::U32 b = ((rdr::U32)blue  * blueMax  + 32767) / 65535;
+
+    return (r << redShift) | (g << greenShift) | (b << blueShift);
+  } else if (cm) {
+    // Try to find the closest pixel by Cartesian distance
+    int colours = 1 << depth;
+    int diff = 256 * 256 * 4;
+    int col = 0;
+    for (int i=0; i<colours; i++) {
+      int r, g, b;
+      cm->lookup(i, &r, &g, &b);
+      int rd = (r-red) >> 8;
+      int gd = (g-green) >> 8;
+      int bd = (b-blue) >> 8;
+      int d = rd*rd + gd*gd + bd*bd;
+      if (d < diff) {
+        col = i;
+        diff = d;
+      }
+    }
+    return col;
+  }
+  // XXX just return 0 for colour map?
+  return 0;
+}
+
+
+void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const
+{
+  if (trueColour) {
+    rgb->r = (((p >> redShift  ) & redMax  ) * 65535 + redMax  /2) / redMax;
+    rgb->g = (((p >> greenShift) & greenMax) * 65535 + greenMax/2) / greenMax;
+    rgb->b = (((p >> blueShift ) & blueMax ) * 65535 + blueMax /2) / blueMax;
+  } else {
+    cm->lookup(p, &rgb->r, &rgb->g, &rgb->b);
+  }
+}
+
+
+void PixelFormat::print(char* str, int len) const
+{
+  // Unfortunately snprintf is not widely available so we build the string up
+  // using strncat - not pretty, but should be safe against buffer overruns.
+
+  char num[20];
+  if (len < 1) return;
+  str[0] = 0;
+  strncat(str, "depth ", len-1-strlen(str));
+  sprintf(num,"%d",depth);
+  strncat(str, num, len-1-strlen(str));
+  strncat(str, " (", len-1-strlen(str));
+  sprintf(num,"%d",bpp);
+  strncat(str, num, len-1-strlen(str));
+  strncat(str, "bpp)", len-1-strlen(str));
+  if (bpp != 8) {
+    if (bigEndian)
+      strncat(str, " big-endian", len-1-strlen(str));
+    else
+      strncat(str, " little-endian", len-1-strlen(str));
+  }
+
+  if (!trueColour) {
+    strncat(str, " color-map", len-1-strlen(str));
+    return;
+  }
+
+  if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
+      blueMax  == (1 << greenShift) - 1 &&
+      greenMax == (1 << (redShift-greenShift)) - 1 &&
+      redMax   == (1 << (depth-redShift)) - 1)
+  {
+    strncat(str, " rgb", len-1-strlen(str));
+    sprintf(num,"%d",depth-redShift);
+    strncat(str, num, len-1-strlen(str));
+    sprintf(num,"%d",redShift-greenShift);
+    strncat(str, num, len-1-strlen(str));
+    sprintf(num,"%d",greenShift);
+    strncat(str, num, len-1-strlen(str));
+    return;
+  }
+
+  if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
+      redMax   == (1 << greenShift) - 1 &&
+      greenMax == (1 << (blueShift-greenShift)) - 1 &&
+      blueMax  == (1 << (depth-blueShift)) - 1)
+  {
+    strncat(str, " bgr", len-1-strlen(str));
+    sprintf(num,"%d",depth-blueShift);
+    strncat(str, num, len-1-strlen(str));
+    sprintf(num,"%d",blueShift-greenShift);
+    strncat(str, num, len-1-strlen(str));
+    sprintf(num,"%d",greenShift);
+    strncat(str, num, len-1-strlen(str));
+    return;
+  }
+
+  strncat(str, " rgb max ", len-1-strlen(str));
+  sprintf(num,"%d,",redMax);
+  strncat(str, num, len-1-strlen(str));
+  sprintf(num,"%d,",greenMax);
+  strncat(str, num, len-1-strlen(str));
+  sprintf(num,"%d",blueMax);
+  strncat(str, num, len-1-strlen(str));
+  strncat(str, " shift ", len-1-strlen(str));
+  sprintf(num,"%d,",redShift);
+  strncat(str, num, len-1-strlen(str));
+  sprintf(num,"%d,",greenShift);
+  strncat(str, num, len-1-strlen(str));
+  sprintf(num,"%d",blueShift);
+  strncat(str, num, len-1-strlen(str));
+}
+
+
+bool PixelFormat::parse(const char* str)
+{
+  char rgbbgr[4];
+  int bits1, bits2, bits3;
+  if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
+    return false;
+  
+  depth = bits1 + bits2 + bits3;
+  bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
+  trueColour = true;
+  rdr::U32 endianTest = 1;
+  bigEndian = (*(rdr::U8*)&endianTest == 0);
+
+  greenShift = bits3;
+  greenMax = (1 << bits2) - 1;
+
+  if (strcasecmp(rgbbgr, "bgr") == 0) {
+    redShift = 0;
+    redMax = (1 << bits3) - 1;
+    blueShift = bits3 + bits2;
+    blueMax = (1 << bits1) - 1;
+  } else if (strcasecmp(rgbbgr, "rgb") == 0) {
+    blueShift = 0;
+    blueMax = (1 << bits3) - 1;
+    redShift = bits3 + bits2;
+    redMax = (1 << bits1) - 1;
+  } else {
+    return false;
+  }
+  return true;
+}
diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h
new file mode 100644
index 0000000..111c38c
--- /dev/null
+++ b/common/rfb/PixelFormat.h
@@ -0,0 +1,58 @@
+/* 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.
+ */
+//
+// PixelFormat - structure to represent a pixel format.  Also has useful
+// methods for reading & writing to streams, etc.
+//
+
+#ifndef __RFB_PIXELFORMAT_H__
+#define __RFB_PIXELFORMAT_H__
+
+#include <rfb/Pixel.h>
+#include <rfb/ColourMap.h>
+
+namespace rdr { class InStream; class OutStream; }
+
+namespace rfb {
+
+  class PixelFormat {
+  public:
+    PixelFormat(int b, int d, bool e, bool t,
+                int rm=0, int gm=0, int bm=0, int rs=0, int gs=0, int bs=0);
+    PixelFormat();
+    bool equal(const PixelFormat& other) const;
+    void read(rdr::InStream* is);
+    void write(rdr::OutStream* os) const;
+    Pixel pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue, ColourMap* cm=0) const;
+    void rgbFromPixel(Pixel pix, ColourMap* cm, Colour* rgb) const;
+    void print(char* str, int len) const;
+    bool parse(const char* str);
+
+    int bpp;
+    int depth;
+    bool bigEndian;
+    bool trueColour;
+    int redMax;
+    int greenMax;
+    int blueMax;
+    int redShift;
+    int greenShift;
+    int blueShift;
+  };
+}
+#endif
diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx
new file mode 100644
index 0000000..da56ee7
--- /dev/null
+++ b/common/rfb/RREDecoder.cxx
@@ -0,0 +1,58 @@
+/* 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 <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/RREDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/rreDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/rreDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/rreDecode.h>
+#undef BPP
+
+Decoder* RREDecoder::create(CMsgReader* reader)
+{
+  return new RREDecoder(reader);
+}
+
+RREDecoder::RREDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+RREDecoder::~RREDecoder()
+{
+}
+
+void RREDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+  rdr::InStream* is = reader->getInStream();
+  switch (reader->bpp()) {
+  case 8:  rreDecode8 (r, is, handler); break;
+  case 16: rreDecode16(r, is, handler); break;
+  case 32: rreDecode32(r, is, handler); break;
+  }
+}
diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h
new file mode 100644
index 0000000..2309f75
--- /dev/null
+++ b/common/rfb/RREDecoder.h
@@ -0,0 +1,35 @@
+/* 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_RREDECODER_H__
+#define __RFB_RREDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+  class RREDecoder : public Decoder {
+  public:
+    static Decoder* create(CMsgReader* reader);
+    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual ~RREDecoder();
+  private:
+    RREDecoder(CMsgReader* reader);
+    CMsgReader* reader;
+  };
+}
+#endif
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
new file mode 100644
index 0000000..b000e9d
--- /dev/null
+++ b/common/rfb/RREEncoder.cxx
@@ -0,0 +1,75 @@
+/* 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 <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/RREEncoder.h>
+
+using namespace rfb;
+
+#define BPP 8
+#include <rfb/rreEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/rreEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/rreEncode.h>
+#undef BPP
+
+Encoder* RREEncoder::create(SMsgWriter* writer)
+{
+  return new RREEncoder(writer);
+}
+
+RREEncoder::RREEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+RREEncoder::~RREEncoder()
+{
+}
+
+bool RREEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  int w = r.width();
+  int h = r.height();
+  rdr::U8* imageBuf = writer->getImageBuf(w*h);
+  ig->getImage(imageBuf, r);
+
+  mos.clear();
+
+  int nSubrects = -1;
+  switch (writer->bpp()) {
+  case 8:  nSubrects = rreEncode8(imageBuf, w, h, &mos);  break;
+  case 16: nSubrects = rreEncode16(imageBuf, w, h, &mos); break;
+  case 32: nSubrects = rreEncode32(imageBuf, w, h, &mos); break;
+  }
+  
+  if (nSubrects < 0) {
+    return writer->writeRect(r, encodingRaw, ig, actual);
+  }
+
+  writer->startRect(r, encodingRRE);
+  rdr::OutStream* os = writer->getOutStream();
+  os->writeU32(nSubrects);
+  os->writeBytes(mos.data(), mos.length());
+  writer->endRect();
+  return true;
+}
diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h
new file mode 100644
index 0000000..1281410
--- /dev/null
+++ b/common/rfb/RREEncoder.h
@@ -0,0 +1,37 @@
+/* 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_RREENCODER_H__
+#define __RFB_RREENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+  class RREEncoder : public Encoder {
+  public:
+    static Encoder* create(SMsgWriter* writer);
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual ~RREEncoder();
+  private:
+    RREEncoder(SMsgWriter* writer);
+    SMsgWriter* writer;
+    rdr::MemOutStream mos;
+  };
+}
+#endif
diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx
new file mode 100644
index 0000000..57cb37b
--- /dev/null
+++ b/common/rfb/RawDecoder.cxx
@@ -0,0 +1,55 @@
+/* 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 <rdr/InStream.h>
+#include <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/RawDecoder.h>
+
+using namespace rfb;
+
+Decoder* RawDecoder::create(CMsgReader* reader)
+{
+  return new RawDecoder(reader);
+}
+
+RawDecoder::RawDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+RawDecoder::~RawDecoder()
+{
+}
+
+void RawDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+  int x = r.tl.x;
+  int y = r.tl.y;
+  int w = r.width();
+  int h = r.height();
+  int nPixels;
+  rdr::U8* imageBuf = reader->getImageBuf(w, w*h, &nPixels);
+  int bytesPerRow = w * (reader->bpp() / 8);
+  while (h > 0) {
+    int nRows = nPixels / w;
+    if (nRows > h) nRows = h;
+    reader->getInStream()->readBytes(imageBuf, nRows * bytesPerRow);
+    handler->imageRect(Rect(x, y, x+w, y+nRows), imageBuf);
+    h -= nRows;
+    y += nRows;
+  }
+}
diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h
new file mode 100644
index 0000000..9fdbb22
--- /dev/null
+++ b/common/rfb/RawDecoder.h
@@ -0,0 +1,35 @@
+/* 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_RAWDECODER_H__
+#define __RFB_RAWDECODER_H__
+
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+  class RawDecoder : public Decoder {
+  public:
+    static Decoder* create(CMsgReader* reader);
+    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual ~RawDecoder();
+  private:
+    RawDecoder(CMsgReader* reader);
+    CMsgReader* reader;
+  };
+}
+#endif
diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx
new file mode 100644
index 0000000..a2545b6
--- /dev/null
+++ b/common/rfb/RawEncoder.cxx
@@ -0,0 +1,59 @@
+/* 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 <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/RawEncoder.h>
+
+using namespace rfb;
+
+Encoder* RawEncoder::create(SMsgWriter* writer)
+{
+  return new RawEncoder(writer);
+}
+
+RawEncoder::RawEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+}
+
+RawEncoder::~RawEncoder()
+{
+}
+
+bool RawEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  int x = r.tl.x;
+  int y = r.tl.y;
+  int w = r.width();
+  int h = r.height();
+  int nPixels;
+  rdr::U8* imageBuf = writer->getImageBuf(w, w*h, &nPixels);
+  int bytesPerRow = w * (writer->bpp() / 8);
+  writer->startRect(r, encodingRaw);
+  while (h > 0) {
+    int nRows = nPixels / w;
+    if (nRows > h) nRows = h;
+    ig->getImage(imageBuf, Rect(x, y, x+w, y+nRows));
+    writer->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow);
+    h -= nRows;
+    y += nRows;
+  }
+  writer->endRect();
+  return true;
+}
diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h
new file mode 100644
index 0000000..1b9ad92
--- /dev/null
+++ b/common/rfb/RawEncoder.h
@@ -0,0 +1,35 @@
+/* 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_RAWENCODER_H__
+#define __RFB_RAWENCODER_H__
+
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+  class RawEncoder : public Encoder {
+  public:
+    static Encoder* create(SMsgWriter* writer);
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual ~RawEncoder();
+  private:
+    RawEncoder(SMsgWriter* writer);
+    SMsgWriter* writer;
+  };
+}
+#endif
diff --git a/common/rfb/Rect.h b/common/rfb/Rect.h
new file mode 100644
index 0000000..52e92b5
--- /dev/null
+++ b/common/rfb/Rect.h
@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+// rfb::Rect and rfb::Point structures
+
+#ifndef __RFB_RECT_INCLUDED__
+#define __RFB_RECT_INCLUDED__
+
+// 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
+
+namespace rfb {
+
+  // rfb::Point
+  //
+  // Represents a point in 2D space, by X and Y coordinates.
+  // Can also be used to represent a delta, or offset, between
+  // two Points.
+  // Functions are provided to allow Points to be compared for
+  // equality and translated by a supplied offset.
+  // Functions are also provided to negate offset Points.
+
+  struct Point {
+    Point() : x(0), y(0) {}
+    Point(int x_, int y_) : x(x_), y(y_) {}
+    inline Point negate() const {return Point(-x, -y);}
+    inline bool equals(const Point &p) const {return x==p.x && y==p.y;}
+    inline Point translate(const Point &p) const {return Point(x+p.x, y+p.y);}
+    inline Point subtract(const Point &p) const {return Point(x-p.x, y-p.y);}
+    int x, y;
+  };
+
+  // rfb::Rect
+  //
+  // Represents a rectangular region defined by its top-left (tl)
+  // and bottom-right (br) Points.
+  // Rects may be compared for equality, checked to determine whether
+  // or not they are empty, cleared (made empty), or intersected with
+  // one another.  The bounding rectangle of two existing Rects
+  // may be calculated, as may the area of a Rect.
+  // Rects may also be translated, in the same way as Points, by
+  // an offset specified in a Point structure.
+
+  struct Rect {
+    Rect() {}
+    Rect(Point tl_, Point br_) : tl(tl_), br(br_) {}
+    Rect(int x1, int y1, int x2, int y2) : tl(x1, y1), br(x2, y2) {}
+    inline void setXYWH(int x, int y, int w, int h) {
+      tl.x = x; tl.y = y; br.x = x+w; br.y = y+h;
+    }
+    inline Rect intersect(const Rect &r) const {
+      Rect result;
+      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 = __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 {
+      return Rect(tl.translate(p), br.translate(p));
+    }
+    inline bool equals(const Rect &r) const {return r.tl.equals(tl) && r.br.equals(br);}
+    inline bool is_empty() const {return (tl.x >= br.x) || (tl.y >= br.y);}
+    inline void clear() {tl = Point(); br = Point();}
+    inline bool enclosed_by(const Rect &r) const {
+      return (tl.x>=r.tl.x) && (tl.y>=r.tl.y) && (br.x<=r.br.x) && (br.y<=r.br.y);
+    }
+    inline bool overlaps(const Rect &r) const {
+      return tl.x < r.br.x && tl.y < r.br.y && br.x > r.tl.x && br.y > r.tl.y;
+    }
+    inline unsigned int area() const {return is_empty() ? 0 : (br.x-tl.x)*(br.y-tl.y);}
+    inline Point dimensions() const {return Point(width(), height());}
+    inline int width() const {return br.x-tl.x;}
+    inline int height() const {return br.y-tl.y;}
+    inline bool contains(const Point &p) const {
+      return (tl.x<=p.x) && (tl.y<=p.y) && (br.x>p.x) && (br.y>p.y);
+    }
+    Point tl;
+    Point br;
+  };
+}
+#endif // __RFB_RECT_INCLUDED__
diff --git a/common/rfb/Region.cxx b/common/rfb/Region.cxx
new file mode 100644
index 0000000..7965a6c
--- /dev/null
+++ b/common/rfb/Region.cxx
@@ -0,0 +1,248 @@
+/* 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.
+ */
+
+// Cross-platform Region class based on the X11 region implementation.  Note
+// that for efficiency this code manipulates the Xlib region structure
+// directly.  Apart from the layout of the structure, there is one other key
+// assumption made: a Region returned from XCreateRegion must always have its
+// rects member allocated so that there is space for at least one rectangle.
+//
+
+#include <rfb/Region.h>
+#include <Xregion/Xregion.h>
+#include <Xregion/region.h>
+#include <assert.h>
+#include <stdio.h>
+
+// A _RectRegion must never be passed as a return parameter to the Xlib region
+// operations.  This is because for efficiency its "rects" member has not been
+// allocated with Xmalloc.  It is however safe to pass it as an input
+// parameter.
+
+class _RectRegion {
+public:
+  _RectRegion(const rfb::Rect& r) {
+    region.rects = &region.extents;
+    region.numRects = 1;
+    region.extents.x1 = r.tl.x;
+    region.extents.y1 = r.tl.y;
+    region.extents.x2 = r.br.x;
+    region.extents.y2 = r.br.y;
+    region.size = 1;
+    if (r.is_empty())
+      region.numRects = 0;
+  }
+  REGION region;
+};
+
+
+rfb::Region::Region() {
+  xrgn = XCreateRegion();
+  assert(xrgn);
+}
+
+rfb::Region::Region(const Rect& r) {
+  xrgn = XCreateRegion();
+  assert(xrgn);
+  reset(r);
+}
+
+rfb::Region::Region(const rfb::Region& r) {
+  xrgn = XCreateRegion();
+  assert(xrgn);
+  XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region::~Region() {
+  XDestroyRegion(xrgn);
+}
+
+rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
+  clear();
+  XUnionRegion(xrgn, r.xrgn, xrgn);
+  return *this;
+}
+
+void rfb::Region::clear() {
+  xrgn->numRects = 0;
+  xrgn->extents.x1 = 0;
+  xrgn->extents.y1 = 0;
+  xrgn->extents.x2 = 0;
+  xrgn->extents.y2 = 0;
+}
+
+void rfb::Region::reset(const Rect& r) {
+  if (r.is_empty()) {
+    clear();
+  } else {
+    xrgn->numRects = 1;
+    xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
+    xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
+    xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
+    xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
+  }
+}
+
+void rfb::Region::translate(const Point& delta) {
+  XOffsetRegion(xrgn, delta.x, delta.y);
+}
+
+void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
+  clear();
+  std::vector<Rect>::const_iterator i;
+  for (i=rects.begin(); i != rects.end(); i++) {
+    _RectRegion rr(*i);
+    XUnionRegion(xrgn, &rr.region, xrgn);
+  }
+}
+
+void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
+                                            int nRects, const ShortRect* rects)
+{
+  if (xrgn->size < nRects)
+  {
+    BOX* prevRects = xrgn->rects;
+    xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
+    if (!xrgn->rects) {
+      fprintf(stderr,"Xrealloc failed\n");
+      Xfree(prevRects);
+      return;
+    }
+    xrgn->size = nRects;
+  }
+
+  xrgn->numRects = nRects;
+  xrgn->extents.x1 = extents->x1;
+  xrgn->extents.y1 = extents->y1;
+  xrgn->extents.x2 = extents->x2;
+  xrgn->extents.y2 = extents->y2;
+  for (int i = 0; i < nRects; i++) {
+    xrgn->rects[i].x1 = rects[i].x1;
+    xrgn->rects[i].y1 = rects[i].y1;
+    xrgn->rects[i].x2 = rects[i].x2;
+    xrgn->rects[i].y2 = rects[i].y2;
+  }
+}
+
+void rfb::Region::copyFrom(const rfb::Region& r) {
+  XUnionRegion(r.xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_intersect(const rfb::Region& r) {
+  XIntersectRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_union(const rfb::Region& r) {
+  XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_subtract(const rfb::Region& r) {
+  XSubtractRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
+  rfb::Region ret;
+  XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
+  return ret;
+}
+
+rfb::Region rfb::Region::union_(const rfb::Region& r) const {
+  rfb::Region ret;
+  XUnionRegion(xrgn, r.xrgn, ret.xrgn);
+  return ret;
+}
+
+rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
+  rfb::Region ret;
+  XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
+  return ret;
+}
+
+bool rfb::Region::equals(const rfb::Region& r) const {
+  return XEqualRegion(xrgn, r.xrgn);
+}
+
+int rfb::Region::numRects() const {
+  return xrgn->numRects;
+}
+
+bool rfb::Region::get_rects(std::vector<Rect>* rects,
+                            bool left2right, bool topdown, int maxArea) const
+{
+  int nRects = xrgn->numRects;
+  int xInc = left2right ? 1 : -1;
+  int yInc = topdown ? 1 : -1;
+  int i = topdown ? 0 : nRects-1;
+  rects->clear();
+  rects->reserve(nRects);
+
+  while (nRects > 0) {
+    int firstInNextBand = i;
+    int nRectsInBand = 0;
+
+    while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
+    {
+      firstInNextBand += yInc;
+      nRects--;
+      nRectsInBand++;
+    }
+
+    if (xInc != yInc)
+      i = firstInNextBand - yInc;
+
+    while (nRectsInBand > 0) {
+      int y = xrgn->rects[i].y1;
+      int h = maxArea / (xrgn->rects[i].x2 - xrgn->rects[i].x1);
+      if (!h) h = xrgn->rects[i].y2 - y;
+      do {
+        if (h > xrgn->rects[i].y2 - y)
+          h = xrgn->rects[i].y2 - y;
+        Rect r(xrgn->rects[i].x1, y, xrgn->rects[i].x2, y+h);
+        rects->push_back(r);
+        y += h;
+      } while (y < xrgn->rects[i].y2);
+      i += xInc;
+      nRectsInBand--;
+    }
+
+    i = firstInNextBand;
+  }
+
+  return !rects->empty();
+}
+
+rfb::Rect rfb::Region::get_bounding_rect() const {
+  return Rect(xrgn->extents.x1, xrgn->extents.y1,
+              xrgn->extents.x2, xrgn->extents.y2);
+}
+
+
+void rfb::Region::debug_print(const char* prefix) const
+{
+  fprintf(stderr,"%s num rects %3ld extents %3d,%3d %3dx%3d\n",
+          prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
+          xrgn->extents.x2-xrgn->extents.x1,
+          xrgn->extents.y2-xrgn->extents.y1);
+
+  for (int i = 0; i < xrgn->numRects; i++) {
+    fprintf(stderr,"    rect %3d,%3d %3dx%3d\n",
+            xrgn->rects[i].x1, xrgn->rects[i].y1,
+            xrgn->rects[i].x2-xrgn->rects[i].x1,
+            xrgn->rects[i].y2-xrgn->rects[i].y1);
+  }
+}
diff --git a/common/rfb/Region.h b/common/rfb/Region.h
new file mode 100644
index 0000000..9337556
--- /dev/null
+++ b/common/rfb/Region.h
@@ -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.
+ */
+
+// Cross-platform Region class based on the X11 region implementation
+
+#ifndef __RFB_REGION_INCLUDED__
+#define __RFB_REGION_INCLUDED__
+
+#include <rfb/Rect.h>
+#include <vector>
+
+struct _XRegion;
+
+namespace rfb {
+
+  struct ShortRect {
+    short x1, y1, x2, y2;
+  };
+
+  class Region {
+  public:
+    // Create an empty region
+    Region();
+    // Create a rectangular region
+    Region(const Rect& r);
+
+    Region(const Region& r);
+    Region &operator=(const Region& src);
+
+    ~Region();
+
+    // the following methods alter the region in place:
+
+    void clear();
+    void reset(const Rect& r);
+    void translate(const rfb::Point& delta);
+    void setOrderedRects(const std::vector<Rect>& rects);
+    void setExtentsAndOrderedRects(const ShortRect* extents, int nRects,
+                                   const ShortRect* rects);
+    void copyFrom(const Region& r);
+
+    void assign_intersect(const Region& r);
+    void assign_union(const Region& r);
+    void assign_subtract(const Region& r);
+
+    // the following three operations return a new region:
+
+    Region intersect(const Region& r) const;
+    Region union_(const Region& r) const;
+    Region subtract(const Region& r) const;
+
+    bool equals(const Region& b) const;
+    int numRects() const;
+    bool is_empty() const { return numRects() == 0; }
+
+    bool get_rects(std::vector<Rect>* rects, bool left2right=true,
+                   bool topdown=true, int maxArea=0) const;
+    Rect get_bounding_rect() const;
+
+    void debug_print(const char *prefix) const;
+
+  protected:
+
+    struct _XRegion* xrgn;
+  };
+
+};
+
+#endif // __RFB_REGION_INCLUDED__
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
new file mode 100644
index 0000000..1422b54
--- /dev/null
+++ b/common/rfb/SConnection.cxx
@@ -0,0 +1,322 @@
+/* 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 <string.h>
+#include <rfb/Exception.h>
+#include <rfb/secTypes.h>
+#include <rfb/SMsgReaderV3.h>
+#include <rfb/SMsgWriterV3.h>
+#include <rfb/SConnection.h>
+#include <rfb/ServerCore.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SConnection");
+
+// AccessRights values
+const SConnection::AccessRights SConnection::AccessView       = 0x0001;
+const SConnection::AccessRights SConnection::AccessKeyEvents  = 0x0002;
+const SConnection::AccessRights SConnection::AccessPtrEvents  = 0x0004;
+const SConnection::AccessRights SConnection::AccessCutText    = 0x0008;
+const SConnection::AccessRights SConnection::AccessDefault    = 0x03ff;
+const SConnection::AccessRights SConnection::AccessNoQuery    = 0x0400;
+const SConnection::AccessRights SConnection::AccessFull       = 0xffff;
+
+
+SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
+  : readyForSetColourMapEntries(false),
+    is(0), os(0), reader_(0), writer_(0),
+    security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
+    reverseConnection(reverseConnection_)
+{
+  defaultMajorVersion = 3;
+  defaultMinorVersion = 8;
+  if (rfb::Server::protocol3_3)
+    defaultMinorVersion = 3;
+
+  cp.setVersion(defaultMajorVersion, defaultMinorVersion);
+}
+
+SConnection::~SConnection()
+{
+  if (security) security->destroy();
+  deleteReaderAndWriter();
+}
+
+void SConnection::deleteReaderAndWriter()
+{
+  delete reader_;
+  reader_ = 0;
+  delete writer_;
+  writer_ = 0;
+}
+
+void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
+{
+  is = is_;
+  os = os_;
+}
+
+void SConnection::initialiseProtocol()
+{
+  cp.writeVersion(os);
+  state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void SConnection::processMsg()
+{
+  switch (state_) {
+  case RFBSTATE_PROTOCOL_VERSION: processVersionMsg();      break;
+  case RFBSTATE_SECURITY_TYPE:    processSecurityTypeMsg(); break;
+  case RFBSTATE_SECURITY:         processSecurityMsg();     break;
+  case RFBSTATE_INITIALISATION:   processInitMsg();         break;
+  case RFBSTATE_NORMAL:           reader_->readMsg();       break;
+  case RFBSTATE_QUERYING:
+    throw Exception("SConnection::processMsg: bogus data from client while "
+                    "querying");
+  case RFBSTATE_UNINITIALISED:
+    throw Exception("SConnection::processMsg: not initialised yet?");
+  default:
+    throw Exception("SConnection::processMsg: invalid state");
+  }
+}
+
+void SConnection::processVersionMsg()
+{
+  vlog.debug("reading protocol version");
+  bool done;
+  if (!cp.readVersion(is, &done)) {
+    state_ = RFBSTATE_INVALID;
+    throw Exception("reading version failed: not an RFB client?");
+  }
+  if (!done) return;
+
+  vlog.info("Client needs protocol version %d.%d",
+            cp.majorVersion, cp.minorVersion);
+
+  if (cp.majorVersion != 3) {
+    // unknown protocol version
+    char msg[256];
+    sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
+            cp.majorVersion, cp.minorVersion,
+            defaultMajorVersion, defaultMinorVersion);
+    throwConnFailedException(msg);
+  }
+
+  if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
+    vlog.error("Client uses unofficial protocol version %d.%d",
+               cp.majorVersion,cp.minorVersion);
+    if (cp.minorVersion >= 8)
+      cp.minorVersion = 8;
+    else if (cp.minorVersion == 7)
+      cp.minorVersion = 7;
+    else
+      cp.minorVersion = 3;
+    vlog.error("Assuming compatibility with version %d.%d",
+               cp.majorVersion,cp.minorVersion);
+  }
+
+  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.
+    for (i=secTypes.begin(); i!=secTypes.end(); i++) {
+      if (*i == secTypeNone || *i == secTypeVncAuth) break;
+    }
+    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(*i);
+    if (*i == secTypeNone) os->flush();
+    state_ = RFBSTATE_SECURITY;
+    security = securityFactory->getSSecurity(*i, reverseConnection);
+    processSecurityMsg();
+    return;
+  }
+
+  // list supported security types for >=3.7 clients
+
+  if (secTypes.empty())
+    throwConnFailedException("No supported security types");
+
+  os->writeU8(secTypes.size());
+  for (i=secTypes.begin(); i!=secTypes.end(); i++)
+    os->writeU8(*i);
+  os->flush();
+  state_ = RFBSTATE_SECURITY_TYPE;
+}
+
+
+void SConnection::processSecurityTypeMsg()
+{
+  vlog.debug("processing security type message");
+  int secType = is->readU8();
+
+  // Verify that the requested security type should be offered
+  std::list<rdr::U8> secTypes;
+  std::list<rdr::U8>::iterator i;
+  securityFactory->getSecTypes(&secTypes, reverseConnection);
+  for (i=secTypes.begin(); i!=secTypes.end(); i++)
+    if (*i == secType) break;
+  if (i == secTypes.end())
+    throw Exception("Requested security type not available");
+
+  vlog.info("Client requests security type %s(%d)",
+            secTypeName(secType),secType);
+
+  try {
+    state_ = RFBSTATE_SECURITY;
+    security = securityFactory->getSSecurity(secType, reverseConnection);
+  } catch (rdr::Exception& e) {
+    throwConnFailedException(e.str());
+  }
+
+  processSecurityMsg();
+}
+
+void SConnection::processSecurityMsg()
+{
+  vlog.debug("processing security message");
+  try {
+    bool done = security->processMsg(this);
+    if (done) {
+      state_ = RFBSTATE_QUERYING;
+      queryConnection(security->getUserName());
+    }
+  } 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;
+  }
+}
+
+void SConnection::processInitMsg()
+{
+  vlog.debug("reading client initialisation");
+  reader_->readClientInit();
+}
+
+void SConnection::throwConnFailedException(const char* msg)
+{
+  vlog.info(msg);
+  if (state_ == RFBSTATE_PROTOCOL_VERSION) {
+    if (cp.majorVersion == 3 && cp.minorVersion == 3) {
+      os->writeU32(0);
+      os->writeString(msg);
+      os->flush();
+    } else {
+      os->writeU8(0);
+      os->writeString(msg);
+      os->flush();
+    }
+  }
+  state_ = RFBSTATE_INVALID;
+  throw ConnFailedException(msg);
+}
+
+void SConnection::writeConnFailedFromScratch(const char* msg,
+                                             rdr::OutStream* os)
+{
+  os->writeBytes("RFB 003.003\n", 12);
+  os->writeU32(0);
+  os->writeString(msg);
+  os->flush();
+}
+
+void SConnection::versionReceived()
+{
+}
+
+void SConnection::authSuccess()
+{
+}
+
+void SConnection::queryConnection(const char* userName)
+{
+  approveConnection(true);
+}
+
+void SConnection::approveConnection(bool accept, const char* reason)
+{
+  if (state_ != RFBSTATE_QUERYING)
+    throw Exception("SConnection::approveConnection: invalid state");
+
+  if (!reason) reason = "Authentication failure";
+
+  if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
+    if (accept) {
+      os->writeU32(secResultOK);
+    } else {
+      os->writeU32(secResultFailed);
+      if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+        os->writeString(reason);
+    }
+    os->flush();
+  }
+
+  if (accept) {
+    state_ = RFBSTATE_INITIALISATION;
+    reader_ = new SMsgReaderV3(this, is);
+    writer_ = new SMsgWriterV3(&cp, os);
+    authSuccess();
+  } else {
+    state_ = RFBSTATE_INVALID;
+    throw AuthFailureException(reason);
+  }
+}
+
+void SConnection::setInitialColourMap()
+{
+}
+
+void SConnection::clientInit(bool shared)
+{
+  writer_->writeServerInit();
+  state_ = RFBSTATE_NORMAL;
+}
+
+void SConnection::setPixelFormat(const PixelFormat& pf)
+{
+  SMsgHandler::setPixelFormat(pf);
+  readyForSetColourMapEntries = true;
+}
+
+void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
+{
+  if (!readyForSetColourMapEntries) {
+    readyForSetColourMapEntries = true;
+    if (!cp.pf().trueColour) {
+      setInitialColourMap();
+    }
+  }
+}
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
new file mode 100644
index 0000000..6b943f5
--- /dev/null
+++ b/common/rfb/SConnection.h
@@ -0,0 +1,193 @@
+/* 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.
+ */
+//
+// SConnection - class on the server side representing a connection to a
+// client.  A derived class should override methods appropriately.
+//
+
+#ifndef __RFB_SCONNECTION_H__
+#define __RFB_SCONNECTION_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/SMsgHandler.h>
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+  class SMsgReader;
+  class SMsgWriter;
+  class SSecurity;
+
+  class SConnection : public SMsgHandler {
+  public:
+
+    SConnection(SSecurityFactory* sf, bool reverseConnection_);
+    virtual ~SConnection();
+
+    // Methods to initialise the connection
+
+    // setStreams() sets the streams to be used for the connection.  These must
+    // be set before initialiseProtocol() and processMsg() are called.  The
+    // SSecurity object may call setStreams() again to provide alternative
+    // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+    // streams).  Ownership of the streams remains with the caller
+    // (i.e. SConnection will not delete them).
+    void setStreams(rdr::InStream* is, rdr::OutStream* os);
+
+    // 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.
+    void initialiseProtocol();
+
+    // processMsg() should be called whenever there is data to read on the
+    // InStream.  You must have called initialiseProtocol() first.
+    void processMsg();
+
+    // approveConnection() is called to either accept or reject the connection.
+    // If accept is false, the reason string gives the reason for the
+    // rejection.  It can either be called directly from queryConnection() or
+    // later, after queryConnection() has returned.  It can only be called when
+    // in state RFBSTATE_QUERYING.  On rejection, an AuthFailureException is
+    // thrown, so this must be handled appropriately by the caller.
+    void approveConnection(bool accept, const char* reason=0);
+
+
+    // Methods to be overridden in a derived class
+
+    // versionReceived() indicates that the version number has just been read
+    // from the client.  The version will already have been "cooked"
+    // to deal with unknown/bogus viewer protocol numbers.
+    virtual void versionReceived();
+
+    // authSuccess() is called when authentication has succeeded.
+    virtual void authSuccess();
+
+    // 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
+    // is the name of the user making the connection, or null (note that the
+    // storage for userName is owned by the caller).  The connection must be
+    // accepted or rejected by calling approveConnection(), either directly
+    // from queryConnection() or some time later.
+    virtual void queryConnection(const char* userName);
+
+    // clientInit() is called when the ClientInit message is received.  The
+    // derived class must call on to SConnection::clientInit().
+    virtual void clientInit(bool shared);
+
+    // setPixelFormat() is called when a SetPixelFormat message is received.
+    // The derived class must call on to SConnection::setPixelFormat().
+    virtual void setPixelFormat(const PixelFormat& pf);
+
+    // framebufferUpdateRequest() is called when a FramebufferUpdateRequest
+    // message is received.  The derived class must call on to
+    // SConnection::framebufferUpdateRequest().
+    virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+
+    // setInitialColourMap() is called when the client needs an initial
+    // SetColourMapEntries message.  In fact this only happens when the client
+    // accepts the server's default pixel format and it uses a colour map.
+    virtual void setInitialColourMap();
+
+    // setAccessRights() allows a security package to limit the access rights
+    // of a VNCSConnectionST to the server.  How the access rights are treated
+    // is up to the derived class.
+
+    typedef rdr::U16 AccessRights;
+    static const AccessRights AccessView;         // View display contents
+    static const AccessRights AccessKeyEvents;    // Send key events
+    static const AccessRights AccessPtrEvents;    // Send pointer events
+    static const AccessRights AccessCutText;      // Send/receive clipboard events
+    static const AccessRights AccessDefault;      // The default rights, INCLUDING FUTURE ONES
+    static const AccessRights AccessNoQuery;      // Connect without local user accepting
+    static const AccessRights AccessFull;         // All of the available AND FUTURE rights
+    virtual void setAccessRights(AccessRights ar) = 0;
+
+    // Other methods
+
+    // authenticated() returns true if the client has authenticated
+    // successfully.
+    bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
+                                   state_ == RFBSTATE_NORMAL); }
+
+    // deleteReaderAndWriter() deletes the reader and writer associated with
+    // this connection.  This may be useful if you want to delete the streams
+    // before deleting the SConnection to make sure that no attempt by the
+    // SConnection is made to read or write.
+    // XXX Do we really need this at all???
+    void deleteReaderAndWriter();
+
+    // throwConnFailedException() prints a message to the log, sends a conn
+    // failed message to the client (if possible) and throws a
+    // ConnFailedException.
+    void throwConnFailedException(const char* msg);
+
+    // writeConnFailedFromScratch() sends a conn failed message to an OutStream
+    // without the need to negotiate the protocol version first.  It actually
+    // does this by assuming that the client will understand version 3.3 of the
+    // protocol.
+    static void writeConnFailedFromScratch(const char* msg,
+                                           rdr::OutStream* os);
+
+    SMsgReader* reader() { return reader_; }
+    SMsgWriter* writer() { return writer_; }
+
+    rdr::InStream* getInStream() { return is; }
+    rdr::OutStream* getOutStream() { return os; }
+
+    enum stateEnum {
+      RFBSTATE_UNINITIALISED,
+      RFBSTATE_PROTOCOL_VERSION,
+      RFBSTATE_SECURITY_TYPE,
+      RFBSTATE_SECURITY,
+      RFBSTATE_QUERYING,
+      RFBSTATE_INITIALISATION,
+      RFBSTATE_NORMAL,
+      RFBSTATE_CLOSING,
+      RFBSTATE_INVALID
+    };
+
+    stateEnum state() { return state_; }
+
+    // ssecurity() returns a pointer to this connection's SSecurity object, if
+    // any
+    const SSecurity* ssecurity() const { return security; }
+
+  protected:
+    void setState(stateEnum s) { state_ = s; }
+
+    bool readyForSetColourMapEntries;
+
+    void processVersionMsg();
+    void processSecurityTypeMsg();
+    void processSecurityMsg();
+    void processInitMsg();
+
+    int defaultMajorVersion, defaultMinorVersion;
+    rdr::InStream* is;
+    rdr::OutStream* os;
+    SMsgReader* reader_;
+    SMsgWriter* writer_;
+    SSecurity* security;
+    SSecurityFactory* securityFactory;
+    stateEnum state_;
+    bool reverseConnection;
+  };
+}
+#endif
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
new file mode 100644
index 0000000..7b054e3
--- /dev/null
+++ b/common/rfb/SDesktop.h
@@ -0,0 +1,121 @@
+/* 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.
+ */
+
+/////////////////////////////////////////////////////////////////////////////
+
+// SDesktop is an interface implemented by back-ends, on which callbacks are
+// made by the VNCServer as appropriate for pointer and keyboard events, etc.
+// SDesktop objects are always created before the VNCServer - the SDesktop
+// will be passed a pointer to the VNCServer in the start() call.  If a more
+// implementation-specific pointer to the VNCServer is required then this
+// can be provided to the SDesktop via an implementation-specific method.
+//
+// An SDesktop usually has an associated PixelBuffer which it tells the
+// VNCServer via the VNCServer's setPixelBuffer() method.  It can do this at
+// any time, but the PixelBuffer MUST be valid by the time the call to start()
+// returns.  The PixelBuffer may be set to null again if desired when stop() is
+// called.  Note that start() and stop() are guaranteed to be called
+// alternately; there should never be two calls to start() without an
+// intervening stop() and vice-versa.
+//
+
+#ifndef __RFB_SDESKTOP_H__
+#define __RFB_SDESKTOP_H__
+
+#include <rfb/PixelBuffer.h>
+#include <rfb/VNCServer.h>
+#include <rfb/InputHandler.h>
+#include <rfb/Exception.h>
+
+namespace rfb {
+
+  class VNCServer;
+
+  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
+    // needed when there are no clients.  A valid PixelBuffer must have been
+    // set via the VNCServer's setPixelBuffer() method by the time this call
+    // returns.
+
+    virtual void start(VNCServer* vs) {}
+
+    // stop() is called by the server when there are no longer any
+    // authenticated clients, and therefore the desktop can cease any
+    // expensive tasks.  No further calls to the VNCServer passed to start()
+    // can be made once stop has returned.
+
+    virtual void stop() {}
+
+    // 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
+    // clientsReadyForUpdate() method.
+
+    virtual void framebufferUpdateRequest() {}
+
+    // getFbSize() returns the current dimensions of the framebuffer.
+    // This can be called even while the SDesktop is not start()ed.
+
+    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() {}
+  };
+
+  // -=- SStaticDesktop
+  //     Trivial implementation of the SDesktop interface, which provides
+  //     dummy input handlers and event processing routine, and exports
+  //     a plain black desktop of the specified format.
+  class SStaticDesktop : public SDesktop {
+  public:
+    SStaticDesktop(const Point& size) : server(0), buffer(0) {
+      PixelFormat pf;
+      buffer = new ManagedPixelBuffer(pf, size.x, size.y);
+      if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y));
+    }
+    SStaticDesktop(const Point& size, const PixelFormat& pf) : buffer(0) {
+      buffer = new ManagedPixelBuffer(pf, size.x, size.y);
+      if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y));
+    }
+    virtual ~SStaticDesktop() {
+      if (buffer) delete buffer;
+    }
+
+    virtual void start(VNCServer* vs) {
+      server = vs;
+      server->setPixelBuffer(buffer);
+    }
+    virtual void stop() {
+      server->setPixelBuffer(0);
+      server = 0;
+    }
+
+  protected:
+    VNCServer* server;
+    ManagedPixelBuffer* buffer;
+  };
+
+};
+
+#endif // __RFB_SDESKTOP_H__
diff --git a/common/rfb/SFTMsgReader.cxx b/common/rfb/SFTMsgReader.cxx
new file mode 100644
index 0000000..22787bf
--- /dev/null
+++ b/common/rfb/SFTMsgReader.cxx
@@ -0,0 +1,201 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgReader.cxx
+
+#include <rfb/SFTMsgReader.h>
+
+using namespace rfb;
+
+SFTMsgReader::SFTMsgReader(rdr::InStream *pIS)
+{
+  m_pIS = pIS;
+}
+
+SFTMsgReader::~SFTMsgReader()
+{
+}
+    
+bool 
+SFTMsgReader::readFileListRqst(unsigned int *pDirNameSize, char *pDirName, 
+                               unsigned int *pFlags)
+{
+  *pFlags = m_pIS->readU8();
+  unsigned int dirNameSize = m_pIS->readU16();
+
+  if (dirNameSize >= FT_FILENAME_SIZE) {
+    m_pIS->skip(dirNameSize);
+    return false;
+  } else {
+    m_pIS->readBytes(pDirName, dirNameSize);
+    *pDirNameSize = dirNameSize;
+    pDirName[dirNameSize] = '\0';
+    return true;
+  }
+}
+    
+bool 
+SFTMsgReader::readFileDownloadRqst(unsigned int *pFilenameSize, char *pFilename, 
+                                   unsigned int *pPosition)
+{
+  unsigned char compressedLevel = 0;
+  return readU8U16U32StringMsg(&compressedLevel, pFilenameSize, pPosition, pFilename);
+}
+
+bool 
+SFTMsgReader::readFileUploadRqst(unsigned int *pFilenameSize, char *pFilename, 
+                                 unsigned int *pPosition)
+{
+  unsigned char compressedLevel = 0;
+  return readU8U16U32StringMsg(&compressedLevel, pFilenameSize, pPosition, pFilename);
+}
+    
+char *
+SFTMsgReader::readFileUploadData(unsigned int *pDataSize, unsigned int *pModTime)
+{
+  unsigned char compressedLevel = m_pIS->readU8();
+  unsigned int realSize = m_pIS->readU16();
+  unsigned int compressedSize = m_pIS->readU16();
+
+  if ((realSize == 0) && (compressedSize == 0)) {
+    *pDataSize = 0;
+    *pModTime = m_pIS->readU32();
+    return NULL;
+  } else {
+    char *pData = new char [compressedSize];
+    m_pIS->readBytes(pData, compressedSize);
+    *pDataSize = compressedSize;
+    *pModTime = 0;
+    return pData;
+  }
+}
+    
+bool 
+SFTMsgReader::readFileCreateDirRqst(unsigned int *pDirNameSize, char *pDirName)
+{
+  return readU8U16StringMsg(pDirNameSize, pDirName);
+}
+
+bool 
+SFTMsgReader::readFileDirSizeRqst(unsigned int *pDirNameSize, char *pDirName)
+{
+  return readU8U16StringMsg(pDirNameSize, pDirName);
+}
+
+bool 
+SFTMsgReader::readFileDeleteRqst(unsigned int *pNameSize, char *pName)
+{
+  return readU8U16StringMsg(pNameSize, pName);
+}
+    
+bool 
+SFTMsgReader::readFileRenameRqst(unsigned int *pOldNameSize, 
+                                 unsigned int *pNewNameSize,
+                                 char *pOldName, char *pNewName)
+{
+  m_pIS->skip(1);
+
+  unsigned int oldNameSize = m_pIS->readU16();
+  unsigned int newNameSize = m_pIS->readU16();
+
+  if ((oldNameSize >= *pOldNameSize) || (newNameSize >= *pNewNameSize)) {
+    m_pIS->skip(oldNameSize);
+    m_pIS->skip(newNameSize);
+    return false;
+  }
+
+  if (oldNameSize != 0) {
+    m_pIS->readBytes(pOldName, oldNameSize);
+    pOldName[oldNameSize] = '\0';
+    *pOldNameSize = oldNameSize;
+  } else {
+    *pOldNameSize = 0;
+    pOldName[0] = '\0';
+  }
+
+  if (newNameSize != 0) {
+    m_pIS->readBytes(pNewName, newNameSize);
+    pNewName[newNameSize] = '\0';
+  } else {
+    *pNewNameSize = 0;
+    pNewName[0] = '\0';
+  }
+
+  return true;
+}
+
+bool
+SFTMsgReader::readFileDownloadCancel(unsigned int *pReasonSize, char *pReason)
+{
+  return readU8U16StringMsg(pReasonSize, pReason);
+}
+
+bool
+SFTMsgReader::readFileUploadFailed(unsigned int *pReasonSize, char *pReason)
+{
+  return readU8U16StringMsg(pReasonSize, pReason);
+}
+
+bool 
+SFTMsgReader::readU8U16StringMsg(unsigned int *pReasonSize, char *pReason)
+{
+  m_pIS->skip(1);
+  unsigned int reasonSize = m_pIS->readU16();
+
+  if (reasonSize >= FT_FILENAME_SIZE) {
+    m_pIS->skip(reasonSize);
+    return false;
+  } else {
+    if (reasonSize == 0) {
+      pReason[0] = '\0';
+    } else {
+      m_pIS->readBytes(pReason, reasonSize);
+      pReason[reasonSize] = '\0';
+    }
+      *pReasonSize = reasonSize;
+    return true;
+  }
+}
+
+bool 
+SFTMsgReader::readU8U16U32StringMsg(unsigned char *pU8, unsigned int *pU16, 
+                                    unsigned int *pU32, char *pString)
+{
+  *pU8 = m_pIS->readU8();
+  unsigned int strSize = m_pIS->readU16();
+  *pU32 = m_pIS->readU32();
+
+  if (strSize >= FT_FILENAME_SIZE) {
+    m_pIS->skip(strSize);
+    return false;
+  } else {
+    *pU16 = strSize;
+    if (strSize == 0) {
+      pString[0] = '\0';
+    } else {
+      m_pIS->readBytes(pString, strSize);
+      pString[strSize] = '\0';
+    }
+    return true;
+  }
+}
diff --git a/common/rfb/SFTMsgReader.h b/common/rfb/SFTMsgReader.h
new file mode 100644
index 0000000..32ac869
--- /dev/null
+++ b/common/rfb/SFTMsgReader.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgReader.h
+
+#ifndef __RFB_SFTMSGREADER_H__
+#define __RFB_SFTMSGREADER_H__
+
+#include <rdr/InStream.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class SFTMsgReader
+  {
+  public:
+    SFTMsgReader(rdr::InStream *pIS);
+    ~SFTMsgReader();
+    
+    bool readFileListRqst(unsigned int *pDirNameSize, char *pDirName, 
+                          unsigned int *pFlags);
+    
+    
+    bool readFileDownloadRqst(unsigned int *pFilenameSize, char *pFilename, 
+                              unsigned int *pPosition);
+
+    bool readFileUploadRqst(unsigned int *pFilenameSize, char *pFilename, 
+                            unsigned int *pPosition);
+    
+    char *readFileUploadData(unsigned int *pDataSize, unsigned int *pModTime);
+
+    
+    bool readFileCreateDirRqst(unsigned int *pDirNameSize, char *pDirName);
+    bool readFileDirSizeRqst(unsigned int *pDirNameSize, char *pDirName);
+    bool readFileDeleteRqst(unsigned int *pNameSize, char *pName);
+    
+    bool readFileRenameRqst(unsigned int *pOldNameSize, unsigned int *pNewNameSize,
+                            char *pOldName, char *pNewName);
+
+    bool readFileDownloadCancel(unsigned int *pReasonSize, char *pReason);
+    bool readFileUploadFailed(unsigned int *pReasonSize, char *pReason);
+
+  private:
+    rdr::InStream *m_pIS;
+
+    bool readU8U16StringMsg(unsigned int *pReasonSize, char *pReason);
+    bool readU8U16U32StringMsg(unsigned char *pU8, unsigned int *pU16, 
+                               unsigned int *pU32, char *pString);
+  };
+}
+
+#endif // __RFB_SFTMSGREADER_H__
diff --git a/common/rfb/SFTMsgWriter.cxx b/common/rfb/SFTMsgWriter.cxx
new file mode 100644
index 0000000..fa6a82f
--- /dev/null
+++ b/common/rfb/SFTMsgWriter.cxx
@@ -0,0 +1,152 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgWriter.cxx
+
+#include <rfb/SFTMsgWriter.h>
+
+using namespace rfb;
+
+SFTMsgWriter::SFTMsgWriter(rdr::OutStream *pOS)
+{
+  m_pOS = pOS;
+}
+
+SFTMsgWriter::~SFTMsgWriter()
+{
+}
+    
+bool 
+SFTMsgWriter::writeFileListData(unsigned char flags, rfb::FileInfo *pFileInfo)
+{
+  unsigned int numFiles = pFileInfo->getNumEntries();
+
+  m_pOS->writeU8(msgTypeFileListData);
+  m_pOS->writeU8(flags);
+  m_pOS->writeU16(numFiles);
+  
+  if (numFiles == 0) {
+    m_pOS->writeU16(0);
+    m_pOS->writeU16(0);
+  } else {
+    unsigned int filenamesSize = pFileInfo->getFilenamesSize() + numFiles;
+
+    m_pOS->writeU16(filenamesSize);
+    m_pOS->writeU16(filenamesSize);
+
+    char *pFilenames = new char [filenamesSize];
+    unsigned int pos = 0;
+
+    for (unsigned int i = 0; i < numFiles; i++) {
+      char *pName = pFileInfo->getNameAt(i);
+      unsigned int len = strlen(pName);
+
+      memcpy((void *)&pFilenames[pos], pName, len + 1);
+      pos += (len + 1);
+
+      if (pFileInfo->getFlagsAt(i) & FT_ATTR_DIR) {
+        m_pOS->writeU32(FT_NET_ATTR_DIR);
+      } else {
+        m_pOS->writeU32(pFileInfo->getSizeAt(i));
+      }
+      m_pOS->writeU32(pFileInfo->getDataAt(i));
+    }
+
+    m_pOS->writeBytes(pFilenames, filenamesSize);
+
+    delete [] pFilenames;
+  }
+
+  m_pOS->flush();
+
+  return true;
+}
+
+bool 
+SFTMsgWriter::writeFileDownloadData(unsigned int dataSize, void *pData)
+{
+  m_pOS->writeU8(msgTypeFileDownloadData);
+  m_pOS->writeU8(0);
+  m_pOS->writeU16(dataSize);
+  m_pOS->writeU16(dataSize);
+  m_pOS->writeBytes(pData, dataSize);
+  m_pOS->flush();
+  return true;
+}
+
+bool 
+SFTMsgWriter::writeFileDownloadData(unsigned int modTime)
+{
+  m_pOS->writeU8(msgTypeFileDownloadData);
+  m_pOS->writeU8(0);
+  m_pOS->writeU16(0);
+  m_pOS->writeU16(0);
+  m_pOS->writeU32(modTime);
+  m_pOS->flush();
+  return true;
+}
+
+bool
+SFTMsgWriter::writeFileUploadCancel(unsigned int reasonLen, char *pReason)
+{
+  m_pOS->writeU8(msgTypeFileUploadCancel);
+  return writeU8U16StringMsg(0, reasonLen, pReason);
+}
+
+bool 
+SFTMsgWriter::writeFileDownloadFailed(unsigned int reasonLen, char *pReason)
+{
+  m_pOS->writeU8(msgTypeFileDownloadFailed);
+  return writeU8U16StringMsg(0, reasonLen, pReason);
+}
+
+bool 
+SFTMsgWriter::writeFileDirSizeData(unsigned int dirSizeLow, 
+                                   unsigned short dirSizeHigh)
+{
+  m_pOS->writeU8(msgTypeFileDirSizeData);
+  m_pOS->writeU8(0);
+  m_pOS->writeU16(dirSizeHigh);
+  m_pOS->writeU32(dirSizeLow);
+  m_pOS->flush();
+  return true;
+}
+
+bool 
+SFTMsgWriter::writeFileLastRqstFailed(unsigned char lastRequest, 
+                                      unsigned short reasonLen,
+                                      char *pReason)
+{
+  m_pOS->writeU8(msgTypeFileLastRequestFailed);
+  return writeU8U16StringMsg(lastRequest, reasonLen, pReason);
+}
+
+bool
+SFTMsgWriter::writeU8U16StringMsg(unsigned char p1, unsigned short p2, char *pP3)
+{
+  m_pOS->writeU8(p1);
+  m_pOS->writeU16(p2);
+  m_pOS->writeBytes(pP3, p2);
+  m_pOS->flush();
+  return true;
+}
diff --git a/common/rfb/SFTMsgWriter.h b/common/rfb/SFTMsgWriter.h
new file mode 100644
index 0000000..f6bea9f
--- /dev/null
+++ b/common/rfb/SFTMsgWriter.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFTMsgWriter.h
+
+#ifndef __RFB_SFTMSGWRITER_H__
+#define __RFB_SFTMSGWRITER_H__
+
+#include <rdr/OutStream.h>
+#include <rfb/FileInfo.h>
+#include <rfb/msgTypes.h>
+
+namespace rfb {
+  class SFTMsgWriter
+  {
+  public:
+    SFTMsgWriter(rdr::OutStream *pOS);
+    ~SFTMsgWriter();
+    
+    bool writeFileListData(unsigned char flags, rfb::FileInfo *pFileInfo);
+    bool writeFileDownloadData(unsigned int dataSize, void *pData);
+    bool writeFileDownloadData(unsigned int modTime);
+    bool writeFileUploadCancel(unsigned int reasonLen, char *pReason);
+    bool writeFileDownloadFailed(unsigned int reasonLen, char *pReason);
+    bool writeFileDirSizeData(unsigned int dirSizeLow, unsigned short dirSizeHigh);
+    bool writeFileLastRqstFailed(unsigned char lastRequest, unsigned short reasonLen, 
+                                 char *pReason);
+
+  private:
+    rdr::OutStream *m_pOS;
+
+    bool writeU8U16StringMsg(unsigned char p1, unsigned short p2, char *pP3);
+  };
+}
+
+#endif // __RFB_SFTMSGWRITER_H__
diff --git a/common/rfb/SFileTransfer.cxx b/common/rfb/SFileTransfer.cxx
new file mode 100644
index 0000000..957e50b
--- /dev/null
+++ b/common/rfb/SFileTransfer.cxx
@@ -0,0 +1,335 @@
+/* Copyright (C) 2006 TightVNC Team.  All Rights Reserved.
+ *    
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransfer.cxx
+
+#include <rfb/msgTypes.h>
+#include <rfb/SFileTransfer.h>
+
+using namespace rfb;
+
+SFileTransfer::SFileTransfer(network::Socket *sock) : 
+  m_bUploadStarted(false), m_bDownloadStarted(false),
+  m_reader(&sock->inStream()), m_writer(&sock->outStream()), m_pSocket(sock)
+{
+}
+
+SFileTransfer::~SFileTransfer()
+{
+}
+
+bool
+SFileTransfer::processMessages(int type)
+{
+  switch(type)
+  {
+    case msgTypeFileListRequest:
+      return processFileListRequest();
+    case msgTypeFileDownloadRequest:
+      return processFileDownloadRequest();
+    case msgTypeFileUploadRequest:
+      return processFileUploadRequest();
+    case msgTypeFileUploadData:
+      return processFileUploadData();
+    case msgTypeFileDownloadCancel:
+      return processFileDownloadCancel();
+    case msgTypeFileUploadFailed:
+      return processFileUploadFailed();
+    case msgTypeFileCreateDirRequest:
+      return processFileCreateDirRequest();
+    case msgTypeFileDirSizeRequest:
+      return processFileDirSizeRequest();
+    case msgTypeFileRenameRequest:
+      return processFileRenameRequest();
+    case msgTypeFileDeleteRequest:
+      return processFileDeleteRequest();
+    default:
+      return false;
+  }
+}
+
+bool 
+SFileTransfer::processFileListRequest()
+{
+  char szDirName[FT_FILENAME_SIZE] = {0};
+  unsigned int dirNameSize = FT_FILENAME_SIZE;
+  unsigned int flags = 0;
+
+  if (!m_reader.readFileListRqst(&dirNameSize, szDirName, &flags)) return false;
+
+  if (!convertPathFromNet(szDirName)) return false;
+
+  bool bDirOnly = false;
+  if (flags & 0x10) bDirOnly = true;
+
+  FileInfo fi;
+  if (!makeFileList(szDirName, &fi, bDirOnly)) {
+    flags = (flags | 0x80);  
+  }
+  return m_writer.writeFileListData((unsigned char)flags, &fi);
+}
+
+bool 
+SFileTransfer::processFileDownloadRequest()
+{
+  char szName[FT_FILENAME_SIZE] = {0};
+  unsigned int nameSize = FT_FILENAME_SIZE;
+  unsigned int position = 0;
+
+  if (!m_reader.readFileDownloadRqst(&nameSize, szName, &position)) return false;
+
+  if (!convertPathFromNet(szName)) return false;
+
+  if (m_bDownloadStarted) {
+    char reason[] = "The download is already started";
+    m_writer.writeFileLastRqstFailed(msgTypeFileDownloadRequest, strlen(reason), reason);
+    return false;
+  }
+
+  if (!m_fileReader.create(szName)) return false;
+
+  m_bDownloadStarted = true;
+
+  sendFileDownloadPortion();
+
+  return true;
+}
+
+bool
+SFileTransfer::sendFileDownloadPortion()
+{
+  char buffer[FT_MAX_SENDING_SIZE];
+  unsigned int bytesRead = 0;
+
+  if (m_fileReader.read((void *)buffer, FT_MAX_SENDING_SIZE, &bytesRead)) {
+    if (bytesRead == 0) {
+      m_writer.writeFileDownloadData(m_fileReader.getTime());
+      m_fileReader.close();
+      m_bDownloadStarted = false;
+      return true;
+    } else {
+      m_writer.writeFileDownloadData(bytesRead, buffer);
+      return initDownloadCallback();
+    }
+  } else {
+    char reason[] = "Error while reading from file";
+    m_writer.writeFileDownloadFailed(strlen(reason), reason);
+    m_fileReader.close();
+    m_bDownloadStarted = false;
+    return true;
+  }
+}
+
+bool 
+SFileTransfer::processFileUploadRequest()
+{
+  char szName[FT_FILENAME_SIZE] = {0};
+  unsigned int nameSize = FT_FILENAME_SIZE;
+  unsigned int position = 0;
+
+  if (!m_reader.readFileUploadRqst(&nameSize, szName, &position)) return false;
+
+  if (!convertPathFromNet(szName)) return false;
+
+  if (m_bUploadStarted) {
+    char reason[] = "The upload is already started";
+    m_writer.writeFileLastRqstFailed(msgTypeFileUploadRequest, strlen(reason), reason);
+    return false;
+  }
+
+  if (!m_fileWriter.create(szName)) {
+    char reason[] = "Can't create local file";
+    m_writer.writeFileLastRqstFailed(msgTypeFileUploadRequest, strlen(reason), reason);
+    return true;
+  }
+
+  m_bUploadStarted = true;
+
+  return true;
+}
+
+bool 
+SFileTransfer::processFileUploadData()
+{
+  unsigned int dataSize = 0;
+  unsigned int modTime = 0;
+
+  char *pUploadData = m_reader.readFileUploadData(&dataSize, &modTime);
+
+  if (!m_bUploadStarted) {
+      char reason[] = "Upload is impossible";
+      m_writer.writeFileUploadCancel(strlen(reason), reason);
+  } else {
+    if (pUploadData == NULL) {
+      if (modTime == 0) {
+        char reason[] = "Upload failed";
+        m_writer.writeFileUploadCancel(strlen(reason), reason);
+      } else {
+        m_fileWriter.setTime(modTime);
+      }
+      m_fileWriter.close();
+      m_bUploadStarted = false;
+    } else {
+      unsigned int dataWritten = 0;
+      m_fileWriter.write(pUploadData, dataSize, &dataWritten);
+      if (dataWritten != dataSize) {
+        char reason[] = "Upload failed";
+        m_writer.writeFileUploadCancel(strlen(reason), reason);
+        m_fileWriter.close();
+        m_bUploadStarted = false;
+      }
+    }
+  }
+  delete [] pUploadData;
+  return true;
+}
+
+bool 
+SFileTransfer::processFileDownloadCancel()
+{
+  char szReason[FT_FILENAME_SIZE] = {0};
+  unsigned int reasonSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileDownloadCancel(&reasonSize, szReason)) return false;
+
+  m_fileReader.close();
+  m_bDownloadStarted = false;
+  return true;
+}
+
+bool 
+SFileTransfer::processFileUploadFailed()
+{
+  char szReason[FT_FILENAME_SIZE] = {0};
+  unsigned int reasonSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileUploadFailed(&reasonSize, szReason)) return false;
+
+  deleteIt(m_fileWriter.getFilename());
+  m_fileWriter.close();
+  m_bUploadStarted = false;
+  return true;
+}
+
+bool 
+SFileTransfer::processFileCreateDirRequest()
+{
+  char szName[FT_FILENAME_SIZE] = {0};
+  unsigned int nameSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileCreateDirRqst(&nameSize, szName)) return false;
+
+  if (!convertPathFromNet(szName)) return false;
+
+  return createDir(szName);
+}
+
+bool 
+SFileTransfer::processFileDirSizeRequest()
+{
+  char szName[FT_FILENAME_SIZE] = {0};
+  unsigned int nameSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileDirSizeRqst(&nameSize, szName)) return false;
+
+  if (!convertPathFromNet(szName)) return false;
+
+  unsigned short highSize16 = 0;
+  unsigned int lowSize32 = 0;
+
+  if (!getDirSize(szName, &highSize16, &lowSize32)) return false;
+
+  return m_writer.writeFileDirSizeData(lowSize32, highSize16);
+}
+
+bool 
+SFileTransfer::processFileRenameRequest()
+{
+  char szOldName[FT_FILENAME_SIZE] = {0};
+  char szNewName[FT_FILENAME_SIZE] = {0};
+
+  unsigned int oldNameSize = FT_FILENAME_SIZE;
+  unsigned int newNameSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileRenameRqst(&oldNameSize, &newNameSize, szOldName, szNewName)) return false;
+
+  if ((!convertPathFromNet(szOldName)) || (!convertPathFromNet(szNewName))) return false;
+
+  return renameIt(szOldName, szNewName);
+}
+
+bool 
+SFileTransfer::processFileDeleteRequest()
+{
+  char szName[FT_FILENAME_SIZE] = {0};
+  unsigned int nameSize = FT_FILENAME_SIZE;
+
+  if (!m_reader.readFileDeleteRqst(&nameSize, szName)) return false;
+
+  if (!convertPathFromNet(szName)) return false;
+
+  return deleteIt(szName);
+}
+
+bool 
+SFileTransfer::convertPathFromNet(char *pszPath)
+{
+  return true;
+}
+
+bool 
+SFileTransfer::makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly)
+{
+  return false;
+}
+
+bool 
+SFileTransfer::deleteIt(char *pszPath)
+{
+  return false;
+}
+
+bool 
+SFileTransfer::renameIt(char *pszOldPath, char *pszNewPath)
+{
+  return false;
+}
+
+bool 
+SFileTransfer::createDir(char *pszPath)
+{
+  return false;
+}
+
+bool 
+SFileTransfer::getDirSize(char *pszName, unsigned short *pHighSize16, 
+                          unsigned int *pLowSize32)
+{
+  return false;
+}
+
+bool
+SFileTransfer::initDownloadCallback()
+{
+  return false;
+}
diff --git a/common/rfb/SFileTransfer.h b/common/rfb/SFileTransfer.h
new file mode 100644
index 0000000..51a4928
--- /dev/null
+++ b/common/rfb/SFileTransfer.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2006 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransfer.h
+
+#ifndef __RFB_SFILETRANSFER_H__
+#define __RFB_SFILETRANSFER_H__
+
+#include <network/Socket.h>
+#include <rfb/SFTMsgReader.h>
+#include <rfb/SFTMsgWriter.h>
+#include <rfb/FileWriter.h>
+#include <rfb/FileReader.h>
+#include <rfb/FileInfo.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class SFileTransfer
+  {
+  public:
+    SFileTransfer(network::Socket *sock);
+    virtual ~SFileTransfer();
+
+    bool processMessages(int type);
+    bool sendFileDownloadPortion();
+
+  protected:
+    bool processFileListRequest();
+    bool processFileDownloadRequest();
+    bool processFileUploadRequest();
+    bool processFileUploadData();
+    bool processFileDownloadCancel();
+    bool processFileUploadFailed();
+    bool processFileCreateDirRequest();
+    bool processFileDirSizeRequest();
+    bool processFileRenameRequest();
+    bool processFileDeleteRequest();
+
+    virtual bool initDownloadCallback();
+    virtual bool makeFileList(char *pszPath, FileInfo *pFI, bool bDirOnly);
+    virtual bool convertPathFromNet(char *pszPath);
+
+    virtual bool deleteIt(char *pszPath);
+    virtual bool renameIt(char *pszOldPath, char *pszNewPath);
+    virtual bool createDir(char *pszPath);
+
+    virtual bool getDirSize(char *pszName, unsigned short *pHighSize16, unsigned int *pLowSize32);
+
+    bool m_bUploadStarted;
+    bool m_bDownloadStarted;
+    
+  private:
+    SFTMsgReader m_reader;
+    SFTMsgWriter m_writer;
+
+    FileWriter m_fileWriter;
+    FileReader m_fileReader;
+
+    network::Socket *m_pSocket;
+  };
+}
+
+#endif // __RFB_SFILETRANSFER_H__
diff --git a/common/rfb/SFileTransferManager.cxx b/common/rfb/SFileTransferManager.cxx
new file mode 100644
index 0000000..999a079
--- /dev/null
+++ b/common/rfb/SFileTransferManager.cxx
@@ -0,0 +1,55 @@
+/* Copyright (C) 2006 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransferManager.cxx
+
+#include <rfb/SFileTransferManager.h>
+
+using namespace rfb;
+
+SFileTransferManager::SFileTransferManager()
+{
+
+}
+
+SFileTransferManager::~SFileTransferManager()
+{
+  destroy();
+}
+
+void
+SFileTransferManager::destroyObject(SFileTransfer *pFT)
+{
+  if (pFT == NULL) return;
+
+  m_lstFTObjects.remove(pFT);
+
+  delete pFT;
+}
+
+void
+SFileTransferManager::destroy()
+{
+  while(!m_lstFTObjects.empty())
+    delete m_lstFTObjects.front();
+}
diff --git a/common/rfb/SFileTransferManager.h b/common/rfb/SFileTransferManager.h
new file mode 100644
index 0000000..fe81644
--- /dev/null
+++ b/common/rfb/SFileTransferManager.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2006 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- SFileTransferManager.h
+
+#ifndef __RFB_SFILETRANSFERMANAGER_H__
+#define __RFB_SFILETRANSFERMANAGER_H__
+
+#include <list>
+
+#include <rfb/SFileTransfer.h>
+#include <network/Socket.h>
+
+namespace rfb {
+  class SFileTransferManager
+  {
+  public:
+    SFileTransferManager();
+    virtual ~SFileTransferManager();
+
+    virtual SFileTransfer *createObject(network::Socket *sock) = 0;
+    void destroyObject(SFileTransfer *pFT);
+
+  protected:
+    std::list<SFileTransfer*> m_lstFTObjects;
+
+    void destroy();
+  };
+}
+
+#endif // __RFB_SFILETRANSFERMANAGER_H__
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
new file mode 100644
index 0000000..ccc97ad
--- /dev/null
+++ b/common/rfb/SMsgHandler.cxx
@@ -0,0 +1,52 @@
+/* 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 <rfb/Exception.h>
+#include <rfb/SMsgHandler.h>
+
+using namespace rfb;
+
+SMsgHandler::SMsgHandler()
+{
+}
+
+SMsgHandler::~SMsgHandler()
+{
+}
+
+void SMsgHandler::clientInit(bool shared)
+{
+}
+
+void SMsgHandler::setPixelFormat(const PixelFormat& pf)
+{
+  cp.setPF(pf);
+}
+
+void SMsgHandler::setEncodings(int nEncodings, rdr::U32* encodings)
+{
+  cp.setEncodings(nEncodings, encodings);
+  supportsLocalCursor();
+}
+
+void SMsgHandler::framebufferUpdateRequest(const Rect& r, bool incremental)
+{
+}
+
+void SMsgHandler::supportsLocalCursor()
+{
+}
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
new file mode 100644
index 0000000..cf3377d
--- /dev/null
+++ b/common/rfb/SMsgHandler.h
@@ -0,0 +1,64 @@
+/* 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.
+ */
+//
+// SMsgHandler - class to handle incoming messages on the server side.
+//
+
+#ifndef __RFB_SMSGHANDLER_H__
+#define __RFB_SMSGHANDLER_H__
+
+#include <rdr/types.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ConnParams.h>
+#include <rfb/InputHandler.h>
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+
+  class SMsgHandler : public InputHandler {
+  public:
+    SMsgHandler();
+    virtual ~SMsgHandler();
+
+    // The following methods are called as corresponding messages are read.  A
+    // derived class should override these methods as desired.  Note that for
+    // the setPixelFormat() and setEncodings() methods, a derived class must
+    // call on to SMsgHandler's methods.
+
+    virtual void clientInit(bool shared);
+
+    virtual void setPixelFormat(const PixelFormat& pf);
+    virtual void setEncodings(int nEncodings, rdr::U32* encodings);
+    virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+
+    // 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
+    // setEncodings message, but in the future this may be due to a message
+    // specially for this purpose.
+    virtual void supportsLocalCursor();
+
+    virtual bool processFTMsg(int type) = 0;
+
+    ConnParams cp;
+  };
+}
+#endif
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
new file mode 100644
index 0000000..f89e0f4
--- /dev/null
+++ b/common/rfb/SMsgReader.cxx
@@ -0,0 +1,97 @@
+/* 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 <rdr/InStream.h>
+#include <rfb/Exception.h>
+#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_)
+{
+}
+
+SMsgReader::~SMsgReader()
+{
+}
+
+void SMsgReader::readSetPixelFormat()
+{
+  is->skip(3);
+  PixelFormat pf;
+  pf.read(is);
+  handler->setPixelFormat(pf);
+}
+
+void SMsgReader::readSetEncodings()
+{
+  is->skip(1);
+  int nEncodings = is->readU16();
+  rdr::U32Array encodings(nEncodings);
+  for (int i = 0; i < nEncodings; i++)
+    encodings.buf[i] = is->readU32();
+  handler->setEncodings(nEncodings, encodings.buf);
+}
+
+void SMsgReader::readFramebufferUpdateRequest()
+{
+  bool inc = is->readU8();
+  int x = is->readU16();
+  int y = is->readU16();
+  int w = is->readU16();
+  int h = is->readU16();
+  handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
+}
+
+void SMsgReader::readKeyEvent()
+{
+  bool down = is->readU8();
+  is->skip(2);
+  rdr::U32 key = is->readU32();
+  handler->keyEvent(key, down);
+}
+
+void SMsgReader::readPointerEvent()
+{
+  int mask = is->readU8();
+  int x = is->readU16();
+  int y = is->readU16();
+  handler->pointerEvent(Point(x, y), mask);
+}
+
+
+void SMsgReader::readClientCutText()
+{
+  is->skip(3);
+  int len = is->readU32();
+  if (len > maxCutText) {
+    is->skip(len);
+    fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
+    return;
+  }
+  CharArray ca(len+1);
+  ca.buf[len] = 0;
+  is->readBytes(ca.buf, len);
+  handler->clientCutText(ca.buf, len);
+}
diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h
new file mode 100644
index 0000000..e6e4044
--- /dev/null
+++ b/common/rfb/SMsgReader.h
@@ -0,0 +1,56 @@
+/* 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.
+ */
+//
+// SMsgReader - class for reading RFB messages on the server side
+// (i.e. messages from client to server).
+//
+
+#ifndef __RFB_SMSGREADER_H__
+#define __RFB_SMSGREADER_H__
+
+namespace rdr { class InStream; }
+
+namespace rfb {
+  class SMsgHandler;
+
+  class SMsgReader {
+  public:
+    virtual ~SMsgReader();
+
+    virtual void readClientInit()=0;
+
+    // readMsg() reads a message, calling the handler as appropriate.
+    virtual void readMsg()=0;
+
+    rdr::InStream* getInStream() { return is; }
+
+  protected:
+    virtual void readSetPixelFormat();
+    virtual void readSetEncodings();
+    virtual void readFramebufferUpdateRequest();
+    virtual void readKeyEvent();
+    virtual void readPointerEvent();
+    virtual void readClientCutText();
+
+    SMsgReader(SMsgHandler* handler, rdr::InStream* is);
+
+    SMsgHandler* handler;
+    rdr::InStream* is;
+  };
+}
+#endif
diff --git a/common/rfb/SMsgReaderV3.cxx b/common/rfb/SMsgReaderV3.cxx
new file mode 100644
index 0000000..be01b5d
--- /dev/null
+++ b/common/rfb/SMsgReaderV3.cxx
@@ -0,0 +1,68 @@
+/* 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 <rfb/PixelFormat.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rdr/InStream.h>
+#include <rfb/SMsgReaderV3.h>
+#include <rfb/SMsgHandler.h>
+
+using namespace rfb;
+
+SMsgReaderV3::SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is)
+  : SMsgReader(handler, is)
+{
+}
+
+SMsgReaderV3::~SMsgReaderV3()
+{
+}
+
+void SMsgReaderV3::readClientInit()
+{
+  bool shared = is->readU8();
+  handler->clientInit(shared);
+}
+
+void SMsgReaderV3::readMsg()
+{
+  int msgType = is->readU8();
+  switch (msgType) {
+  case msgTypeSetPixelFormat:           readSetPixelFormat(); break;
+  case msgTypeSetEncodings:             readSetEncodings(); break;
+  case msgTypeFramebufferUpdateRequest: readFramebufferUpdateRequest(); break;
+  case msgTypeKeyEvent:                 readKeyEvent(); break;
+  case msgTypePointerEvent:             readPointerEvent(); break;
+  case msgTypeClientCutText:            readClientCutText(); break;
+
+  case msgTypeFileListRequest:
+  case msgTypeFileDownloadRequest:
+  case msgTypeFileUploadRequest:
+  case msgTypeFileUploadData:
+  case msgTypeFileDownloadCancel:
+  case msgTypeFileUploadFailed:
+  case msgTypeFileCreateDirRequest:
+  case msgTypeFileDirSizeRequest:
+  case msgTypeFileRenameRequest:
+  case msgTypeFileDeleteRequest:        handler->processFTMsg(msgType); break;
+
+  default:
+    fprintf(stderr, "unknown message type %d\n", msgType);
+    throw Exception("unknown message type");
+  }
+}
diff --git a/common/rfb/SMsgReaderV3.h b/common/rfb/SMsgReaderV3.h
new file mode 100644
index 0000000..c6b7bf4
--- /dev/null
+++ b/common/rfb/SMsgReaderV3.h
@@ -0,0 +1,32 @@
+/* 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_SMSGREADERV3_H__
+#define __RFB_SMSGREADERV3_H__
+
+#include <rfb/SMsgReader.h>
+
+namespace rfb {
+  class SMsgReaderV3 : public SMsgReader {
+  public:
+    SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is);
+    virtual ~SMsgReaderV3();
+    virtual void readClientInit();
+    virtual void readMsg();
+  };
+}
+#endif
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
new file mode 100644
index 0000000..085dfc1
--- /dev/null
+++ b/common/rfb/SMsgWriter.cxx
@@ -0,0 +1,202 @@
+/* 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 <assert.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/ColourMap.h>
+#include <rfb/ConnParams.h>
+#include <rfb/UpdateTracker.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SMsgWriter");
+
+SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
+  : imageBufIdealSize(0), cp(cp_), os(os_), lenBeforeRect(0),
+    currentEncoding(0), updatesSent(0), rawBytesEquivalent(0),
+    imageBuf(0), imageBufSize(0)
+{
+  for (unsigned int i = 0; i <= encodingMax; i++) {
+    encoders[i] = 0;
+    bytesSent[i] = 0;
+    rectsSent[i] = 0;
+  }
+}
+
+SMsgWriter::~SMsgWriter()
+{
+  vlog.info("framebuffer updates %d",updatesSent);
+  int bytes = 0;
+  for (unsigned int i = 0; i <= encodingMax; i++) {
+    delete encoders[i];
+    if (i != encodingCopyRect)
+      bytes += bytesSent[i];
+    if (rectsSent[i])
+      vlog.info("  %s rects %d, bytes %d",
+                encodingName(i), rectsSent[i], bytesSent[i]);
+  }
+  vlog.info("  raw bytes equivalent %d, compression ratio %f",
+          rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
+  delete [] imageBuf;
+}
+
+void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours,
+                                          ColourMap* cm)
+{
+  startMsg(msgTypeSetColourMapEntries);
+  os->pad(1);
+  os->writeU16(firstColour);
+  os->writeU16(nColours);
+  for (int i = firstColour; i < firstColour+nColours; i++) {
+    int r, g, b;
+    cm->lookup(i, &r, &g, &b);
+    os->writeU16(r);
+    os->writeU16(g);
+    os->writeU16(b);
+  }
+  endMsg();
+}
+
+void SMsgWriter::writeBell()
+{
+  startMsg(msgTypeBell);
+  endMsg();
+}
+
+void SMsgWriter::writeServerCutText(const char* str, int len)
+{
+  startMsg(msgTypeServerCutText);
+  os->pad(3);
+  os->writeU32(len);
+  os->writeBytes(str, len);
+  endMsg();
+}
+
+void SMsgWriter::setupCurrentEncoder()
+{
+  unsigned int encoding = cp->currentEncoding();
+
+  // FIXME: Code duplication, see writeRect().
+  if (!encoders[encoding]) {
+    encoders[encoding] = Encoder::createEncoder(encoding, this);
+    assert(encoders[encoding]);
+  }
+
+  encoders[encoding]->setCompressLevel(cp->compressLevel);
+  encoders[encoding]->setQualityLevel(cp->qualityLevel);
+}
+
+int SMsgWriter::getNumRects(const Rect &r)
+{
+  unsigned int encoding = cp->currentEncoding();
+
+  if (!encoders[encoding])
+    setupCurrentEncoder();
+
+  return encoders[encoding]->getNumRects(r);
+}
+
+// FIXME: This functions does not compute the number of rectangles correctly
+//        if the Tight encoder is used (but currently that does not matter
+//        because this function is never used).
+void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
+                                        Region* updatedRegion)
+{
+  writeFramebufferUpdateStart(ui.numRects());
+  writeRects(ui, ig, updatedRegion);
+  writeFramebufferUpdateEnd();
+}
+
+void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
+                            Region* updatedRegion)
+{
+  std::vector<Rect> rects;
+  std::vector<Rect>::const_iterator i;
+  updatedRegion->copyFrom(ui.changed);
+  updatedRegion->assign_union(ui.copied);
+
+  ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0);
+  for (i = rects.begin(); i != rects.end(); i++)
+    writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y);
+
+  ui.changed.get_rects(&rects);
+  for (i = rects.begin(); i != rects.end(); i++) {
+    Rect actual;
+    if (!writeRect(*i, ig, &actual)) {
+      updatedRegion->assign_subtract(*i);
+      updatedRegion->assign_union(actual);
+    }
+  }
+}
+
+
+bool SMsgWriter::needFakeUpdate()
+{
+  return false;
+}
+
+bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  return writeRect(r, cp->currentEncoding(), ig, actual);
+}
+
+bool SMsgWriter::writeRect(const Rect& r, unsigned int encoding,
+                           ImageGetter* ig, Rect* actual)
+{
+  if (!encoders[encoding]) {
+    encoders[encoding] = Encoder::createEncoder(encoding, this);
+    assert(encoders[encoding]);
+  }
+  return encoders[encoding]->writeRect(r, ig, actual);
+}
+
+void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
+{
+  startRect(r,encodingCopyRect);
+  os->writeU16(srcX);
+  os->writeU16(srcY);
+  endRect();
+}
+
+rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels)
+{
+  int requiredBytes = required * (cp->pf().bpp / 8);
+  int requestedBytes = requested * (cp->pf().bpp / 8);
+  int size = requestedBytes;
+  if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+  if (size < requiredBytes)
+    size = requiredBytes;
+
+  if (imageBufSize < size) {
+    imageBufSize = size;
+    delete [] imageBuf;
+    imageBuf = new rdr::U8[imageBufSize];
+  }
+  if (nPixels)
+    *nPixels = imageBufSize / (cp->pf().bpp / 8);
+  return imageBuf;
+}
+
+int SMsgWriter::bpp()
+{
+  return cp->pf().bpp;
+}
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
new file mode 100644
index 0000000..ed8ad0e
--- /dev/null
+++ b/common/rfb/SMsgWriter.h
@@ -0,0 +1,163 @@
+/* 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.
+ */
+//
+// SMsgWriter - class for writing RFB messages on the server side.
+//
+
+#ifndef __RFB_SMSGWRITER_H__
+#define __RFB_SMSGWRITER_H__
+
+#include <rdr/types.h>
+#include <rfb/encodings.h>
+#include <rfb/Encoder.h>
+
+namespace rdr { class OutStream; }
+
+namespace rfb {
+
+  class PixelFormat;
+  class ConnParams;
+  class ImageGetter;
+  class ColourMap;
+  class Region;
+  class UpdateInfo;
+
+  class WriteSetCursorCallback {
+  public:
+    virtual void writeSetCursorCallback() = 0;
+  };
+
+  class SMsgWriter {
+  public:
+    virtual ~SMsgWriter();
+
+    // writeServerInit() must only be called at the appropriate time in the
+    // protocol initialisation.
+    virtual void writeServerInit()=0;
+
+    // Methods to write normal protocol messages
+
+    // writeSetColourMapEntries() writes a setColourMapEntries message, using
+    // the given ColourMap object to lookup the RGB values of the given range
+    // of colours.
+    virtual void writeSetColourMapEntries(int firstColour, int nColours,
+                                          ColourMap* cm);
+
+    // writeBell() and writeServerCutText() do the obvious thing.
+    virtual void writeBell();
+    virtual void writeServerCutText(const char* str, int len);
+
+    // setupCurrentEncoder() should be called before each framebuffer update,
+    // prior to calling getNumRects() or writeFramebufferUpdateStart().
+    void setupCurrentEncoder();
+
+    // getNumRects() computes the number of sub-rectangles that will compose a
+    // given rectangle, for current encoder.
+    int getNumRects(const Rect &r);
+
+    // writeSetDesktopSize() on a V3 writer won't actually write immediately,
+    // but will write the relevant pseudo-rectangle as part of the next update.
+    virtual bool writeSetDesktopSize()=0;
+
+    // Like setDesktopSize, we can't just write out a setCursor message
+    // immediately on a V3 writer.  Instead of calling writeSetCursor()
+    // directly, you must call cursorChange(), and then invoke writeSetCursor()
+    // 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, const Point& hotspot,
+                                void* data, void* mask)=0;
+    virtual void writeSetXCursor(int width, int height, int hotspotX,
+                                int hotspotY, void* data, void* mask)=0;
+
+    // needFakeUpdate() returns true when an immediate update is needed in
+    // order to flush out setDesktopSize or setCursor pseudo-rectangles to the
+    // client.
+    virtual bool needFakeUpdate();
+
+    // writeFramebufferUpdate() writes a framebuffer update using the given
+    // UpdateInfo and ImageGetter.  On a V3 writer this may have
+    // pseudo-rectangles for setDesktopSize and setCursor added to it, and so
+    // may invoke writeSetCursorCallback().
+    virtual void writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
+                                        Region* updatedRegion);
+
+    // writeRects() accepts an UpdateInfo (changed & copied regions) and an
+    // ImageGetter to fetch pixels from.  It then calls writeCopyRect() and
+    // writeRect() as appropriate.  writeFramebufferUpdateStart() must be used
+    // before the first writeRects() call and writeFrameBufferUpdateEnd() after
+    // the last one.  It returns the actual region sent to the client, which
+    // may be smaller than the update passed in.
+    virtual void writeRects(const UpdateInfo& update, ImageGetter* ig,
+                            Region* updatedRegion);
+
+    // To construct a framebuffer update you can call
+    // writeFramebufferUpdateStart(), followed by a number of writeCopyRect()s
+    // and writeRect()s, finishing with writeFramebufferUpdateEnd().  If you
+    // know the exact number of rectangles ahead of time you can specify it to
+    // writeFramebufferUpdateStart() which can be more efficient.
+    virtual void writeFramebufferUpdateStart(int nRects)=0;
+    virtual void writeFramebufferUpdateStart()=0;
+    virtual void writeFramebufferUpdateEnd()=0;
+
+    // writeRect() tries to write the given rectangle.  If it is unable to
+    // write the whole rectangle it returns false and sets actual to the actual
+    // rectangle which was updated.
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, unsigned int encoding,
+                           ImageGetter* ig, Rect* actual);
+
+    virtual void writeCopyRect(const Rect& r, int srcX, int srcY);
+
+    virtual void startRect(const Rect& r, unsigned int enc)=0;
+    virtual void endRect()=0;
+
+    ConnParams* getConnParams() { return cp; }
+    rdr::OutStream* getOutStream() { return os; }
+    rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0);
+    int bpp();
+
+    int getUpdatesSent()           { return updatesSent; }
+    int getRectsSent(int encoding) { return rectsSent[encoding]; }
+    int getBytesSent(int encoding) { return bytesSent[encoding]; }
+    int getRawBytesEquivalent()    { return rawBytesEquivalent; }
+
+    int imageBufIdealSize;
+
+  protected:
+    SMsgWriter(ConnParams* cp, rdr::OutStream* os);
+
+    virtual void startMsg(int type)=0;
+    virtual void endMsg()=0;
+
+    ConnParams* cp;
+    rdr::OutStream* os;
+
+    Encoder* encoders[encodingMax+1];
+    int lenBeforeRect;
+    unsigned int currentEncoding;
+    int updatesSent;
+    int bytesSent[encodingMax+1];
+    int rectsSent[encodingMax+1];
+    int rawBytesEquivalent;
+
+    rdr::U8* imageBuf;
+    int imageBufSize;
+  };
+}
+#endif
diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx
new file mode 100644
index 0000000..a85f85e
--- /dev/null
+++ b/common/rfb/SMsgWriterV3.cxx
@@ -0,0 +1,197 @@
+/* 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 <rdr/OutStream.h>
+#include <rdr/MemOutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriterV3.h>
+
+using namespace rfb;
+
+SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
+  : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0),
+    nRectsInHeader(0), wsccb(0),
+    needSetDesktopSize(false)
+{
+}
+
+SMsgWriterV3::~SMsgWriterV3()
+{
+  delete updateOS;
+}
+
+void SMsgWriterV3::writeServerInit()
+{
+  os->writeU16(cp->width);
+  os->writeU16(cp->height);
+  cp->pf().write(os);
+  os->writeString(cp->name());
+  endMsg();
+}
+
+void SMsgWriterV3::startMsg(int type)
+{
+  if (os != realOS)
+    throw Exception("startMsg called while writing an update?");
+
+  os->writeU8(type);
+}
+
+void SMsgWriterV3::endMsg()
+{
+  os->flush();
+}
+
+bool SMsgWriterV3::writeSetDesktopSize() {
+  if (!cp->supportsDesktopResize) return false;
+  needSetDesktopSize = true;
+  return true;
+}
+
+void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
+{
+  wsccb = cb;
+}
+
+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(hotspot.x);
+  os->writeS16(hotspot.y);
+  os->writeU16(width);
+  os->writeU16(height);
+  os->writeU32(pseudoEncodingCursor);
+  os->writeBytes(data, width * height * (cp->pf().bpp/8));
+  os->writeBytes(mask, (width+7)/8 * height);
+}
+
+void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
+				   int hotspotY, void* data, void* mask)
+{
+  if (!wsccb) return;
+  if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
+  os->writeS16(hotspotX);
+  os->writeS16(hotspotY);
+  os->writeU16(width);
+  os->writeU16(height);
+  os->writeU32(pseudoEncodingXCursor);
+  // FIXME: We only support black and white cursors, currently. We
+  // could pass the correct color by using the pix0/pix1 values
+  // returned from getBitmap, in writeSetCursorCallback. However, we
+  // would then need to undo the conversion from rgb to Pixel that is
+  // done by FakeAllocColor. 
+  if (width * height) {
+    os->writeU8(0);
+    os->writeU8(0);
+    os->writeU8(0);
+    os->writeU8(255);
+    os->writeU8(255);
+    os->writeU8(255);
+    os->writeBytes(data, (width+7)/8 * height);
+    os->writeBytes(mask, (width+7)/8 * height);
+  }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
+{
+  startMsg(msgTypeFramebufferUpdate);
+  os->pad(1);
+  if (wsccb) nRects++;
+  if (needSetDesktopSize) nRects++;
+  os->writeU16(nRects);
+  nRectsInUpdate = 0;
+  nRectsInHeader = nRects;
+  if (wsccb) {
+    wsccb->writeSetCursorCallback();
+    wsccb = 0;
+  }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart()
+{
+  nRectsInUpdate = nRectsInHeader = 0;
+  if (!updateOS)
+    updateOS = new rdr::MemOutStream;
+  os = updateOS;
+}
+
+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);
+    os->writeS16(0);
+    os->writeU16(cp->width);
+    os->writeU16(cp->height);
+    os->writeU32(pseudoEncodingDesktopSize);
+    needSetDesktopSize = false;
+  }
+
+  if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
+                    "nRects out of sync");
+  if (os == updateOS) {
+    os = realOS;
+    startMsg(msgTypeFramebufferUpdate);
+    os->pad(1);
+    os->writeU16(nRectsInUpdate);
+    os->writeBytes(updateOS->data(), updateOS->length());
+    updateOS->clear();
+  }
+
+  updatesSent++;
+  endMsg();
+}
+
+bool SMsgWriterV3::needFakeUpdate()
+{
+  return wsccb || needSetDesktopSize;
+}
+
+void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
+{
+  if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriterV3::startRect: nRects out of sync");
+
+  currentEncoding = encoding;
+  lenBeforeRect = os->length();
+  if (encoding != encodingCopyRect)
+    rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
+
+  os->writeS16(r.tl.x);
+  os->writeS16(r.tl.y);
+  os->writeU16(r.width());
+  os->writeU16(r.height());
+  os->writeU32(encoding);
+}
+
+void SMsgWriterV3::endRect()
+{
+  if (currentEncoding <= encodingMax) {
+    bytesSent[currentEncoding] += os->length() - lenBeforeRect;
+    rectsSent[currentEncoding]++;
+  }
+}
diff --git a/common/rfb/SMsgWriterV3.h b/common/rfb/SMsgWriterV3.h
new file mode 100644
index 0000000..501fa48
--- /dev/null
+++ b/common/rfb/SMsgWriterV3.h
@@ -0,0 +1,57 @@
+/* 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_SMSGWRITERV3_H__
+#define __RFB_SMSGWRITERV3_H__
+
+#include <rfb/SMsgWriter.h>
+
+namespace rdr { class MemOutStream; }
+
+namespace rfb {
+  class SMsgWriterV3 : public SMsgWriter {
+  public:
+    SMsgWriterV3(ConnParams* cp, rdr::OutStream* os);
+    virtual ~SMsgWriterV3();
+
+    virtual void writeServerInit();
+    virtual void startMsg(int type);
+    virtual void endMsg();
+    virtual bool writeSetDesktopSize();
+    virtual void cursorChange(WriteSetCursorCallback* cb);
+    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);
+    virtual void writeFramebufferUpdateStart();
+    virtual void writeFramebufferUpdateEnd();
+    virtual bool needFakeUpdate();
+    virtual void startRect(const Rect& r, unsigned int encoding);
+    virtual void endRect();
+
+  private:
+    rdr::MemOutStream* updateOS;
+    rdr::OutStream* realOS;
+    int nRectsInUpdate;
+    int nRectsInHeader;
+    WriteSetCursorCallback* wsccb;
+    bool needSetDesktopSize;
+    bool needLastRect;
+  };
+}
+#endif
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
new file mode 100644
index 0000000..108985b
--- /dev/null
+++ b/common/rfb/SSecurity.h
@@ -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.
+ */
+//
+// 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.  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.
+// Note that the first time processMsg() is called, there is no guarantee that
+// there is any data to read from the SConnection's InStream, but subsequent
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+//
+// getType() should return the secType value corresponding to the SSecurity
+// implementation.
+//
+
+#ifndef __RFB_SSECURITY_H__
+#define __RFB_SSECURITY_H__
+
+#include <rdr/types.h>
+#include <rfb/util.h>
+#include <list>
+
+namespace rfb {
+
+  class SConnection;
+
+  class SSecurity {
+  public:
+    virtual ~SSecurity() {}
+    virtual bool processMsg(SConnection* sc)=0;
+    virtual void destroy() { delete this; }
+    virtual int getType() const = 0;
+
+    // getUserName() gets the name of the user attempting authentication.  The
+    // storage is owned by the SSecurity object, so a copy must be taken if
+    // necessary.  Null may be returned to indicate that there is no user name
+    // for this security type.
+    virtual const char* getUserName() const = 0;
+  };
+
+  // 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(rdr::U8 secType, bool noAuth=false)=0;
+    virtual void getSecTypes(std::list<rdr::U8>* secTypes,
+                             bool reverseConnection) = 0;
+  };
+
+}
+#endif
diff --git a/common/rfb/SSecurityFactoryStandard.cxx b/common/rfb/SSecurityFactoryStandard.cxx
new file mode 100644
index 0000000..a072698
--- /dev/null
+++ b/common/rfb/SSecurityFactoryStandard.cxx
@@ -0,0 +1,128 @@
+/* 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.
+ */
+//
+// SSecurityFactoryStandard
+//
+
+#include <rfb/secTypes.h>
+#include <rfb/SSecurityNone.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/Password.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SSecurityFactoryStandard");
+
+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");
+
+
+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 secTypeVncAuth:
+    return new SSecurityVncAuth(&vncAuthPasswd);
+  default:
+    throw Exception("Security type not supported");
+  }
+}
+
+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;
+  }
+}
+
+
+VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name,
+                                               const char* desc,
+                                               StringParameter* passwdFile_)
+: BinaryParameter(name, desc, 0, 0), passwdFile(passwdFile_) {
+}
+
+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();
+  } catch (...) {
+    return 0;
+  }
+}
+
+
diff --git a/common/rfb/SSecurityFactoryStandard.h b/common/rfb/SSecurityFactoryStandard.h
new file mode 100644
index 0000000..165881e
--- /dev/null
+++ b/common/rfb/SSecurityFactoryStandard.h
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+//
+// SSecurityFactoryStandard - implementation of the SSecurityFactory
+// interface.
+//
+// Server implementations must define an instance of a
+// VncAuthPasswdParameter-based class somewhere.  Any class based on
+// VncAuthPasswdParameter will automatically register itself as the
+// password parameter to be used by the Standard factory.
+//
+// Two implementations are provided here:
+//
+// VncAuthPasswdConfigParameter - reads the password from the Binary
+//                                parameter "Password".
+// VncAuthPasswdFileParameter   - reads the password from the file named
+//                                in the String parameter "PasswordFile".
+//
+// This factory supports only the "None" and "VncAuth" security types.
+//
+
+#ifndef __RFB_SSECURITYFACTORY_STANDARD_H__
+#define __RFB_SSECURITYFACTORY_STANDARD_H__
+
+#include <rfb/SSecurityVncAuth.h>
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter {
+  public:
+    VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_);
+    virtual char* getVncAuthPasswd();
+  protected:
+    StringParameter* passwdFile;
+  };
+
+  class SSecurityFactoryStandard : public SSecurityFactory {
+  public:
+    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:
+    virtual bool isSecTypeSupported(rdr::U8 secType);
+  };
+
+}
+#endif
diff --git a/common/rfb/SSecurityNone.h b/common/rfb/SSecurityNone.h
new file mode 100644
index 0000000..5c19f29
--- /dev/null
+++ b/common/rfb/SSecurityNone.h
@@ -0,0 +1,36 @@
+/* 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.
+ */
+//
+// SSecurityNone.h
+//
+
+#ifndef __SSECURITYNONE_H__
+#define __SSECURITYNONE_H__
+
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+  class SSecurityNone : public SSecurity {
+  public:
+    virtual bool processMsg(SConnection* sc) { return true; }
+    virtual int getType() const {return secTypeNone;}
+    virtual const char* getUserName() const {return 0;}
+  };
+}
+#endif
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
new file mode 100644
index 0000000..29a3b96
--- /dev/null
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -0,0 +1,87 @@
+/* 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.
+ */
+//
+// 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/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("SVncAuth");
+
+
+SSecurityVncAuth::SSecurityVncAuth(VncAuthPasswdGetter* pg_)
+  : sentChallenge(false), responsePos(0), pg(pg_)
+{
+}
+
+bool SSecurityVncAuth::processMsg(SConnection* sc)
+{
+  rdr::InStream* is = sc->getInStream();
+  rdr::OutStream* os = sc->getOutStream();
+
+  if (!sentChallenge) {
+    rdr::RandomStream rs;
+    rs.readBytes(challenge, vncAuthChallengeSize);
+    os->writeBytes(challenge, vncAuthChallengeSize);
+    os->flush();
+    sentChallenge = true;
+    return false;
+  }
+
+  while (responsePos < vncAuthChallengeSize && is->checkNoWait(1))
+    response[responsePos++] = is->readU8();
+
+  if (responsePos < vncAuthChallengeSize) return false;
+
+  PlainPasswd passwd(pg->getVncAuthPasswd());
+
+  if (!passwd.buf)
+    throw AuthFailureException("No password configured for VNC Auth");
+
+  // 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);
+
+  // Check the actual response
+  if (memcmp(challenge, response, vncAuthChallengeSize) != 0)
+    throw AuthFailureException();
+
+  return true;
+}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
new file mode 100644
index 0000000..1d0a82d
--- /dev/null
+++ b/common/rfb/SSecurityVncAuth.h
@@ -0,0 +1,55 @@
+/* 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.
+ */
+// SSecurityVncAuth - legacy VNC authentication protocol.
+// The getPasswd call can be overridden if you wish to store
+// the VncAuth password in an implementation-specific place.
+// Otherwise, the password is read from a BinaryParameter
+// called Password.
+
+#ifndef __RFB_SSECURITYVNCAUTH_H__
+#define __RFB_SSECURITYVNCAUTH_H__
+
+#include <rfb/SSecurity.h>
+#include <rfb/secTypes.h>
+#include <rdr/types.h>
+
+namespace rfb {
+
+  class VncAuthPasswdGetter {
+  public:
+    // getPasswd() returns a string or null if unsuccessful.  The
+    // SSecurityVncAuth object delete[]s the string when done.
+    virtual char* getVncAuthPasswd()=0;
+  };
+
+  class SSecurityVncAuth : public SSecurity {
+  public:
+    SSecurityVncAuth(VncAuthPasswdGetter* pg);
+    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;
+    int responsePos;
+    VncAuthPasswdGetter* pg;
+  };
+}
+#endif
diff --git a/common/rfb/ScaledPixelBuffer.cxx b/common/rfb/ScaledPixelBuffer.cxx
new file mode 100644
index 0000000..bf4612d
--- /dev/null
+++ b/common/rfb/ScaledPixelBuffer.cxx
@@ -0,0 +1,132 @@
+/* Copyright (C) 2005 TightVNC Team.  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.
+ */
+
+// -=- ScaledPixelBuffer.cxx
+
+#include <rfb/ScaledPixelBuffer.h>
+
+#include <math.h>
+#include <memory.h>
+
+using namespace rdr;
+using namespace rfb;
+
+ScaledPixelBuffer::ScaledPixelBuffer(U8 **src_data_, int src_width_,
+                                     int src_height_, int scale)
+  : bpp(32), scaled_data(0), scale_ratio(1), scale(100) {
+
+  setSourceBuffer(src_data_, src_width_, src_height_);
+}
+
+ScaledPixelBuffer::ScaledPixelBuffer() 
+  : src_data(0), src_width(0), src_height(0), scale_ratio(1), scale(100),
+    bpp(32), scaled_data(0) {
+}
+
+ScaledPixelBuffer::~ScaledPixelBuffer() {
+}
+
+void ScaledPixelBuffer::setSourceBuffer(U8 **src_data_, int w, int h) {
+  src_data = src_data_;
+  src_width  = w;
+  src_height = h;
+  calculateScaledBufferSize();
+  recreateScaledBuffer();
+}
+
+void ScaledPixelBuffer::setScale(int scale_) {
+  if (scale != scale_) {
+    scale = scale_;
+    scale_ratio = double(scale) / 100;
+    calculateScaledBufferSize();
+    recreateScaledBuffer();
+  }
+}
+
+void ScaledPixelBuffer::scaleRect(const Rect& r) {
+  static U8 *src_ptr, *ptr;
+  static U8 r0, r1, r2, r3;
+  static U8 g0, g1, g2, g3;
+  static U8 b0, b1, b2, b3;
+  static double c1_sub_dx, c1_sub_dy;
+  static double dx, dy;
+  static int i, j;
+  static Rect changed_rect;
+
+  // Calculate the changed pixel rect in the scaled image
+  changed_rect = calculateScaleBoundary(r);
+
+  // Scale the source rect to the destination image buffer using
+  // bilinear interplation
+  for (int y = changed_rect.tl.y; y < changed_rect.br.y; y++) {
+    j = (int)(dy = y / scale_ratio);
+    dy -= j;
+    c1_sub_dy = 1 - dy;
+
+    for (int x = changed_rect.tl.x; x < changed_rect.br.x; x++) {
+      ptr = &scaled_data[(x + y*scaled_width) * 4];
+
+      i = (int)(dx = x / scale_ratio);
+      dx -= i;
+      c1_sub_dx = 1 - dx;
+
+      src_ptr = &(*src_data)[(i + (j*src_width))*4];
+      b0 = *src_ptr; g0 = *(src_ptr+1); r0 = *(src_ptr+2);
+      if (i+1 < src_width) {
+        b1 = *(src_ptr+4); g1 = *(src_ptr+5); r1 = *(src_ptr+6);
+      } else {
+        b1 = b0; r1 = r0; g1 = g0;
+      }
+      if (j+1 < src_height) {
+        src_ptr += src_width * 4;
+        b3 = *src_ptr; g3 = *(src_ptr+1); r3 = *(src_ptr+2);
+      } else {
+        b3 = b0; r3 = r0; g3 = g0;
+      }
+      if ((i+1 < src_width) && (j+1 < src_height)) {
+        b2 = *(src_ptr+4); g2 = *(src_ptr+5); r2 = *(src_ptr+6);
+      } else if (i+1 >= src_width) {
+        b2 = b3; r2 = r3; g2 = g3;
+      } else {
+        b2 = b1; r2 = r1; g2 = g1;
+      }
+      *ptr++ = (U8)((b0*c1_sub_dx+b1*dx)*c1_sub_dy + (b3*c1_sub_dx+b2*dx)*dy);
+      *ptr++ = (U8)((g0*c1_sub_dx+g1*dx)*c1_sub_dy + (g3*c1_sub_dx+g2*dx)*dy);
+      *ptr   = (U8)((r0*c1_sub_dx+r1*dx)*c1_sub_dy + (r3*c1_sub_dx+r2*dx)*dy);
+    }
+  }
+}
+
+Rect ScaledPixelBuffer::calculateScaleBoundary(const Rect& r) {
+  static int x_start, y_start, x_end, y_end;
+  x_start = r.tl.x == 0 ? 0 : ceil((r.tl.x-1) * scale_ratio);
+  y_start = r.tl.y == 0 ? 0 : ceil((r.tl.y-1) * scale_ratio);
+  x_end = ceil(r.br.x * scale_ratio - 1); 
+  x_end = x_end < scaled_width ? x_end + 1 : scaled_width;
+  y_end = ceil(r.br.y * scale_ratio - 1);
+  y_end = y_end < scaled_height ? y_end + 1 : scaled_height;
+  return Rect(x_start, y_start, x_end, y_end);
+}
+
+void ScaledPixelBuffer::calculateScaledBufferSize() {
+  scaled_width  = (int)ceil(src_width  * scale_ratio);
+  scaled_height = (int)ceil(src_height * scale_ratio);
+}
+
+void ScaledPixelBuffer::recreateScaledBuffer() {
+}
diff --git a/common/rfb/ScaledPixelBuffer.h b/common/rfb/ScaledPixelBuffer.h
new file mode 100644
index 0000000..3b6aa7e
--- /dev/null
+++ b/common/rfb/ScaledPixelBuffer.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2005 TightVNC Team.  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.
+ */
+
+// -=- ScaledPixelBuffer.h
+//
+// The ScaledPixelBuffer class allows to scale the image data 
+// from the source buffer to destination buffer using bilinear 
+// interpolation.
+
+#include <rdr/types.h>
+#include <rfb/Rect.h>
+
+using namespace rdr;
+
+namespace rfb {
+
+  class ScaledPixelBuffer {
+  public:
+    ScaledPixelBuffer(U8 **data, int width, int height, int scale);
+    ScaledPixelBuffer();
+    virtual ~ScaledPixelBuffer();
+
+    // Get width, height, number of pixels and scale
+    int width()  const { return scaled_width; }
+    int height() const { return scaled_height; }
+    int area() const { return scaled_width * scaled_height; }
+    int getScale() const { return scale; }
+
+    // Get rectangle encompassing this buffer
+    //   Top-left of rectangle is either at (0,0), or the specified point.
+    Rect getRect() const { return Rect(0, 0, scaled_width, scaled_height); }
+    Rect getRect(const Point& pos) const {
+      return Rect(pos, pos.translate(Point(scaled_width, scaled_height)));
+    }
+
+    // Set the new source buffer and its parameters
+    void setSourceBuffer(U8 **src_data, int w, int h);
+
+    // Set the new scale, in percent
+    virtual void setScale(int scale);
+
+    // Scale rect from the source image buffer to the destination buffer
+    // using bilinear interpolation
+    virtual void scaleRect(const Rect& r);
+
+    // Calculate the scaled image rectangle which depend on the source 
+    // image rectangle.
+    inline Rect calculateScaleBoundary(const Rect& r);
+
+  protected:
+
+    // Calculate the scaled buffer size depending on the source buffer
+    // parameters (width, height, pixel format)
+    void calculateScaledBufferSize();
+
+    // Recreate the scaled pixel buffer
+    virtual void recreateScaledBuffer();
+
+    int src_width;
+    int src_height;
+    int scaled_width;
+    int scaled_height;
+    int bpp;
+    int scale;
+    double scale_ratio;
+    U8 **src_data;
+    U8 *scaled_data;
+  };
+
+};
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
new file mode 100644
index 0000000..750daae
--- /dev/null
+++ b/common/rfb/ServerCore.cxx
@@ -0,0 +1,94 @@
+/* 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.
+ */
+
+// -=- ServerCore.cxx
+
+// This header will define the Server interface, from which ServerMT and
+// ServerST will be derived.
+
+#include <string.h>
+#include <rfb/util.h>
+#include <rfb/ServerCore.h>
+
+rfb::IntParameter rfb::Server::idleTimeout
+("IdleTimeout",
+ "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);
+rfb::IntParameter rfb::Server::maxConnectionTime
+("MaxConnectionTime",
+ "Terminate when a client has been connected for s seconds", 
+ 0, 0);
+rfb::IntParameter rfb::Server::maxIdleTime
+("MaxIdleTime",
+ "Terminate after s seconds of user inactivity", 
+ 0, 0);
+rfb::IntParameter rfb::Server::clientWaitTimeMillis
+("ClientWaitTimeMillis",
+ "The number of milliseconds to wait for a client which is no longer "
+ "responding",
+ 20000, 0);
+rfb::BoolParameter rfb::Server::compareFB
+("CompareFB",
+ "Perform pixel comparison on framebuffer to reduce unnecessary updates",
+ true);
+rfb::BoolParameter rfb::Server::protocol3_3
+("Protocol3.3",
+ "Always use protocol version 3.3 for backwards compatibility with "
+ "badly-behaved clients",
+ false);
+rfb::BoolParameter rfb::Server::alwaysShared
+("AlwaysShared",
+ "Always treat incoming connections as shared, regardless of the client-"
+ "specified setting",
+ false);
+rfb::BoolParameter rfb::Server::neverShared
+("NeverShared",
+ "Never treat incoming connections as shared, regardless of the client-"
+ "specified setting",
+ false);
+rfb::BoolParameter rfb::Server::disconnectClients
+("DisconnectClients",
+ "Disconnect existing clients if an incoming connection is non-shared. "
+ "If combined with NeverShared then new connections will be refused "
+ "while there is a client active",
+ true);
+rfb::BoolParameter rfb::Server::acceptKeyEvents
+("AcceptKeyEvents",
+ "Accept key press and release events from clients.",
+ true);
+rfb::BoolParameter rfb::Server::acceptPointerEvents
+("AcceptPointerEvents",
+ "Accept pointer press and release events from clients.",
+ true);
+rfb::BoolParameter rfb::Server::acceptCutText
+("AcceptCutText",
+ "Accept clipboard updates from clients.",
+ true);
+rfb::BoolParameter rfb::Server::sendCutText
+("SendCutText",
+ "Send clipboard changes to clients.",
+ true);
+rfb::BoolParameter rfb::Server::queryConnect
+("QueryConnect",
+ "Prompt the local user to accept or reject incoming connections.",
+ false);
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
new file mode 100644
index 0000000..68d7b74
--- /dev/null
+++ b/common/rfb/ServerCore.h
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+// -=- ServerCore.h
+
+// This header will define the Server interface, from which ServerMT and
+// ServerST will be derived.
+
+#ifndef __RFB_SERVER_CORE_H__
+#define __RFB_SERVER_CORE_H__
+
+#include <rfb/Configuration.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  class Server {
+  public:
+
+    static IntParameter idleTimeout;
+    static IntParameter maxDisconnectionTime;
+    static IntParameter maxConnectionTime;
+    static IntParameter maxIdleTime;
+    static IntParameter clientWaitTimeMillis;
+    static BoolParameter compareFB;
+    static BoolParameter protocol3_3;
+    static BoolParameter alwaysShared;
+    static BoolParameter neverShared;
+    static BoolParameter disconnectClients;
+    static BoolParameter acceptKeyEvents;
+    static BoolParameter acceptPointerEvents;
+    static BoolParameter acceptCutText;
+    static BoolParameter sendCutText;
+    static BoolParameter queryConnect;
+
+  };
+
+};
+
+#endif // __RFB_SERVER_CORE_H__
+
diff --git a/common/rfb/Threading.h b/common/rfb/Threading.h
new file mode 100644
index 0000000..66b3aa0
--- /dev/null
+++ b/common/rfb/Threading.h
@@ -0,0 +1,31 @@
+/* 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.
+ */
+
+// -=- Threading.h
+// General purpose threading interface.
+// If the current platform supports threading then __RFB_THREADING_IMPL
+// will be defined after this header has been included.
+
+#ifndef __RFB_THREADING_H__
+#define __RFB_THREADING_H__
+
+#ifdef WIN32
+#include <rfb_win32/Threading.h>
+#endif
+
+#endif // __RFB_THREADING_H__
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
new file mode 100644
index 0000000..9f8c505
--- /dev/null
+++ b/common/rfb/TightDecoder.cxx
@@ -0,0 +1,159 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky.  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
+ * (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 <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/TightDecoder.h>
+#include <stdio.h> /* jpeglib.h needs FILE */
+extern "C" {
+#include <jpeglib.h>
+}
+
+using namespace rfb;
+
+#define RGB_TO_PIXEL(r,g,b)						\
+  (((PIXEL_T)(r) & myFormat.redMax) << myFormat.redShift |		\
+   ((PIXEL_T)(g) & myFormat.greenMax) << myFormat.greenShift |	        \
+   ((PIXEL_T)(b) & myFormat.blueMax) << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL(r,g,b)                                       \
+   ((((PIXEL_T)(r) & 0xFF) * myFormat.redMax + 127) / 255             \
+    << myFormat.redShift |                                              \
+    (((PIXEL_T)(g) & 0xFF) * myFormat.greenMax + 127) / 255           \
+    << myFormat.greenShift |                                            \
+    (((PIXEL_T)(b) & 0xFF) * myFormat.blueMax + 127) / 255            \
+    << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b)						\
+  (((rdr::U32)(r) & 0xFF) << myFormat.redShift |				\
+   ((rdr::U32)(g) & 0xFF) << myFormat.greenShift |			\
+   ((rdr::U32)(b) & 0xFF) << myFormat.blueShift)
+
+#define TIGHT_MAX_WIDTH 2048
+
+static void JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData,
+			      int compressedLen);
+static bool jpegError;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/tightDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/tightDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/tightDecode.h>
+#undef BPP
+
+Decoder* TightDecoder::create(CMsgReader* reader)
+{
+  return new TightDecoder(reader);
+}
+
+TightDecoder::TightDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+TightDecoder::~TightDecoder()
+{
+}
+
+void TightDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+  rdr::InStream* is = reader->getInStream();
+  /* Uncompressed RGB24 JPEG data, before translated, can be up to 3
+     times larger, if VNC bpp is 8. */
+  rdr::U8* buf = reader->getImageBuf(r.area()*3);
+  switch (reader->bpp()) {
+  case 8:
+    tightDecode8 (r, is, zis, (rdr::U8*) buf, handler); break;
+  case 16:
+    tightDecode16(r, is, zis, (rdr::U16*)buf, handler); break;
+  case 32:
+    tightDecode32(r, is, zis, (rdr::U32*)buf, handler); break;
+  }
+}
+
+
+//
+// A "Source manager" for the JPEG library.
+//
+
+static struct jpeg_source_mgr jpegSrcManager;
+static JOCTET *jpegBufferPtr;
+static size_t jpegBufferLen;
+
+static void JpegInitSource(j_decompress_ptr cinfo);
+static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
+static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
+static void JpegTermSource(j_decompress_ptr cinfo);
+
+static void
+JpegInitSource(j_decompress_ptr cinfo)
+{
+  jpegError = false;
+}
+
+static boolean
+JpegFillInputBuffer(j_decompress_ptr cinfo)
+{
+  jpegError = true;
+  jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+  jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+
+  return TRUE;
+}
+
+static void
+JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
+{
+  if (num_bytes < 0 || (size_t)num_bytes > jpegSrcManager.bytes_in_buffer) {
+    jpegError = true;
+    jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+    jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+  } else {
+    jpegSrcManager.next_input_byte += (size_t) num_bytes;
+    jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+static void
+JpegTermSource(j_decompress_ptr cinfo)
+{
+  /* No work necessary here. */
+}
+
+static void
+JpegSetSrcManager(j_decompress_ptr cinfo, char *compressedData, int compressedLen)
+{
+  jpegBufferPtr = (JOCTET *)compressedData;
+  jpegBufferLen = (size_t)compressedLen;
+
+  jpegSrcManager.init_source = JpegInitSource;
+  jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
+  jpegSrcManager.skip_input_data = JpegSkipInputData;
+  jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
+  jpegSrcManager.term_source = JpegTermSource;
+  jpegSrcManager.next_input_byte = jpegBufferPtr;
+  jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+
+  cinfo->src = &jpegSrcManager;
+}
diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h
new file mode 100644
index 0000000..1047b37
--- /dev/null
+++ b/common/rfb/TightDecoder.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2000-2003 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
+ * (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_TIGHTDECODER_H__
+#define __RFB_TIGHTDECODER_H__
+
+#include <rdr/ZlibInStream.h>
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+  class TightDecoder : public Decoder {
+  public:
+    static Decoder* create(CMsgReader* reader);
+    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual ~TightDecoder();
+  private:
+    TightDecoder(CMsgReader* reader);
+    CMsgReader* reader;
+    rdr::ZlibInStream zis[4];
+  };
+
+  // Compression control 
+  const unsigned int rfbTightExplicitFilter = 0x04;
+  const unsigned int rfbTightFill = 0x08;
+  const unsigned int rfbTightJpeg = 0x09;
+  const unsigned int rfbTightMaxSubencoding = 0x09;
+
+  // Filters to improve compression efficiency
+  const unsigned int rfbTightFilterCopy = 0x00;
+  const unsigned int rfbTightFilterPalette = 0x01;
+  const unsigned int rfbTightFilterGradient = 0x02;
+}
+
+#endif
diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx
new file mode 100644
index 0000000..e89a560
--- /dev/null
+++ b/common/rfb/TightEncoder.cxx
@@ -0,0 +1,193 @@
+/* Copyright (C) 2000-2003 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
+ * (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 <rdr/OutStream.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/TightEncoder.h>
+
+using namespace rfb;
+
+// Minimum amount of data to be compressed. This value should not be
+// changed, doing so will break compatibility with existing clients.
+#define TIGHT_MIN_TO_COMPRESS 12
+
+// Adjustable parameters.
+// FIXME: Get rid of #defines
+#define TIGHT_JPEG_MIN_RECT_SIZE 1024
+#define TIGHT_DETECT_MIN_WIDTH      8
+#define TIGHT_DETECT_MIN_HEIGHT     8
+
+//
+// Compression level stuff. The following array contains various
+// encoder parameters for each of 10 compression levels (0..9).
+// Last three parameters correspond to JPEG quality levels (0..9).
+//
+// NOTE: s_conf[9].maxRectSize should be >= s_conf[i].maxRectSize,
+// where i in [0..8]. RequiredBuffSize() method depends on this.
+// FIXME: Is this comment obsolete?
+//
+
+const TIGHT_CONF TightEncoder::conf[10] = {
+  {   512,   32,   6, 0, 0, 0,   4,  5 },
+  {  2048,   64,   6, 1, 1, 1,   8, 10 },
+  {  4096,  128,   8, 3, 3, 2,  24, 15 },
+  {  8192,  256,  12, 5, 5, 2,  32, 25 },
+  { 16384,  512,  12, 6, 7, 3,  32, 37 },
+  { 32768,  512,  12, 7, 8, 4,  32, 50 },
+  { 65536, 1024,  16, 7, 8, 5,  32, 60 },
+  { 65536, 1024,  16, 8, 9, 6,  64, 70 },
+  { 65536, 2048,  24, 9, 9, 7,  64, 75 },
+  { 65536, 2048,  32, 9, 9, 9,  96, 80 }
+};
+const int TightEncoder::defaultCompressLevel = 6;
+
+// FIXME: Not good to mirror TightEncoder's members here.
+static const TIGHT_CONF* s_pconf;
+static const TIGHT_CONF* s_pjconf;
+
+//
+// Including BPP-dependent implementation of the encoder.
+//
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/tightEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/tightEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/tightEncode.h>
+#undef BPP
+
+Encoder* TightEncoder::create(SMsgWriter* writer)
+{
+  return new TightEncoder(writer);
+} 
+
+TightEncoder::TightEncoder(SMsgWriter* writer_) : writer(writer_)
+{
+  setCompressLevel(defaultCompressLevel);
+  setQualityLevel(-1);
+}
+
+TightEncoder::~TightEncoder()
+{
+}
+
+void TightEncoder::setCompressLevel(int level)
+{
+  if (level >= 0 && level <= 9) {
+    pconf = &conf[level];
+  } else {
+    pconf = &conf[defaultCompressLevel];
+  }
+}
+
+void TightEncoder::setQualityLevel(int level)
+{
+  if (level >= 0 && level <= 9) {
+    pjconf = &conf[level];
+  } else {
+    pjconf = NULL;
+  }
+}
+
+int TightEncoder::getNumRects(const Rect &r)
+{
+  const unsigned int w = r.width();
+  const unsigned int h = r.height();
+
+  // Will this rectangle split into subrects?
+  bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
+  if (!rectTooBig)
+    return 1;
+
+  // Compute max sub-rectangle size.
+  const unsigned int subrectMaxWidth =
+    (w > pconf->maxRectWidth) ? pconf->maxRectWidth : w;
+  const unsigned int subrectMaxHeight =
+    pconf->maxRectSize / subrectMaxWidth;
+
+  // Return the number of subrects.
+  return (((w - 1) / pconf->maxRectWidth + 1) *
+          ((h - 1) / subrectMaxHeight + 1));
+}
+
+bool TightEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  // Shortcuts to rectangle coordinates and dimensions.
+  const int x = r.tl.x;
+  const int y = r.tl.y;
+  const unsigned int w = r.width();
+  const unsigned int h = r.height();
+
+  // Copy members of current TightEncoder instance to static variables.
+  s_pconf = pconf;
+  s_pjconf = pjconf;
+
+  // Encode small rects as is.
+  bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
+  if (!rectTooBig) {
+    writeSubrect(r, ig);
+    return true;
+  }
+
+  // Compute max sub-rectangle size.
+  const unsigned int subrectMaxWidth =
+    (w > pconf->maxRectWidth) ? pconf->maxRectWidth : w;
+  const unsigned int subrectMaxHeight =
+    pconf->maxRectSize / subrectMaxWidth;
+
+  // Split big rects into separately encoded subrects.
+  Rect sr;
+  unsigned int dx, dy, sw, sh;
+  for (dy = 0; dy < h; dy += subrectMaxHeight) {
+    for (dx = 0; dx < w; dx += pconf->maxRectWidth) {
+      sw = (dx + pconf->maxRectWidth < w) ? pconf->maxRectWidth : w - dx;
+      sh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+      sr.setXYWH(x + dx, y + dy, sw, sh);
+      writeSubrect(sr, ig);
+    }
+  }
+  return true;
+}
+
+void TightEncoder::writeSubrect(const Rect& r, ImageGetter* ig)
+{
+  rdr::U8* imageBuf = writer->getImageBuf(r.area());
+  ConnParams* cp = writer->getConnParams();
+  mos.clear();
+
+  switch (writer->bpp()) {
+  case 8:
+    tightEncode8(r, &mos, zos, imageBuf, cp, ig);  break;
+  case 16:
+    tightEncode16(r, &mos, zos, imageBuf, cp, ig); break;
+  case 32:
+    tightEncode32(r, &mos, zos, imageBuf, cp, ig); break;
+  }
+
+  writer->startRect(r, encodingTight);
+  rdr::OutStream* os = writer->getOutStream();
+  os->writeBytes(mos.data(), mos.length());
+  writer->endRect();
+}
diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h
new file mode 100644
index 0000000..9c11eaf
--- /dev/null
+++ b/common/rfb/TightEncoder.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2000-2003 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
+ * (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_TIGHTENCODER_H__
+#define __RFB_TIGHTENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <rfb/Encoder.h>
+
+// FIXME: Check if specifying extern "C" is really necessary.
+#include <stdio.h>
+extern "C" {
+#include "jpeg/jpeglib.h"
+}
+
+namespace rfb {
+
+  struct TIGHT_CONF {
+    unsigned int maxRectSize, maxRectWidth;
+    unsigned int monoMinRectSize;
+    int idxZlibLevel, monoZlibLevel, rawZlibLevel;
+    int idxMaxColorsDivisor;
+    int jpegQuality;
+  };
+
+  //
+  // Compression level stuff. The following array contains various
+  // encoder parameters for each of 10 compression levels (0..9).
+  // Last three parameters correspond to JPEG quality levels (0..9).
+  //
+  // NOTE: s_conf[9].maxRectSize should be >= s_conf[i].maxRectSize,
+  // where i in [0..8]. RequiredBuffSize() method depends on this.
+  // FIXME: Is this comment obsolete?
+  //
+
+  
+  class TightEncoder : public Encoder {
+  public:
+    static Encoder* create(SMsgWriter* writer);
+    virtual void setCompressLevel(int level);
+    virtual void setQualityLevel(int level);
+    virtual int getNumRects(const Rect &r);
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual ~TightEncoder();
+
+  private:
+    TightEncoder(SMsgWriter* writer);
+    void writeSubrect(const Rect& r, ImageGetter* ig);
+
+    SMsgWriter* writer;
+    rdr::MemOutStream mos;
+    rdr::ZlibOutStream zos[4];
+
+    static const int defaultCompressLevel;
+    static const TIGHT_CONF conf[];
+
+    const TIGHT_CONF* pconf;
+    const TIGHT_CONF* pjconf;
+  };
+
+}
+
+#endif
diff --git a/common/rfb/TightPalette.cxx b/common/rfb/TightPalette.cxx
new file mode 100644
index 0000000..c4ed04e
--- /dev/null
+++ b/common/rfb/TightPalette.cxx
@@ -0,0 +1,110 @@
+/* Copyright (C) 2000-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
+ * (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.
+ */
+
+//
+// TightPalette class implementation.
+//
+
+#include <rfb/TightPalette.h>
+
+using namespace rfb;
+
+TightPalette::TightPalette(int maxColors)
+{
+  setMaxColors(maxColors);
+  reset();
+}
+
+void TightPalette::reset()
+{
+  m_numColors = 0;
+  memset(m_hash, 0, 256 * sizeof(TightColorList *));
+}
+
+void TightPalette::setMaxColors(int maxColors)
+{
+  m_maxColors = maxColors;
+  if (m_maxColors < 0) {
+    m_maxColors = 0;
+  } else if (m_maxColors > 254) {
+    m_maxColors = 254;
+  }
+}
+
+int TightPalette::insert(rdr::U32 rgb, int numPixels)
+{
+  TightColorList *pnode;
+  TightColorList *prev_pnode = NULL;
+  int hash_key, idx, new_idx, count;
+
+  hash_key = hashFunc(rgb);
+
+  pnode = m_hash[hash_key];
+
+  while (pnode != NULL) {
+    if (pnode->rgb == rgb) {
+      // Such palette entry already exists.
+      new_idx = idx = pnode->idx;
+      count = m_entry[idx].numPixels + numPixels;
+      if (new_idx && m_entry[new_idx-1].numPixels < count) {
+        do {
+          m_entry[new_idx] = m_entry[new_idx-1];
+          m_entry[new_idx].listNode->idx = new_idx;
+          new_idx--;
+        }
+        while (new_idx && m_entry[new_idx-1].numPixels < count);
+
+        m_entry[new_idx].listNode = pnode;
+        pnode->idx = new_idx;
+      }
+      m_entry[new_idx].numPixels = count;
+      return m_numColors;
+    }
+    prev_pnode = pnode;
+    pnode = pnode->next;
+  }
+
+  // Check if the palette is full.
+  if (m_numColors == 256 || m_numColors == m_maxColors) {
+    m_numColors = 0;
+    return 0;
+  }
+
+  // Move palette entries with lesser pixel counts.
+  for ( idx = m_numColors;
+        idx > 0 && m_entry[idx-1].numPixels < numPixels;
+        idx-- ) {
+    m_entry[idx] = m_entry[idx-1];
+    m_entry[idx].listNode->idx = idx;
+  }
+
+  // Add new palette entry into the freed slot.
+  pnode = &m_list[m_numColors];
+  if (prev_pnode != NULL) {
+    prev_pnode->next = pnode;
+  } else {
+    m_hash[hash_key] = pnode;
+  }
+  pnode->next = NULL;
+  pnode->idx = idx;
+  pnode->rgb = rgb;
+  m_entry[idx].listNode = pnode;
+  m_entry[idx].numPixels = numPixels;
+
+  return ++m_numColors;
+}
diff --git a/common/rfb/TightPalette.h b/common/rfb/TightPalette.h
new file mode 100644
index 0000000..2f6448e
--- /dev/null
+++ b/common/rfb/TightPalette.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 2000-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
+ * (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.
+ */
+
+//
+// TightPalette class is a container for ordered color values. Colors
+// are keys in a hash where values are frequency counts. Also, there
+// is a list where colors are always sorted by these counts (more
+// frequent first).
+//
+
+#ifndef __RFB_TIGHTPALETTE_H__
+#define __RFB_TIGHTPALETTE_H__
+
+#include <string.h>
+#include <rdr/types.h>
+
+namespace rfb {
+
+  struct TightColorList {
+    TightColorList *next;
+    int idx;
+    rdr::U32 rgb;
+  };
+
+  struct TightPaletteEntry {
+    TightColorList *listNode;
+    int numPixels;
+  };
+
+  class TightPalette {
+
+  protected:
+
+    // FIXME: Bigger hash table? Better hash function?
+    inline static int hashFunc(rdr::U32 rgb) {
+      return (rgb ^ (rgb >> 13)) & 0xFF;
+    }
+
+  public:
+
+    TightPalette(int maxColors = 254);
+
+    //
+    // Re-initialize the object. This does not change maximum number
+    // of colors.
+    //
+    void reset();
+
+    //
+    // Set limit on the number of colors in the palette. Note that
+    // this value cannot exceed 254.
+    //
+    void setMaxColors(int maxColors);
+
+    //
+    // Insert new color into the palette, or increment its counter if
+    // the color is already there. Returns new number of colors, or
+    // zero if the palette is full. If the palette becomes full, it
+    // reports zero colors and cannot be used any more without calling
+    // reset().
+    //
+    int insert(rdr::U32 rgb, int numPixels);
+
+    //
+    // Return number of colors in the palette.
+    //
+    inline int getNumColors() const {
+      return m_numColors;
+    }
+
+    //
+    // Return the color specified by its index in the palette.
+    //
+    inline rdr::U32 getEntry(int i) const {
+      return (i < m_numColors) ? m_entry[i].listNode->rgb : (rdr::U32)-1;
+    }
+
+    //
+    // Return the pixel counter of the color specified by its index.
+    //
+    inline int getCount(int i) const {
+      return (i < m_numColors) ? m_entry[i].numPixels : 0;
+    }
+
+    //
+    // Return the index of a specified color.
+    //
+    inline rdr::U8 getIndex(rdr::U32 rgb) const {
+      TightColorList *pnode = m_hash[hashFunc(rgb)];
+      while (pnode != NULL) {
+        if (pnode->rgb == rgb) {
+          return (rdr::U8)pnode->idx;
+        }
+        pnode = pnode->next;
+      }
+      return 0xFF;              // no such color
+    }
+
+  protected:
+
+    int m_maxColors;
+    int m_numColors;
+
+    TightPaletteEntry m_entry[256];
+    TightColorList *m_hash[256];
+    TightColorList m_list[256];
+
+  };
+
+} // namespace rfb
+
+#endif // __RFB_TIGHTPALETTE_H__
diff --git a/common/rfb/Timer.cxx b/common/rfb/Timer.cxx
new file mode 100644
index 0000000..66fd2b1
--- /dev/null
+++ b/common/rfb/Timer.cxx
@@ -0,0 +1,179 @@
+/* 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.
+ */
+
+// -=- Timer.cxx
+
+#include <stdio.h>
+#ifdef WIN32
+#include <windows.h>
+#ifndef _WIN32_WCE
+#include <sys/timeb.h>
+#endif
+#endif
+#include <rfb/Timer.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+
+// XXX Lynx/OS 2.3: proto for gettimeofday()
+#ifdef Lynx
+#include <sys/proto.h>
+#endif
+
+using namespace rfb;
+
+#ifndef __NO_DEFINE_VLOG__
+static LogWriter vlog("Timer");
+#endif
+
+
+// Win32 does not provide gettimeofday, so we emulate it to simplify the
+// Timer code.
+
+#ifdef _WIN32
+static void gettimeofday(struct timeval* tv, void*)
+{
+  LARGE_INTEGER counts, countsPerSec;
+  static double usecPerCount = 0.0;
+
+  if (QueryPerformanceCounter(&counts)) {
+    if (usecPerCount == 0.0) {
+      QueryPerformanceFrequency(&countsPerSec);
+      usecPerCount = 1000000.0 / countsPerSec.QuadPart;
+    }
+
+    LONGLONG usecs = (LONGLONG)(counts.QuadPart * usecPerCount);
+    tv->tv_usec = (long)(usecs % 1000000);
+    tv->tv_sec = (long)(usecs / 1000000);
+
+  } else {
+#ifndef _WIN32_WCE
+    struct timeb tb;
+    ftime(&tb);
+    tv->tv_sec = tb.time;
+    tv->tv_usec = tb.millitm * 1000;
+#else
+    throw SystemException("QueryPerformanceCounter", GetLastError());
+#endif
+  }
+}
+#endif
+
+
+// Millisecond timeout processing helper functions
+
+inline static timeval addMillis(timeval inTime, int millis) {
+  int secs = millis / 1000;
+  millis = millis % 1000;
+  inTime.tv_sec += secs;
+  inTime.tv_usec += millis * 1000;
+  if (inTime.tv_usec >= 1000000) {
+    inTime.tv_sec++;
+    inTime.tv_usec -= 1000000;
+  }
+  return inTime;
+}
+
+inline static int diffTimeMillis(timeval later, timeval earlier) {
+  return ((later.tv_sec - earlier.tv_sec) * 1000) + ((later.tv_usec - earlier.tv_usec) / 1000);
+}
+
+std::list<Timer*> Timer::pending;
+
+int Timer::checkTimeouts() {
+  if (pending.empty())
+    return 0;
+  timeval now;
+  gettimeofday(&now, 0);
+  while (pending.front()->isBefore(now)) {
+    Timer* timer = pending.front();
+    pending.pop_front();
+    vlog.debug("handleTimeout(%p)", timer);
+    if (timer->cb->handleTimeout(timer)) {
+      timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
+      if (timer->isBefore(now)) {
+        // Time has jumped forwards!
+	      vlog.info("time has moved forwards!");
+        timer->dueTime = addMillis(now, timer->timeoutMs);
+      }
+      insertTimer(timer);
+    } else if (pending.empty()) {
+      return 0;
+    }
+  }
+  return getNextTimeout();
+}
+
+int Timer::getNextTimeout() {
+  timeval now;
+  gettimeofday(&now, 0);
+  int toWait = __rfbmax(1, diffTimeMillis(pending.front()->dueTime, now));
+  if (toWait > pending.front()->timeoutMs) {
+    if (toWait - pending.front()->timeoutMs < 1000) {
+      vlog.info("gettimeofday is broken...");
+      return toWait;
+    }
+    // Time has jumped backwards!
+    vlog.info("time has moved backwards!");
+    pending.front()->dueTime = now;
+    toWait = 1;
+  }
+  return toWait;
+}
+
+void Timer::insertTimer(Timer* t) {
+  std::list<Timer*>::iterator i;
+  for (i=pending.begin(); i!=pending.end(); i++) {
+    if (t->isBefore((*i)->dueTime)) {
+      pending.insert(i, t);
+      return;
+    }
+  }
+  pending.push_back(t);
+}
+
+void Timer::start(int timeoutMs_) {
+  timeval now;
+  gettimeofday(&now, 0);
+  stop();
+  timeoutMs = timeoutMs_;
+  dueTime = addMillis(now, timeoutMs);
+  insertTimer(this);
+}
+
+void Timer::stop() {
+  pending.remove(this);
+}
+
+bool Timer::isStarted() {
+  std::list<Timer*>::iterator i;
+  for (i=pending.begin(); i!=pending.end(); i++) {
+    if (*i == this)
+      return true;
+  }
+  return false;
+}
+
+int Timer::getTimeoutMs() {
+  return timeoutMs;
+}
+
+bool Timer::isBefore(timeval other) {
+  return (dueTime.tv_sec < other.tv_sec) ||
+    ((dueTime.tv_sec == other.tv_sec) &&
+     (dueTime.tv_usec < other.tv_usec));
+}
diff --git a/common/rfb/Timer.h b/common/rfb/Timer.h
new file mode 100644
index 0000000..e295b82
--- /dev/null
+++ b/common/rfb/Timer.h
@@ -0,0 +1,102 @@
+/* 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_TIMER_H__
+#define __RFB_TIMER_H__
+
+#include <list>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace rfb {
+
+  /* Timer
+
+     Cross-platform timeout handling.  The caller creates instances of Timer and passes a
+     Callback implementation to each.  The Callback will then be called with a pointer to
+     the Timer instance that timed-out when the timeout occurs.
+
+     The static methods of Timer are used by the main loop of the application both to
+     dispatch elapsed Timer callbacks and to determine how long to wait in select() for
+     the next timeout to occur.
+
+  */
+
+  struct Timer {
+
+    struct Callback {
+      // handleTimeout
+      //   Passed a pointer to the Timer that has timed out.  If the handler returns true
+      //   then the Timer is reset and left running, causing another timeout after the
+      //   appropriate interval.
+      //   If the handler returns false then the Timer is cancelled.
+      virtual bool handleTimeout(Timer* t) = 0;
+    };
+
+    // checkTimeouts()
+    //   Dispatches any elapsed Timers, and returns the number of milliseconds until the
+    //   next Timer will timeout.
+    static int checkTimeouts();
+
+    // getNextTimeout()
+    //   Returns the number of milliseconds until the next timeout, without dispatching
+    //   any elapsed Timers.
+    static int getNextTimeout();
+
+    // Create a Timer with the specified callback handler
+    Timer(Callback* cb_) {cb = cb_;}
+    ~Timer() {stop();}
+
+    // startTimer
+    //   Starts the timer, causing a timeout after the specified number of milliseconds.
+    //   If the timer is already active then it will be implicitly cancelled and re-started.
+    void start(int timeoutMs_);
+
+    // stopTimer
+    //   Cancels the timer.
+    void stop();
+
+    // isStarted
+    //   Determines whether the timer is started.
+    bool isStarted();
+
+    // getTimeoutMs
+    //   Determines the previously used timeout value, if any.
+    //   Usually used with isStarted() to get the _current_ timeout.
+    int getTimeoutMs();
+
+    // isBefore
+    //   Determine whether the Timer will timeout before the specified time.
+    bool isBefore(timeval other);
+
+  protected:
+    timeval dueTime;
+    int timeoutMs;
+    Callback* cb;
+
+    static void insertTimer(Timer* t);
+    // The list of currently active Timers, ordered by time left until timeout.
+    static std::list<Timer*> pending;
+  };
+
+};
+
+#endif
diff --git a/common/rfb/TransImageGetter.cxx b/common/rfb/TransImageGetter.cxx
new file mode 100644
index 0000000..82c291b
--- /dev/null
+++ b/common/rfb/TransImageGetter.cxx
@@ -0,0 +1,278 @@
+/* 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 <stdlib.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/ColourMap.h>
+#include <rfb/TrueColourMap.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/ColourCube.h>
+#include <rfb/TransImageGetter.h>
+
+using namespace rfb;
+
+const PixelFormat bgr233PF(8, 8, false, true, 7, 7, 3, 0, 3, 6);
+
+static void noTransFn(void* table_,
+                      const PixelFormat& inPF, void* inPtr, int inStride,
+                      const PixelFormat& outPF, void* outPtr, int outStride,
+                      int width, int height)
+{
+  rdr::U8* ip = (rdr::U8*)inPtr;
+  rdr::U8* op = (rdr::U8*)outPtr;
+  int inStrideBytes = inStride * (inPF.bpp/8);
+  int outStrideBytes = outStride * (outPF.bpp/8);
+  int widthBytes = width * (outPF.bpp/8);
+
+  while (height > 0) {
+    memcpy(op, ip, widthBytes);
+    ip += inStrideBytes;
+    op += outStrideBytes;
+    height--;
+  }
+}
+
+#define BPPOUT 8
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+#define BPPOUT 16
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+#define BPPOUT 32
+#include "transInitTempl.h"
+#define BPPIN 8
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 16
+#include "transTempl.h"
+#undef BPPIN
+#define BPPIN 32
+#include "transTempl.h"
+#undef BPPIN
+#undef BPPOUT
+
+
+// Translation functions.  Note that transSimple* is only used for 8/16bpp and
+// transRGB* is used for 16/32bpp
+
+static transFnType transSimpleFns[][3] = {
+  { transSimple8to8,  transSimple8to16,  transSimple8to32 },
+  { transSimple16to8, transSimple16to16, transSimple16to32 },
+};
+static transFnType transRGBFns[][3] = {
+  { transRGB16to8, transRGB16to16, transRGB16to32 },
+  { transRGB32to8, transRGB32to16, transRGB32to32 }
+};
+static transFnType transRGBCubeFns[][3] = {
+  { transRGBCube16to8, transRGBCube16to16, transRGBCube16to32 },
+  { transRGBCube32to8, transRGBCube32to16, transRGBCube32to32 }
+};
+
+// Table initialisation functions.
+
+typedef void (*initCMtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+                                 ColourMap* cm, const PixelFormat& outPF);
+typedef void (*initTCtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+                                 const PixelFormat& outPF);
+typedef void (*initCMtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+                                   ColourMap* cm, ColourCube* cube);
+typedef void (*initTCtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
+                                   ColourCube* cube);
+
+
+static initCMtoTCFnType initSimpleCMtoTCFns[] = {
+    initSimpleCMtoTC8, initSimpleCMtoTC16, initSimpleCMtoTC32
+};
+
+static initTCtoTCFnType initSimpleTCtoTCFns[] = {
+    initSimpleTCtoTC8, initSimpleTCtoTC16, initSimpleTCtoTC32
+};
+
+static initCMtoCubeFnType initSimpleCMtoCubeFns[] = {
+    initSimpleCMtoCube8, initSimpleCMtoCube16, initSimpleCMtoCube32
+};
+
+static initTCtoCubeFnType initSimpleTCtoCubeFns[] = {
+    initSimpleTCtoCube8, initSimpleTCtoCube16, initSimpleTCtoCube32
+};
+
+static initTCtoTCFnType initRGBTCtoTCFns[] = {
+    initRGBTCtoTC8, initRGBTCtoTC16, initRGBTCtoTC32
+};
+
+static initTCtoCubeFnType initRGBTCtoCubeFns[] = {
+    initRGBTCtoCube8, initRGBTCtoCube16, initRGBTCtoCube32
+};
+
+
+TransImageGetter::TransImageGetter(bool econ)
+  : economic(econ), pb(0), table(0), transFn(0), cube(0)
+{
+}
+
+TransImageGetter::~TransImageGetter()
+{
+  delete [] table;
+}
+
+void TransImageGetter::init(PixelBuffer* pb_, const PixelFormat& out,
+                            SMsgWriter* writer, ColourCube* cube_)
+{
+  pb = pb_;
+  outPF = out;
+  transFn = 0;
+  cube = cube_;
+  const PixelFormat& inPF = pb->getPF();
+
+  if ((inPF.bpp != 8) && (inPF.bpp != 16) && (inPF.bpp != 32))
+    throw Exception("TransImageGetter: bpp in not 8, 16 or 32");
+
+  if ((outPF.bpp != 8) && (outPF.bpp != 16) && (outPF.bpp != 32))
+    throw Exception("TransImageGetter: bpp out not 8, 16 or 32");
+
+  if (!outPF.trueColour) {
+    if (outPF.bpp != 8)
+      throw Exception("TransImageGetter: outPF has color map but not 8bpp");
+
+    if (!inPF.trueColour) {
+      if (inPF.bpp != 8)
+        throw Exception("TransImageGetter: inPF has colorMap but not 8bpp");
+
+      // CM to CM/Cube
+
+      if (cube) {
+        transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+        (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, inPF,
+                                                pb->getColourMap(), cube);
+      } else {
+        transFn = noTransFn;
+        setColourMapEntries(0, 256, writer);
+      }
+      return;
+    }
+
+    // TC to CM/Cube
+
+    ColourCube defaultCube(6,6,6);
+    if (!cube) cube = &defaultCube;
+
+    if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
+      transFn = transRGBCubeFns[inPF.bpp/32][outPF.bpp/16];
+      (*initRGBTCtoCubeFns[outPF.bpp/16]) (&table, inPF, cube);
+    } else {
+      transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+      (*initSimpleTCtoCubeFns[outPF.bpp/16]) (&table, inPF, cube);
+    }
+
+    if (cube != &defaultCube)
+      return;
+
+    if (writer) writer->writeSetColourMapEntries(0, 216, cube);
+    cube = 0;
+    return;
+  }
+
+  if (inPF.equal(outPF)) {
+    transFn = noTransFn;
+    return;
+  }
+
+  if (!inPF.trueColour) {
+
+    // CM to TC
+
+    if (inPF.bpp != 8)
+      throw Exception("TransImageGetter: inPF has colorMap but not 8bpp");
+    transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+    (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, pb->getColourMap(),
+                                          outPF);
+    return;
+  }
+
+  // TC to TC
+
+  if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
+    transFn = transRGBFns[inPF.bpp/32][outPF.bpp/16];
+    (*initRGBTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
+  } else {
+    transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
+    (*initSimpleTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
+  }
+}
+
+void TransImageGetter::setColourMapEntries(int firstCol, int nCols,
+                                           SMsgWriter* writer)
+{
+  if (nCols == 0)
+    nCols = (1 << pb->getPF().depth) - firstCol;
+  if (pb->getPF().trueColour) return; // shouldn't be called in this case
+
+  if (outPF.trueColour) {
+    (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, pb->getPF(),
+                                          pb->getColourMap(), outPF);
+  } else if (cube) {
+    (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, pb->getPF(),
+                                            pb->getColourMap(), cube);
+  } else if (writer && pb->getColourMap()) {
+    writer->writeSetColourMapEntries(firstCol, nCols, pb->getColourMap());
+  }
+}
+
+void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride)
+{
+  if (!transFn)
+    throw Exception("TransImageGetter: not initialised yet");
+
+  int inStride;
+  const rdr::U8* inPtr = pb->getPixelsR(r.translate(offset.negate()), &inStride);
+
+  if (!outStride) outStride = r.width();
+
+  (*transFn)(table, pb->getPF(), (void*)inPtr, inStride,
+             outPF, outPtr, outStride, r.width(), r.height());
+}
+
+void TransImageGetter::translatePixels(void* inPtr, void* outPtr,
+                                       int nPixels) const
+{
+  (*transFn)(table, pb->getPF(), inPtr, nPixels,
+             outPF, outPtr, nPixels, nPixels, 1);
+}
diff --git a/common/rfb/TransImageGetter.h b/common/rfb/TransImageGetter.h
new file mode 100644
index 0000000..5328e6d
--- /dev/null
+++ b/common/rfb/TransImageGetter.h
@@ -0,0 +1,104 @@
+/* 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.
+ */
+//
+// TransImageGetter - class to perform translation between pixel formats,
+// implementing the ImageGetter interface.
+//
+
+#ifndef __RFB_TRANSIMAGEGETTER_H__
+#define __RFB_TRANSIMAGEGETTER_H__
+
+#include <rfb/Rect.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ImageGetter.h>
+
+namespace rfb {
+  typedef void (*transFnType)(void* table_,
+                              const PixelFormat& inPF, void* inPtr,
+                              int inStride,
+                              const PixelFormat& outPF, void* outPtr,
+                              int outStride, int width, int height);
+
+  class SMsgWriter;
+  class ColourMap;
+  class PixelBuffer;
+  class ColourCube;
+
+  class TransImageGetter : public ImageGetter {
+  public:
+
+    TransImageGetter(bool econ=false);
+    virtual ~TransImageGetter();
+
+    // init() is called to initialise the translation tables.  The PixelBuffer
+    // argument gives the source data and format details, outPF gives the
+    // client's pixel format.  If the client has a colour map, then the writer
+    // argument is used to send a SetColourMapEntries message to the client.
+
+    void init(PixelBuffer* pb, const PixelFormat& outPF, SMsgWriter* writer=0,
+              ColourCube* cube=0);
+
+    // setColourMapEntries() is called when the PixelBuffer has a colour map
+    // which has changed.  firstColour and nColours specify which part of the
+    // colour map has changed.  If nColours is 0, this means the rest of the
+    // colour map.  The PixelBuffer previously passed to init() must have a
+    // valid ColourMap object.  If the client also has a colour map, then the
+    // writer argument is used to send a SetColourMapEntries message to the
+    // client.  If the client is true colour then instead we update the
+    // internal translation table - in this case the caller should also make
+    // sure that the client receives an update of the relevant parts of the
+    // framebuffer (the simplest thing to do is just update the whole
+    // framebuffer, though it is possible to be smarter than this).
+
+    void setColourMapEntries(int firstColour, int nColours,
+                             SMsgWriter* writer=0);
+
+    // getImage() gets the given rectangle of data from the PixelBuffer,
+    // translates it into the client's pixel format and puts it in the buffer
+    // pointed to by the outPtr argument.  The optional outStride argument can
+    // be used where padding is required between the output scanlines (the
+    // padding will be outStride-r.width() pixels).
+    void getImage(void* outPtr, const Rect& r, int outStride=0);
+
+    // translatePixels() translates the given number of pixels from inPtr,
+    // putting it into the buffer pointed to by outPtr.  The pixels at inPtr
+    // should be in the same format as the PixelBuffer, and the translated
+    // pixels will be in the format previously given by the outPF argument to
+    // init().  Note that this call does not use the PixelBuffer's pixel data.
+    void translatePixels(void* inPtr, void* outPtr, int nPixels) const;
+
+    // setPixelBuffer() changes the pixel buffer to be used.  The new pixel
+    // buffer MUST have the same pixel format as the old one - if not you
+    // should call init() instead.
+    void setPixelBuffer(PixelBuffer* pb_) { pb = pb_; }
+
+    // setOffset() sets an offset which is subtracted from the coordinates of
+    // the rectangle given to getImage().
+    void setOffset(const Point& offset_) { offset = offset_; }
+
+  private:
+    bool economic;
+    PixelBuffer* pb;
+    PixelFormat outPF;
+    rdr::U8* table;
+    transFnType transFn;
+    ColourCube* cube;
+    Point offset;
+  };
+}
+#endif
diff --git a/common/rfb/TransferQueue.cxx b/common/rfb/TransferQueue.cxx
new file mode 100644
index 0000000..0180752
--- /dev/null
+++ b/common/rfb/TransferQueue.cxx
@@ -0,0 +1,311 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- TransferQueue.
+
+#include <rfb/TransferQueue.h>
+
+using namespace rfb;
+
+TransferQueue::TransferQueue()
+{
+	 m_numEntries = 0;
+     m_pEntries = NULL;
+}
+
+TransferQueue::~TransferQueue()
+{
+  free();
+}
+
+void
+TransferQueue::add(TransferQueue *pTQ)
+{
+  for (unsigned int i = 0; i < pTQ->getNumEntries(); i++) {
+    add(pTQ->getLocPathAt(i), pTQ->getRemPathAt(i),	pTQ->getLocNameAt(i), 
+      pTQ->getRemNameAt(i), pTQ->getSizeAt(i), pTQ->getDataAt(i), pTQ->getFlagsAt(i));
+  }
+}
+
+void
+TransferQueue::add(char *pLocPath, char *pRemPath, FileInfo *pFI, unsigned int flags)
+{
+  char locPath[FT_FILENAME_SIZE];
+  char remPath[FT_FILENAME_SIZE];
+  strcpy(locPath, pLocPath);
+  strcpy(remPath, pRemPath);
+  
+  for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+    add(locPath, remPath, pFI->getNameAt(i), pFI->getNameAt(i), 
+      pFI->getSizeAt(i), pFI->getDataAt(i), (pFI->getFlagsAt(i) | flags));
+  }
+}
+
+void 
+TransferQueue::add(char *pLocPath, char *pRemPath, char *pLocName, char *pRemName, 
+                   unsigned int size, unsigned int data, unsigned int flags)
+{
+  FILEINFOEX *pTemporary = new FILEINFOEX[m_numEntries + 1];
+  if (m_numEntries != 0) 
+    memcpy(pTemporary, m_pEntries, m_numEntries * sizeof(FILEINFOEX));
+  
+  strcpy(pTemporary[m_numEntries].locPath, pLocPath);
+  strcpy(pTemporary[m_numEntries].locName, pLocName);
+  strcpy(pTemporary[m_numEntries].remPath, pRemPath);
+  strcpy(pTemporary[m_numEntries].remName, pRemName);
+  
+  pTemporary[m_numEntries].info.size = size;
+  pTemporary[m_numEntries].info.data = data;
+  pTemporary[m_numEntries].info.flags = flags;
+  
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  
+  m_pEntries = pTemporary;
+  pTemporary = NULL;
+  m_numEntries++;
+}
+
+char *
+TransferQueue::getLocPathAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].locPath;
+  }
+  return NULL;
+}
+
+char *
+TransferQueue::getLocNameAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].locName;
+  }
+  return NULL;
+}
+
+char *
+TransferQueue::getRemPathAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].remPath;
+  }
+  return NULL;
+}
+
+char *
+TransferQueue::getRemNameAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].remName;
+  }
+  return NULL;
+}
+
+char *
+TransferQueue::getFullLocPathAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    sprintf(m_szFullLocPath, "%s\\%s", getLocPathAt(number), getLocNameAt(number));
+    return m_szFullLocPath;
+  }
+  return NULL;
+}
+
+char *
+TransferQueue::getFullRemPathAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    sprintf(m_szFullRemPath, "%s\\%s", getRemPathAt(number), getRemNameAt(number));
+    return m_szFullRemPath;
+  }
+  return NULL;
+}
+
+SIZEDATAFLAGSINFO * 
+TransferQueue::getSizeDataFlagsAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return &m_pEntries[number].info;
+  }
+  return NULL;
+}
+
+bool 
+TransferQueue::setLocPathAt(unsigned int number, char *pName)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    strcpy(m_pEntries[number].locPath, pName);
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setLocNameAt(unsigned int number, char *pName)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    strcpy(m_pEntries[number].locName, pName);
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setRemPathAt(unsigned int number, char *pName)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    strcpy(m_pEntries[number].remPath, pName);
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setRemNameAt(unsigned int number, char *pName)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    strcpy(m_pEntries[number].remName, pName);
+    return true;
+  }
+  return false;
+}
+
+unsigned int
+TransferQueue::getSizeAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].info.size;
+  }
+  return 0;
+}
+
+unsigned int
+TransferQueue::getDataAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].info.data;
+  }
+  return 0;
+}
+
+unsigned int 
+TransferQueue::getFlagsAt(unsigned int number)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    return m_pEntries[number].info.flags;
+  }
+  return 0;
+}
+
+bool 
+TransferQueue::setSizeAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.size = value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setDataAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.data = value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setFlagsAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.flags = m_pEntries[number].info.flags | value;
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::clearFlagAt(unsigned int number, unsigned int value)
+{
+  if ((number >= 0) && (number < m_numEntries)) {
+    m_pEntries[number].info.flags = (m_pEntries[number].info.flags & (value ^ 0xFFFFFFFF));
+    return true;
+  }
+  return false;
+}
+
+bool 
+TransferQueue::setFlagToAll(unsigned int flag)
+{
+  for (unsigned int i = 0; i < m_numEntries; i++) {
+    setFlagsAt(i, flag);
+  }
+  return true;
+}
+
+bool 
+TransferQueue::deleteAt(unsigned int number)
+{
+  if ((number >= m_numEntries) || (number < 0)) return false;
+  
+  FILEINFOEX *pTemporary = new FILEINFOEX[m_numEntries - 1];
+  
+  if (number == 0) {
+    memcpy(pTemporary, &m_pEntries[1], (m_numEntries - 1) * sizeof(FILEINFOEX));
+  } else {
+    memcpy(pTemporary, m_pEntries, number * sizeof(FILEINFOEX));
+    if (number != (m_numEntries - 1)) 
+      memcpy(&pTemporary[number], &m_pEntries[number + 1], (m_numEntries - number - 1) * sizeof(FILEINFOEX));
+  }
+  
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  m_pEntries = pTemporary;
+  pTemporary = NULL;
+  m_numEntries--;
+  return true;
+}
+
+unsigned int 
+TransferQueue::getNumEntries()
+{
+  return m_numEntries;
+}
+
+void 
+TransferQueue::free()
+{
+  if (m_pEntries != NULL) {
+    delete [] m_pEntries;
+    m_pEntries = NULL;
+  }
+  m_numEntries = 0;
+}
diff --git a/common/rfb/TransferQueue.h b/common/rfb/TransferQueue.h
new file mode 100644
index 0000000..ba748e0
--- /dev/null
+++ b/common/rfb/TransferQueue.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- TransferQueue.
+
+#ifndef __RFB_TRANSFERQUEUE_H__
+#define __RFB_TRANSFERQUEUE_H__
+
+#include <stdlib.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb/fttypes.h>
+
+namespace rfb {
+  class TransferQueue  
+  {
+  public:
+    TransferQueue();
+    ~TransferQueue();
+
+    void add(TransferQueue *pTQ);
+    void add(char *pLocPath, char*pRemPath, FileInfo *pFI, unsigned int flags);
+    void add(char *pLocPath, char *pRemPath, char *pLocName, char *pRemName,
+      unsigned int size, unsigned int data, unsigned int flags);
+    
+    char *getLocPathAt(unsigned int number);
+    char *getLocNameAt(unsigned int number);
+    char *getRemPathAt(unsigned int number);
+    char *getRemNameAt(unsigned int number);
+    
+    char *getFullLocPathAt(unsigned int number);
+    char *getFullRemPathAt(unsigned int number);
+    
+    bool setLocPathAt(unsigned int number, char *pName);
+    bool setLocNameAt(unsigned int number, char *pName);
+    bool setRemPathAt(unsigned int number, char *pName);
+    bool setRemNameAt(unsigned int number, char *pName);
+    
+    unsigned int getSizeAt(unsigned int number);
+    unsigned int getDataAt(unsigned int number);
+    unsigned int getFlagsAt(unsigned int number);
+    
+    SIZEDATAFLAGSINFO * getSizeDataFlagsAt(unsigned int number);
+    
+    
+    bool setSizeAt(unsigned int number, unsigned int value);
+    bool setDataAt(unsigned int number, unsigned int value);
+    bool setFlagsAt(unsigned int number, unsigned int value);
+    bool clearFlagAt(unsigned int number, unsigned int value);
+    bool setFlagToAll(unsigned int flag);
+    
+    bool deleteAt(unsigned int number);
+    
+    unsigned int getNumEntries();
+    
+    void free();
+    
+  private:
+    FILEINFOEX *m_pEntries;
+    unsigned int m_numEntries;
+    
+    char m_szFullLocPath[FT_FILENAME_SIZE];
+    char m_szFullRemPath[FT_FILENAME_SIZE];
+  };
+}
+
+#endif // __RFB_TRANSFERQUEUE_H__
diff --git a/common/rfb/TrueColourMap.h b/common/rfb/TrueColourMap.h
new file mode 100644
index 0000000..1e87fa4
--- /dev/null
+++ b/common/rfb/TrueColourMap.h
@@ -0,0 +1,42 @@
+/* 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_TRUECOLOURMAP_H__
+#define __RFB_TRUECOLOURMAP_H__
+
+#include <rfb/ColourMap.h>
+
+namespace rfb {
+
+  class TrueColourMap : public ColourMap {
+  public:
+    TrueColourMap(const PixelFormat& pf_) : pf(pf_) {}
+
+    virtual void lookup(int i, int* r, int* g, int* b)
+    {
+      *r = (((i >> pf.redShift  ) & pf.redMax)
+            * 65535 + pf.redMax/2) / pf.redMax;
+      *g = (((i >> pf.greenShift) & pf.greenMax)
+            * 65535 + pf.greenMax/2) / pf.greenMax;
+      *b = (((i >> pf.blueShift) & pf.blueMax)
+            * 65535 + pf.blueMax/2) / pf.blueMax;
+    }
+  private:
+    PixelFormat pf;
+  };
+}
+#endif
diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx
new file mode 100644
index 0000000..14ac49d
--- /dev/null
+++ b/common/rfb/UpdateTracker.cxx
@@ -0,0 +1,156 @@
+/* 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.
+ */
+
+// -=- rfbUpdateTracker.cpp
+//
+// Tracks updated regions and a region-copy event, too
+//
+
+#include <assert.h>
+
+#include <rfb/UpdateTracker.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("UpdateTracker");
+
+
+// -=- ClippingUpdateTracker
+
+void ClippingUpdateTracker::add_changed(const Region &region) {
+  ut->add_changed(region.intersect(clipRect));
+}
+
+void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+  // Clip the destination to the display area
+  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(clipRect);
+  if (!tmp.is_empty()) {
+    // Translate the source back to a destination region
+    tmp.translate(delta);
+
+    // Pass the copy region to the child tracker
+    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())
+    ut->add_changed(tmp);
+}
+
+// SimpleUpdateTracker
+
+SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
+  copy_enabled = use_copyrect;
+}
+
+SimpleUpdateTracker::~SimpleUpdateTracker() {
+}
+
+void SimpleUpdateTracker::enable_copyrect(bool enable) {
+  if (!enable && copy_enabled) {
+    add_changed(copied);
+    copied.clear();
+  }
+  copy_enabled=enable;
+}
+
+void SimpleUpdateTracker::add_changed(const Region &region) {
+  changed.assign_union(region);
+}
+
+void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+  // Do we support copyrect?
+  if (!copy_enabled) {
+    add_changed(dest);
+    return;
+  }
+
+  // Is there anything to do?
+  if (dest.is_empty()) return;
+
+  // Calculate whether any of this copy can be treated as a continuation
+  // of an earlier one
+  Region src = dest;
+  src.translate(delta.negate());
+  Region overlap = src.intersect(copied);
+
+  if (overlap.is_empty()) {
+    // There is no overlap
+
+    Rect newbr = dest.get_bounding_rect();
+    Rect oldbr = copied.get_bounding_rect();
+    if (oldbr.area() > newbr.area()) {
+      // Old copyrect is (probably) bigger - use it
+      changed.assign_union(dest);
+    } else {
+      // New copyrect is probably bigger
+      // Use the new one
+      // But be careful not to copy stuff that still needs
+      // to be updated.
+      Region invalid_src = src.intersect(changed);
+      invalid_src.translate(delta);
+      changed.assign_union(invalid_src);
+      changed.assign_union(copied);
+      copied = dest;
+      copy_delta = delta;
+    }
+    return;
+  }
+
+  Region invalid_src = overlap.intersect(changed);
+  invalid_src.translate(delta);
+  changed.assign_union(invalid_src);
+  
+  overlap.translate(delta);
+
+  Region nonoverlapped_copied = dest.union_(copied).subtract(overlap);
+  changed.assign_union(nonoverlapped_copied);
+
+  copied = overlap;
+  copy_delta = copy_delta.translate(delta);
+
+  return;
+}
+
+void SimpleUpdateTracker::subtract(const Region& region) {
+  copied.assign_subtract(region);
+  changed.assign_subtract(region);
+}
+
+void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
+{
+  copied.assign_subtract(changed);
+  info->changed = changed.intersect(clip);
+  info->copied = copied.intersect(clip);
+  info->copy_delta = copy_delta;
+}
+
+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/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h
new file mode 100644
index 0000000..5b51317
--- /dev/null
+++ b/common/rfb/UpdateTracker.h
@@ -0,0 +1,103 @@
+/* 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_UPDATETRACKER_INCLUDED__
+#define __RFB_UPDATETRACKER_INCLUDED__
+
+#include <rfb/Rect.h>
+#include <rfb/Region.h>
+#include <rfb/PixelBuffer.h>
+
+namespace rfb {
+
+  class UpdateInfo {
+  public:
+    Region changed;
+    Region copied;
+    Point copy_delta;
+    bool is_empty() const {
+      return copied.is_empty() && changed.is_empty();
+    }
+    int numRects() const {
+      return copied.numRects() + changed.numRects();
+    }
+  };
+
+  class UpdateTracker {
+  public:
+    UpdateTracker() {};
+    virtual ~UpdateTracker() {};
+
+    virtual void add_changed(const Region &region) = 0;
+    virtual void add_copied(const Region &dest, const Point &delta) = 0;
+  };
+
+  class ClippingUpdateTracker : public UpdateTracker {
+  public:
+    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* ut;
+    Region clipRect;
+  };
+
+  class SimpleUpdateTracker : public UpdateTracker {
+  public:
+    SimpleUpdateTracker(bool use_copyrect=true);
+    virtual ~SimpleUpdateTracker();
+
+    virtual void enable_copyrect(bool enable);
+
+    virtual void add_changed(const Region &region);
+    virtual void add_copied(const Region &dest, const Point &delta);
+    virtual void subtract(const Region& region);
+
+    // Fill the supplied UpdateInfo structure with update information
+    virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
+
+    // Copy the contained updates to another tracker
+    virtual void copyTo(UpdateTracker* to) const;
+
+
+    // Get the changed/copied regions
+    const Region& get_changed() const {return changed;}
+    const Region& get_copied() const {return copied;}
+    const Point& get_delta() const {return copy_delta;}
+
+    // Move the entire update region by an offset
+    void translate(const Point& p) {changed.translate(p); copied.translate(p);}
+
+    virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();}
+
+    virtual void clear() {changed.clear(); copied.clear();};
+  protected:
+    Region changed;
+    Region copied;
+    Point copy_delta;
+    bool copy_enabled;
+  };
+
+}
+
+#endif // __RFB_UPDATETRACKER_INCLUDED__
diff --git a/common/rfb/UserPasswdGetter.h b/common/rfb/UserPasswdGetter.h
new file mode 100644
index 0000000..18b0bae
--- /dev/null
+++ b/common/rfb/UserPasswdGetter.h
@@ -0,0 +1,30 @@
+/* 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_USERPASSWDGETTER_H__
+#define __RFB_USERPASSWDGETTER_H__
+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).
+    virtual void getUserPasswd(char** user, char** password)=0;
+  };
+}
+#endif
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
new file mode 100644
index 0000000..fe60e43
--- /dev/null
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -0,0 +1,714 @@
+/* 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 <rfb/VNCSConnectionST.h>
+#include <rfb/LogWriter.h>
+#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>
+
+using namespace rfb;
+
+static LogWriter vlog("VNCSConnST");
+
+VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
+                                   bool reverse)
+  : 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)), m_pFileTransfer(0)
+{
+  setStreams(&sock->inStream(), &sock->outStream());
+  peerEndpoint.buf = sock->getPeerEndpoint();
+  VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
+
+  // Configure the socket
+  setSocketTimeouts();
+  lastEventTime = time(0);
+
+  // Add this client to the VNCServerST
+  if (server->m_pFTManager != NULL) {
+    SFileTransfer *pFT = server->m_pFTManager->createObject(sock);
+    if (pFT != NULL) {
+      m_pFileTransfer = pFT;
+    }
+  }
+
+  server->clients.push_front(this);
+}
+
+
+VNCSConnectionST::~VNCSConnectionST()
+{
+  // If we reach here then VNCServerST is deleting us!
+  VNCServerST::connectionsLog.write(1,"closed: %s (%s)",
+                                    peerEndpoint.buf,
+                                    (closeReason.buf) ? closeReason.buf : "");
+
+  // Release any keys the client still had pressed
+  std::set<rdr::U32>::iterator i;
+  for (i=pressedKeys.begin(); i!=pressedKeys.end(); i++)
+    server->desktop->keyEvent(*i, false);
+  if (server->pointerClient == this)
+    server->pointerClient = 0;
+
+  if (m_pFileTransfer) 
+    server->m_pFTManager->destroyObject(m_pFileTransfer);
+
+  // Remove this client from the server
+  server->clients.remove(this);
+
+}
+
+
+// Methods called from VNCServerST
+
+bool VNCSConnectionST::init()
+{
+  try {
+    initialiseProtocol();
+  } catch (rdr::Exception& e) {
+    close(e.str());
+    return false;
+  }
+  return true;
+}
+
+void VNCSConnectionST::close(const char* reason)
+{
+  // Log the reason for the close
+  if (!closeReason.buf)
+    closeReason.buf = strDup(reason);
+  else
+    vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
+
+  if (authenticated()) {
+      server->lastDisconnectTime = time(0);
+  }
+
+  // Just shutdown the socket and mark our state as closing.  Eventually the
+  // calling code will call VNCServerST's removeSocket() method causing us to
+  // be deleted.
+  sock->shutdown();
+  setState(RFBSTATE_CLOSING);
+}
+
+
+void VNCSConnectionST::processMessages()
+{
+  if (state() == RFBSTATE_CLOSING) return;
+  try {
+    // - Now set appropriate socket timeouts and process data
+    setSocketTimeouts();
+    bool clientsReadyBefore = server->clientsReadyForUpdate();
+
+    while (getInStream()->checkNoWait(1)) {
+      processMsg();
+    }
+
+    if (!clientsReadyBefore && !requested.is_empty())
+      server->desktop->framebufferUpdateRequest();
+  } catch (rdr::EndOfStream&) {
+    close("Clean disconnection");
+  } catch (rdr::Exception &e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::writeFramebufferUpdateOrClose()
+{
+  try {
+    writeFramebufferUpdate();
+  } catch(rdr::Exception &e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::pixelBufferChange()
+{
+  try {
+    if (!authenticated()) return;
+    if (cp.width && cp.height && (server->pb->width() != cp.width ||
+                                  server->pb->height() != cp.height))
+    {
+      // We need to clip the next update to the new size, but also add any
+      // extra bits if it's bigger.  If we wanted to do this exactly, something
+      // like the code below would do it, but at the moment we just update the
+      // entire new size.  However, we do need to clip the renderedCursorRect
+      // because that might be added to updates in writeFramebufferUpdate().
+
+      //updates.intersect(server->pb->getRect());
+      //
+      //if (server->pb->width() > cp.width)
+      //  updates.add_changed(Rect(cp.width, 0, server->pb->width(),
+      //                           server->pb->height()));
+      //if (server->pb->height() > cp.height)
+      //  updates.add_changed(Rect(0, cp.height, cp.width,
+      //                           server->pb->height()));
+
+      renderedCursorRect = renderedCursorRect.intersect(server->pb->getRect());
+
+      cp.width = server->pb->width();
+      cp.height = server->pb->height();
+      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
+    // work out what's actually changed.
+    updates.clear();
+    updates.add_changed(server->pb->getRect());
+    vlog.debug("pixel buffer changed - re-initialising image getter");
+    image_getter.init(server->pb, cp.pf(), writer());
+    if (writer()->needFakeUpdate())
+      writeFramebufferUpdate();
+  } catch(rdr::Exception &e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::setColourMapEntriesOrClose(int firstColour,int nColours)
+{
+  try {
+    setColourMapEntries(firstColour, nColours);
+  } catch(rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::bell()
+{
+  try {
+    if (state() == RFBSTATE_NORMAL) writer()->writeBell();
+  } catch(rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::serverCutText(const char *str, int len)
+{
+  try {
+    if (!(accessRights & AccessCutText)) return;
+    if (!rfb::Server::sendCutText) return;
+    if (state() == RFBSTATE_NORMAL)
+      writer()->writeServerCutText(str, len);
+  } catch(rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+void VNCSConnectionST::setCursorOrClose()
+{
+  try {
+    setCursor();
+  } catch(rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+
+int VNCSConnectionST::checkIdleTimeout()
+{
+  int idleTimeout = rfb::Server::idleTimeout;
+  if (idleTimeout == 0) return 0;
+  if (state() != RFBSTATE_NORMAL && idleTimeout < 15)
+    idleTimeout = 15; // minimum of 15 seconds while authenticating
+  time_t now = time(0);
+  if (now < lastEventTime) {
+    // Someone must have set the time backwards.  Set lastEventTime so that the
+    // idleTimeout will count from now.
+    vlog.info("Time has gone backwards - resetting idle timeout");
+    lastEventTime = now;
+  }
+  int timeLeft = lastEventTime + idleTimeout - now;
+  if (timeLeft < -60) {
+    // Our callback is over a minute late - someone must have set the time
+    // forwards.  Set lastEventTime so that the idleTimeout will count from
+    // now.
+    vlog.info("Time has gone forwards - resetting idle timeout");
+    lastEventTime = now;
+    return secsToMillis(idleTimeout);
+  }
+  if (timeLeft <= 0) {
+    close("Idle timeout");
+    return 0;
+  }
+  return secsToMillis(timeLeft);
+}
+
+// renderedCursorChange() is called whenever the server-side rendered cursor
+// changes shape or position.  It ensures that the next update will clean up
+// the old rendered cursor and if necessary draw the new rendered cursor.
+
+void VNCSConnectionST::renderedCursorChange()
+{
+  if (state() != RFBSTATE_NORMAL) return;
+  removeRenderedCursor = true;
+  if (needRenderedCursor())
+    drawRenderedCursor = true;
+}
+
+// needRenderedCursor() returns true if this client needs the server-side
+// rendered cursor.  This may be because it does not support local cursor or
+// because the current cursor position has not been set by this client.
+// Unfortunately we can't know for sure when the current cursor position has
+// been set by this client.  We guess that this is the case when the current
+// cursor position is the same as the last pointer event from this client, or
+// if it is a very short time since this client's last pointer event (up to a
+// second).  [ Ideally we should do finer-grained timing here and make the time
+// configurable, but I don't think it's that important. ]
+
+bool VNCSConnectionST::needRenderedCursor()
+{
+  return (state() == RFBSTATE_NORMAL
+          && (!cp.supportsLocalCursor && !cp.supportsLocalXCursor
+              || (!server->cursorPos.equals(pointerEventPos) &&
+                  (time(0) - pointerEventTime) > 0)));
+}
+
+
+void VNCSConnectionST::approveConnectionOrClose(bool accept,
+                                                const char* reason)
+{
+  try {
+    approveConnection(accept, reason);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+
+
+// -=- Callbacks from SConnection
+
+void VNCSConnectionST::authSuccess()
+{
+  lastEventTime = time(0);
+
+  server->startDesktop();
+
+  // - Set the connection parameters appropriately
+  cp.width = server->pb->width();
+  cp.height = server->pb->height();
+  cp.setName(server->getName());
+  
+  // - Set the default pixel format
+  cp.setPF(server->pb->getPF());
+  char buffer[256];
+  cp.pf().print(buffer, 256);
+  vlog.info("Server default pixel format %s", buffer);
+  image_getter.init(server->pb, cp.pf(), 0);
+
+  // - Mark the entire display as "dirty"
+  updates.add_changed(server->pb->getRect());
+  startTime = time(0);
+}
+
+void VNCSConnectionST::queryConnection(const char* userName)
+{
+  // - Authentication succeeded - clear from blacklist
+  CharArray name; name.buf = sock->getPeerAddress();
+  server->blHosts->clearBlackmark(name.buf);
+
+  // - Special case to provide a more useful error message
+  if (rfb::Server::neverShared && !rfb::Server::disconnectClients &&
+    server->authClientCount() > 0) {
+    approveConnection(false, "The server is already in use");
+    return;
+  }
+
+  // - Does the client have the right to bypass the query?
+  if (reverseConnection ||
+      !(rfb::Server::queryConnect || sock->requiresQuery()) ||
+      (accessRights & AccessNoQuery))
+  {
+    approveConnection(true);
+    return;
+  }
+
+  // - Get the server to display an Accept/Reject dialog, if required
+  //   If a dialog is displayed, the result will be PENDING, and the
+  //   server will call approveConnection at a later time
+  CharArray reason;
+  VNCServerST::queryResult qr = server->queryConnection(sock, userName,
+                                                        &reason.buf);
+  if (qr == VNCServerST::PENDING)
+    return;
+
+  // - If server returns ACCEPT/REJECT then pass result to SConnection
+  approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
+}
+
+void VNCSConnectionST::clientInit(bool shared)
+{
+  lastEventTime = time(0);
+  if (rfb::Server::alwaysShared || reverseConnection) shared = true;
+  if (rfb::Server::neverShared) shared = false;
+  if (!shared) {
+    if (rfb::Server::disconnectClients) {
+      // - Close all the other connected clients
+      vlog.debug("non-shared connection - closing clients");
+      server->closeClients("Non-shared connection requested", getSock());
+    } else {
+      // - Refuse this connection if there are existing clients, in addition to
+      // this one
+      if (server->authClientCount() > 1) {
+        close("Server is already in use");
+        return;
+      }
+    }
+  }
+  SConnection::clientInit(shared);
+}
+
+void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
+{
+  SConnection::setPixelFormat(pf);
+  char buffer[256];
+  pf.print(buffer, 256);
+  vlog.info("Client pixel format %s", buffer);
+  image_getter.init(server->pb, pf, writer());
+  setCursor();
+}
+
+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 = pos;
+    if (buttonMask)
+      server->pointerClient = this;
+    else
+      server->pointerClient = 0;
+    server->desktop->pointerEvent(pointerEventPos, buttonMask);
+  }
+}
+
+
+class VNCSConnectionSTShiftPresser {
+public:
+  VNCSConnectionSTShiftPresser(SDesktop* desktop_)
+    : desktop(desktop_), pressed(false) {}
+  ~VNCSConnectionSTShiftPresser() {
+    if (pressed) { desktop->keyEvent(XK_Shift_L, false); }
+  }
+  void press() {
+    desktop->keyEvent(XK_Shift_L, true);
+    pressed = true;
+  }
+  SDesktop* desktop;
+  bool pressed;
+};
+
+// keyEvent() - record in the pressedKeys which keys were pressed.  Allow
+// multiple down events (for autorepeat), but only allow a single up event.
+void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) {
+  lastEventTime = time(0);
+  server->lastUserInputTime = lastEventTime;
+  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) {
+    if (pressedKeys.find(XK_Shift_L) == pressedKeys.end() &&
+        pressedKeys.find(XK_Shift_R) == pressedKeys.end())
+      shiftPresser.press();
+    key = XK_Tab;
+  }
+
+  if (down) {
+    pressedKeys.insert(key);
+  } else {
+    if (!pressedKeys.erase(key)) return;
+  }
+  server->desktop->keyEvent(key, down);
+}
+
+void VNCSConnectionST::clientCutText(const char* str, int len)
+{
+  if (!(accessRights & AccessCutText)) return;
+  if (!rfb::Server::acceptCutText) return;
+  server->desktop->clientCutText(str, len);
+}
+
+void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
+{
+  if (!(accessRights & AccessView)) return;
+
+  SConnection::framebufferUpdateRequest(r, incremental);
+
+  Region reqRgn(r);
+  requested.assign_union(reqRgn);
+
+  if (!incremental) {
+    // Non-incremental update - treat as if area requested has changed
+    updates.add_changed(reqRgn);
+    server->comparer->add_changed(reqRgn);
+  }
+
+  writeFramebufferUpdate();
+}
+
+void VNCSConnectionST::setInitialColourMap()
+{
+  setColourMapEntries(0, 0);
+}
+
+// supportsLocalCursor() is called whenever the status of
+// cp.supportsLocalCursor has changed.  If the client does now support local
+// cursor, we make sure that the old server-side rendered cursor is cleaned up
+// and the cursor is sent to the client.
+
+void VNCSConnectionST::supportsLocalCursor()
+{
+  if (cp.supportsLocalCursor || cp.supportsLocalXCursor) {
+    removeRenderedCursor = true;
+    drawRenderedCursor = false;
+    setCursor();
+  }
+}
+
+void VNCSConnectionST::writeSetCursorCallback()
+{
+  if (cp.supportsLocalXCursor) {
+    Pixel pix0, pix1;
+    rdr::U8Array bitmap(server->cursor.getBitmap(&pix0, &pix1));
+    if (bitmap.buf) {
+      // The client supports XCursor and the cursor only has two
+      // colors. Use the XCursor encoding.
+      writer()->writeSetXCursor(server->cursor.width(),
+				server->cursor.height(),
+				server->cursor.hotspot.x,
+				server->cursor.hotspot.y,
+				bitmap.buf, server->cursor.mask.buf);
+      return;
+    } else {
+      // More than two colors
+      if (!cp.supportsLocalCursor) {
+	// FIXME: We could reduce to two colors. 
+	vlog.info("Unable to send multicolor cursor: RichCursor not supported by client");
+	return;
+      }
+    }
+  }
+
+  // Use RichCursor
+  rdr::U8* transData = writer()->getImageBuf(server->cursor.area());
+  image_getter.translatePixels(server->cursor.data, transData,
+			       server->cursor.area());
+  writer()->writeSetCursor(server->cursor.width(),
+                           server->cursor.height(),
+                           server->cursor.hotspot,
+                           transData, server->cursor.mask.buf);
+}
+
+
+void VNCSConnectionST::writeFramebufferUpdate()
+{
+  if (state() != RFBSTATE_NORMAL || requested.is_empty()) return;
+
+  server->checkUpdate();
+
+  // If the previous position of the rendered cursor overlaps the source of the
+  // copy, then when the copy happens the corresponding rectangle in the
+  // destination will be wrong, so add it to the changed region.
+
+  if (!updates.get_copied().is_empty() && !renderedCursorRect.is_empty()) {
+    Rect bogusCopiedCursor = (renderedCursorRect.translate(updates.get_delta())
+                              .intersect(server->pb->getRect()));
+    if (!updates.get_copied().intersect(bogusCopiedCursor).is_empty()) {
+      updates.add_changed(bogusCopiedCursor);
+    }
+  }
+
+  // If we need to remove the old rendered cursor, just add the rectangle to
+  // the changed region.
+
+  if (removeRenderedCursor) {
+    updates.add_changed(renderedCursorRect);
+    renderedCursorRect.clear();
+    removeRenderedCursor = false;
+  }
+
+  // Return if there is nothing to send the client.
+
+  if (updates.is_empty() && !writer()->needFakeUpdate() && !drawRenderedCursor)
+    return;
+
+  // If the client needs a server-side rendered cursor, work out the cursor
+  // rectangle.  If it's empty then don't bother drawing it, but if it overlaps
+  // with the update region, we need to draw the rendered cursor regardless of
+  // whether it has changed.
+
+  if (needRenderedCursor()) {
+    renderedCursorRect
+      = (server->renderedCursor.getRect(server->renderedCursorTL)
+         .intersect(requested.get_bounding_rect()));
+
+    if (renderedCursorRect.is_empty()) {
+      drawRenderedCursor = false;
+    } else if (!updates.get_changed().union_(updates.get_copied())
+               .intersect(renderedCursorRect).is_empty()) {
+      drawRenderedCursor = true;
+    }
+
+    // We could remove the new cursor rect from updates here.  It's not clear
+    // whether this is worth it.  If we do remove it, then we won't draw over
+    // the same bit of screen twice, but we have the overhead of a more complex
+    // region.
+
+    //if (drawRenderedCursor)
+    //  updates.subtract(renderedCursorRect);
+  }
+
+  UpdateInfo update;
+  updates.enable_copyrect(cp.useCopyRect);
+  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.
+    writer()->setupCurrentEncoder();
+    int nRects = update.copied.numRects() + (drawRenderedCursor ? 1 : 0);
+    std::vector<Rect> rects;
+    std::vector<Rect>::const_iterator i;
+    update.changed.get_rects(&rects);
+    for (i = rects.begin(); i != rects.end(); i++) {
+      if (i->width() && i->height())
+	nRects += writer()->getNumRects(*i);
+    }
+    
+    writer()->writeFramebufferUpdateStart(nRects);
+    Region updatedRegion;
+    writer()->writeRects(update, &image_getter, &updatedRegion);
+    updates.subtract(updatedRegion);
+    if (drawRenderedCursor)
+      writeRenderedCursorRect();
+    writer()->writeFramebufferUpdateEnd();
+    requested.clear();
+  }
+}
+
+
+// writeRenderedCursorRect() writes a single rectangle drawing the rendered
+// cursor on the client.
+
+void VNCSConnectionST::writeRenderedCursorRect()
+{
+  image_getter.setPixelBuffer(&server->renderedCursor);
+  image_getter.setOffset(server->renderedCursorTL);
+
+  Rect actual;
+  writer()->writeRect(renderedCursorRect, &image_getter, &actual);
+
+  image_getter.setPixelBuffer(server->pb);
+  image_getter.setOffset(Point(0,0));
+
+  drawRenderedCursor = false;
+}
+
+void VNCSConnectionST::setColourMapEntries(int firstColour, int nColours)
+{
+  if (!readyForSetColourMapEntries) return;
+  if (server->pb->getPF().trueColour) return;
+
+  image_getter.setColourMapEntries(firstColour, nColours, writer());
+
+  if (cp.pf().trueColour) {
+    updates.add_changed(server->pb->getRect());
+  }
+}
+
+
+// setCursor() is called whenever the cursor has changed shape or pixel format.
+// If the client supports local cursor then it will arrange for the cursor to
+// be sent to the client.
+
+void VNCSConnectionST::setCursor()
+{
+  if (state() != RFBSTATE_NORMAL || !cp.supportsLocalCursor) return;
+  writer()->cursorChange(this);
+  if (writer()->needFakeUpdate())
+    writeFramebufferUpdate();
+}
+
+void VNCSConnectionST::setSocketTimeouts()
+{
+  int timeoutms = rfb::Server::clientWaitTimeMillis;
+  soonestTimeout(&timeoutms, secsToMillis(rfb::Server::idleTimeout));
+  if (timeoutms == 0)
+    timeoutms = -1;
+  sock->inStream().setTimeout(timeoutms);
+  sock->outStream().setTimeout(timeoutms);
+}
+
+char* VNCSConnectionST::getStartTime()
+{
+  char* result = ctime(&startTime);
+  result[24] = '\0';
+  return result; 
+}
+
+void VNCSConnectionST::setStatus(int status)
+{
+  switch (status) {
+  case 0:
+    accessRights = accessRights | AccessPtrEvents | AccessKeyEvents | AccessView;
+    break;
+  case 1:
+    accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents) | AccessView;
+    break;
+  case 2:
+    accessRights = accessRights & !(AccessPtrEvents | AccessKeyEvents | AccessView);
+    break;
+  }
+  framebufferUpdateRequest(server->pb->getRect(), false);
+}
+int VNCSConnectionST::getStatus()
+{
+  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0007)
+    return 0;
+  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0001)
+    return 1;
+  if ((accessRights & (AccessPtrEvents | AccessKeyEvents | AccessView)) == 0x0000)
+    return 2;
+  return 4;
+}
+
+bool VNCSConnectionST::processFTMsg(int type)
+{
+  if (m_pFileTransfer != NULL) 
+    return m_pFileTransfer->processMessages(type);
+  else 
+    return false;
+}
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
new file mode 100644
index 0000000..a04296d
--- /dev/null
+++ b/common/rfb/VNCSConnectionST.h
@@ -0,0 +1,176 @@
+/* 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.
+ */
+
+//
+// VNCSConnectionST is our derived class of SConnection for VNCServerST - there
+// is one for each connected client.  We think of VNCSConnectionST as part of
+// the VNCServerST implementation, so its methods are allowed full access to
+// members of VNCServerST.
+//
+
+#ifndef __RFB_VNCSCONNECTIONST_H__
+#define __RFB_VNCSCONNECTIONST_H__
+
+#include <set>
+#include <rfb/SConnection.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/TransImageGetter.h>
+#include <rfb/VNCServerST.h>
+#include <rfb/SFileTransfer.h>
+
+namespace rfb {
+  class VNCSConnectionST : public SConnection,
+                           public WriteSetCursorCallback {
+  public:
+    VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
+    virtual ~VNCSConnectionST();
+
+    // Methods called from VNCServerST.  None of these methods ever knowingly
+    // throw an exception.
+
+    // Unless otherwise stated, the SConnectionST may not be valid after any of
+    // these methods are called, since they catch exceptions and may have
+    // called close() which deletes the object.
+
+    // init() must be called to initialise the protocol.  If it fails it
+    // returns false, and close() will have been called.
+    bool init();
+
+    // close() shuts down the socket to the client and deletes the
+    // SConnectionST object.
+    void close(const char* reason);
+
+    // processMessages() processes incoming messages from the client, invoking
+    // various callbacks as a result.  It continues to process messages until
+    // reading might block.  shutdown() will be called on the connection's
+    // Socket if an error occurs, via the close() call.
+    void processMessages();
+
+    void writeFramebufferUpdateOrClose();
+    void pixelBufferChange();
+    void setColourMapEntriesOrClose(int firstColour, int nColours);
+    void bell();
+    void serverCutText(const char *str, int len);
+    void setCursorOrClose();
+
+    // checkIdleTimeout() returns the number of milliseconds left until the
+    // idle timeout expires.  If it has expired, the connection is closed and
+    // zero is returned.  Zero is also returned if there is no idle timeout.
+    int checkIdleTimeout();
+
+    // The following methods never throw exceptions nor do they ever delete the
+    // SConnectionST object.
+
+    // renderedCursorChange() is called whenever the server-side rendered
+    // cursor changes shape or position.  It ensures that the next update will
+    // clean up the old rendered cursor and if necessary draw the new rendered
+    // cursor.
+    void renderedCursorChange();
+
+    // needRenderedCursor() returns true if this client needs the server-side
+    // rendered cursor.  This may be because it does not support local cursor
+    // or because the current cursor position has not been set by this client.
+    bool needRenderedCursor();
+
+    network::Socket* getSock() { return sock; }
+    bool readyForUpdate() { return !requested.is_empty(); }
+    void add_changed(const Region& region) { updates.add_changed(region); }
+    void add_copied(const Region& dest, const Point& delta) {
+      updates.add_copied(dest, delta);
+    }
+
+    const char* getPeerEndpoint() const {return peerEndpoint.buf;}
+
+    // approveConnectionOrClose() is called some time after
+    // VNCServerST::queryConnection() has returned with PENDING to accept or
+    // reject the connection.  The accept argument should be true for
+    // acceptance, or false for rejection, in which case a string reason may
+    // also be given.
+
+    void approveConnectionOrClose(bool accept, const char* reason);
+
+    char* getStartTime();
+
+    void setStatus(int status);
+    int getStatus();
+
+    bool processFTMsg(int type);
+
+  private:
+    // SConnection callbacks
+
+    // These methods are invoked as callbacks from processMsg().  Note that
+    // none of these methods should call any of the above methods which may
+    // delete the SConnectionST object.
+
+    virtual void authSuccess();
+    virtual void queryConnection(const char* userName);
+    virtual void clientInit(bool shared);
+    virtual void setPixelFormat(const PixelFormat& pf);
+    virtual void pointerEvent(const Point& pos, int buttonMask);
+    virtual void keyEvent(rdr::U32 key, bool down);
+    virtual void clientCutText(const char* str, int len);
+    virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+    virtual void setInitialColourMap();
+    virtual void supportsLocalCursor();
+
+    // setAccessRights() allows a security package to limit the access rights
+    // of a VNCSConnectioST to the server.  These access rights are applied
+    // such that the actual rights granted are the minimum of the server's
+    // default access settings and the connection's access settings.
+    virtual void setAccessRights(AccessRights ar) {accessRights=ar;}
+
+    // WriteSetCursorCallback
+    virtual void writeSetCursorCallback();
+
+    // Internal methods
+
+    // writeFramebufferUpdate() attempts to write a framebuffer update to the
+    // client.
+
+    void writeFramebufferUpdate();
+
+    void writeRenderedCursorRect();
+    void setColourMapEntries(int firstColour, int nColours);
+    void setCursor();
+    void setSocketTimeouts();
+
+    network::Socket* sock;
+    CharArray peerEndpoint;
+    VNCServerST* server;
+    SimpleUpdateTracker updates;
+    TransImageGetter image_getter;
+    Region requested;
+    bool drawRenderedCursor, removeRenderedCursor;
+    Rect renderedCursorRect;
+
+    std::set<rdr::U32> pressedKeys;
+
+    time_t lastEventTime;
+    time_t pointerEventTime;
+    Point pointerEventPos;
+
+    AccessRights accessRights;
+
+    CharArray closeReason;
+    time_t startTime;
+
+    SFileTransfer *m_pFileTransfer;
+  };
+}
+#endif
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
new file mode 100644
index 0000000..df0fb0e
--- /dev/null
+++ b/common/rfb/VNCServer.h
@@ -0,0 +1,86 @@
+/* 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.
+ */
+//
+// VNCServer - abstract interface implemented by the RFB library.  The back-end
+// code calls the relevant methods as appropriate.
+
+#ifndef __RFB_VNCSERVER_H__
+#define __RFB_VNCSERVER_H__
+
+#include <rfb/UpdateTracker.h>
+#include <rfb/SSecurity.h>
+
+namespace rfb {
+
+  class VNCServer : public UpdateTracker {
+  public:
+
+    // setPixelBuffer() tells the server to use the given pixel buffer.  If
+    // this differs in size from the previous pixel buffer, this may result in
+    // protocol messages being sent, or clients being disconnected.
+    virtual void setPixelBuffer(PixelBuffer* pb) = 0;
+
+    // setColourMapEntries() tells the server that some entries in the colour
+    // map have changed.  The server will retrieve them via the PixelBuffer's
+    // ColourMap object.  This may result in protocol messages being sent.
+    // If nColours is 0, this means the rest of the colour map.
+    virtual void setColourMapEntries(int firstColour=0, int nColours=0) = 0;
+
+    // serverCutText() tells the server that the cut text has changed.  This
+    // will normally be sent to all clients.
+    virtual void serverCutText(const char* str, int len) = 0;
+
+    // bell() tells the server that it should make all clients make a bell sound.
+    virtual void bell() = 0;
+
+    // clientsReadyForUpdate() returns true if there is at least one client
+    // waiting for an update, false if no clients are ready.
+    virtual bool clientsReadyForUpdate() = 0;
+
+    // - Close all currently-connected clients, by calling
+    //   their close() method with the supplied reason.
+    virtual void closeClients(const char* reason) = 0;
+
+    // tryUpdate() causes the server to attempt to send updates to any waiting
+    // clients.
+    virtual void tryUpdate() = 0;
+
+    // setCursor() tells the server that the cursor has changed.  The
+    // cursorData argument contains width*height pixel values in the pixel
+    // buffer's format.  The mask argument is a bitmask with a 1-bit meaning
+    // the corresponding pixel in cursorData is valid.  The mask consists of
+    // left-to-right, top-to-bottom scanlines, where each scanline is padded to
+    // a whole number of bytes [(width+7)/8].  Within each byte the most
+    // 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, const Point& hotspot,
+                           void* cursorData, void* mask) = 0;
+
+    // setCursorPos() tells the server the current position of the cursor.
+    virtual void setCursorPos(const Point& p) = 0;
+
+    // setSSecurityFactory() tells the server which factory to use when
+    // attempting to authenticate connections.
+    virtual void setSSecurityFactory(SSecurityFactory* f) = 0;
+
+    // setName() tells the server what desktop title to supply to clients
+    virtual void setName(const char* name) = 0;
+  };
+}
+#endif
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
new file mode 100644
index 0000000..cc18faa
--- /dev/null
+++ b/common/rfb/VNCServerST.cxx
@@ -0,0 +1,531 @@
+/* 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.
+ */
+
+// -=- Single-Threaded VNC Server implementation
+
+
+// Note about how sockets get closed:
+//
+// Closing sockets to clients is non-trivial because the code which calls
+// VNCServerST must explicitly know about all the sockets (so that it can block
+// on them appropriately).  However, VNCServerST may want to close clients for
+// a number of reasons, and from a variety of entry points.  The simplest is
+// when processSocketEvent() is called for a client, and the remote end has
+// closed its socket.  A more complex reason is when processSocketEvent() is
+// called for a client which has just sent a ClientInit with the shared flag
+// set to false - in this case we want to close all other clients.  Yet another
+// reason for disconnecting clients is when the desktop size has changed as a
+// result of a call to setPixelBuffer().
+//
+// 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).  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>
+#include <rfb/VNCServerST.h>
+#include <rfb/VNCSConnectionST.h>
+#include <rfb/ComparingUpdateTracker.h>
+#include <rfb/SSecurityFactoryStandard.h>
+#include <rfb/KeyRemapper.h>
+#include <rfb/util.h>
+
+#include <rdr/types.h>
+
+using namespace rfb;
+
+static LogWriter slog("VNCServerST");
+LogWriter VNCServerST::connectionsLog("Connections");
+static SSecurityFactoryStandard defaultSecurityFactory;
+
+//
+// -=- VNCServerST Implementation
+//
+
+// -=- Constructors/Destructor
+
+VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_,
+                         SSecurityFactory* sf)
+  : blHosts(&blacklist), desktop(desktop_), desktopStarted(false), pb(0),
+    m_pFTManager(0), name(strDup(name_)), pointerClient(0), comparer(0),
+    renderedCursorInvalid(false),
+    securityFactory(sf ? sf : &defaultSecurityFactory),
+    queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
+    useEconomicTranslate(false),
+    lastConnectionTime(0), disableclients(false)
+{
+  lastUserInputTime = lastDisconnectTime = time(0);
+  slog.debug("creating single-threaded server %s", name.buf);
+}
+
+VNCServerST::~VNCServerST()
+{
+  slog.debug("shutting down server %s", name.buf);
+
+  // Close any active clients, with appropriate logging & cleanup
+  closeClients("Server shutdown");
+
+  // 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();
+  }
+
+  // Stop the desktop object if active, *only* after deleting all clients!
+  if (desktopStarted) {
+    desktopStarted = false;
+    desktop->stop();
+  }
+
+  delete comparer;
+}
+
+
+// SocketServer methods
+
+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 (blHosts->isBlackmarked(address.buf)) {
+    connectionsLog.error("blacklisted: %s", address.buf);
+    try {
+      SConnection::writeConnFailedFromScratch("Too many security failures",
+                                              &sock->outStream());
+    } catch (rdr::Exception&) {
+    }
+    sock->shutdown();
+    closingSockets.push_back(sock);
+    return;
+  }
+
+  if (clients.empty()) {
+    lastConnectionTime = time(0);
+  }
+
+  VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+  client->init();
+}
+
+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) {
+      (*ci)->processMessages();
+      return;
+    }
+  }
+  throw rdr::Exception("invalid Socket in VNCServerST");
+}
+
+int VNCServerST::checkTimeouts()
+{
+  int timeout = 0;
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+    ci_next = ci; ci_next++;
+    soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
+  }
+
+  int timeLeft;
+  time_t now;
+
+  // Optimization: Only call time() if using any maxTime. 
+  if (rfb::Server::maxDisconnectionTime || rfb::Server::maxConnectionTime || rfb::Server::maxIdleTime) {
+    now = time(0);
+  }
+  
+  // Check MaxDisconnectionTime 
+  if (rfb::Server::maxDisconnectionTime && clients.empty()) {
+    if (now < lastDisconnectTime) {
+      // Someone must have set the time backwards. 
+      slog.info("Time has gone backwards - resetting lastDisconnectTime");
+      lastDisconnectTime = now;
+    }
+    timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
+    if (timeLeft < -60) {
+      // Someone must have set the time forwards.
+      slog.info("Time has gone forwards - resetting lastDisconnectTime");
+      lastDisconnectTime = now;
+      timeLeft = rfb::Server::maxDisconnectionTime;
+    }
+    if (timeLeft <= 0) { 
+      slog.info("MaxDisconnectionTime reached, exiting");
+      exit(0);
+    }
+    soonestTimeout(&timeout, timeLeft * 1000);
+  }
+
+  // Check MaxConnectionTime 
+  if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
+    if (now < lastConnectionTime) {
+      // Someone must have set the time backwards. 
+      slog.info("Time has gone backwards - resetting lastConnectionTime");
+      lastConnectionTime = now;
+    }
+    timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
+    if (timeLeft < -60) {
+      // Someone must have set the time forwards.
+      slog.info("Time has gone forwards - resetting lastConnectionTime");
+      lastConnectionTime = now;
+      timeLeft = rfb::Server::maxConnectionTime;
+    }
+    if (timeLeft <= 0) {
+      slog.info("MaxConnectionTime reached, exiting");
+      exit(0);
+    }
+    soonestTimeout(&timeout, timeLeft * 1000);
+  }
+
+  
+  // Check MaxIdleTime 
+  if (rfb::Server::maxIdleTime) {
+    if (now < lastUserInputTime) {
+      // Someone must have set the time backwards. 
+      slog.info("Time has gone backwards - resetting lastUserInputTime");
+      lastUserInputTime = now;
+    }
+    timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
+    if (timeLeft < -60) {
+      // Someone must have set the time forwards.
+      slog.info("Time has gone forwards - resetting lastUserInputTime");
+      lastUserInputTime = now;
+      timeLeft = rfb::Server::maxIdleTime;
+    }
+    if (timeLeft <= 0) {
+      slog.info("MaxIdleTime reached, exiting");
+      exit(0);
+    }
+    soonestTimeout(&timeout, timeLeft * 1000);
+  }
+  
+  return timeout;
+}
+
+
+// VNCServer methods
+
+void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
+{
+  pb = pb_;
+  delete comparer;
+  comparer = 0;
+
+  if (pb) {
+    comparer = new ComparingUpdateTracker(pb);
+    cursor.setPF(pb->getPF());
+    renderedCursor.setPF(pb->getPF());
+
+    std::list<VNCSConnectionST*>::iterator ci, ci_next;
+    for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
+      ci_next = ci; ci_next++;
+      (*ci)->pixelBufferChange();
+    }
+  } else {
+    if (desktopStarted)
+      throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
+  }
+}
+
+void VNCServerST::setColourMapEntries(int firstColour, int nColours)
+{
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->setColourMapEntriesOrClose(firstColour, nColours);
+  }
+}
+
+void VNCServerST::bell()
+{
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->bell();
+  }
+}
+
+void VNCServerST::serverCutText(const char* str, int len)
+{
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->serverCutText(str, len);
+  }
+}
+
+void VNCServerST::add_changed(const Region& region)
+{
+  comparer->add_changed(region);
+}
+
+void VNCServerST::add_copied(const Region& dest, const Point& delta)
+{
+  comparer->add_copied(dest, delta);
+}
+
+bool VNCServerST::clientsReadyForUpdate()
+{
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    if ((*ci)->readyForUpdate())
+      return true;
+  }
+  return false;
+}
+
+void VNCServerST::tryUpdate()
+{
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->writeFramebufferUpdateOrClose();
+  }
+}
+
+void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
+                            void* data, void* mask)
+{
+  cursor.hotspot = newHotspot;
+  cursor.setSize(width, height);
+  memcpy(cursor.data, data, cursor.dataLen());
+  memcpy(cursor.mask.buf, mask, cursor.maskLen());
+
+  cursor.crop();
+
+  renderedCursorInvalid = true;
+
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->renderedCursorChange();
+    (*ci)->setCursorOrClose();
+  }
+}
+
+void VNCServerST::setCursorPos(const Point& pos)
+{
+  if (!cursorPos.equals(pos)) {
+    cursorPos = pos;
+    renderedCursorInvalid = true;
+    std::list<VNCSConnectionST*>::iterator ci;
+    for (ci = clients.begin(); ci != clients.end(); ci++)
+      (*ci)->renderedCursorChange();
+  }
+}
+
+// Other public methods
+
+void VNCServerST::approveConnection(network::Socket* sock, bool accept,
+                                    const char* reason)
+{
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    if ((*ci)->getSock() == sock) {
+      (*ci)->approveConnectionOrClose(accept, reason);
+      return;
+    }
+  }
+}
+
+void VNCServerST::closeClients(const char* reason, network::Socket* except)
+{
+  std::list<VNCSConnectionST*>::iterator i, next_i;
+  for (i=clients.begin(); i!=clients.end(); i=next_i) {
+    next_i = i; next_i++;
+    if ((*i)->getSock() != except)
+      (*i)->close(reason);
+  }
+}
+
+void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
+{
+  sockets->clear();
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    sockets->push_back((*ci)->getSock());
+  }
+  std::list<network::Socket*>::iterator si;
+  for (si = closingSockets.begin(); si != closingSockets.end(); si++) {
+    sockets->push_back(*si);
+  }
+}
+
+SConnection* VNCServerST::getSConnection(network::Socket* sock) {
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    if ((*ci)->getSock() == sock)
+      return *ci;
+  }
+  return 0;
+}
+
+
+// -=- Internal methods
+
+void VNCServerST::startDesktop()
+{
+  if (!desktopStarted) {
+    slog.debug("starting desktop");
+    desktop->start(this);
+    desktopStarted = true;
+    if (!pb)
+      throw Exception("SDesktop::start() did not set a valid PixelBuffer");
+  }
+}
+
+int VNCServerST::authClientCount() {
+  int count = 0;
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++) {
+    if ((*ci)->authenticated())
+      count++;
+  }
+  return count;
+}
+
+inline bool VNCServerST::needRenderedCursor()
+{
+  std::list<VNCSConnectionST*>::iterator ci;
+  for (ci = clients.begin(); ci != clients.end(); ci++)
+    if ((*ci)->needRenderedCursor()) return true;
+  return false;
+}
+
+// checkUpdate() is called just before sending an update.  It checks to see
+// what updates are pending and propagates them to the update tracker for each
+// client.  It uses the ComparingUpdateTracker's compare() method to filter out
+// areas of the screen which haven't actually changed.  It also checks the
+// state of the (server-side) rendered cursor, if necessary rendering it again
+// with the correct background.
+
+void VNCServerST::checkUpdate()
+{
+  bool renderCursor = needRenderedCursor();
+
+  if (comparer->is_empty() && !(renderCursor && renderedCursorInvalid))
+    return;
+
+  Region toCheck = comparer->get_changed().union_(comparer->get_copied());
+
+  if (renderCursor) {
+    Rect clippedCursorRect
+      = cursor.getRect(cursorTL()).intersect(pb->getRect());
+
+    if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
+                                   .is_empty())) {
+      renderCursor = false;
+    } else {
+      renderedCursorTL = clippedCursorRect.tl;
+      renderedCursor.setSize(clippedCursorRect.width(),
+                             clippedCursorRect.height());
+      toCheck.assign_union(clippedCursorRect);
+    }
+  }
+
+  pb->grabRegion(toCheck);
+
+  if (rfb::Server::compareFB)
+    comparer->compare();
+
+  if (renderCursor) {
+    pb->getImage(renderedCursor.data,
+                 renderedCursor.getRect(renderedCursorTL));
+    renderedCursor.maskRect(cursor.getRect(cursorTL()
+                                           .subtract(renderedCursorTL)),
+                            cursor.data, cursor.mask.buf);
+    renderedCursorInvalid = false;
+  }
+
+  std::list<VNCSConnectionST*>::iterator ci, ci_next;
+  for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+    ci_next = ci; ci_next++;
+    (*ci)->add_copied(comparer->get_copied(), comparer->get_delta());
+    (*ci)->add_changed(comparer->get_changed());
+  }
+
+  comparer->clear();
+}
+
+void VNCServerST::getConnInfo(ListConnInfo * listConn)
+{
+  listConn->Clear();
+  listConn->setDisable(getDisable());
+  if (clients.empty())
+    return;
+  std::list<VNCSConnectionST*>::iterator i;
+  for (i = clients.begin(); i != clients.end(); i++)
+    listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
+                      (*i)->getStartTime(), (*i)->getStatus());
+}
+
+void VNCServerST::setConnStatus(ListConnInfo* listConn)
+{
+  setDisable(listConn->getDisable());
+  if (listConn->Empty() || clients.empty()) return;
+  for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
+    VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
+    std::list<VNCSConnectionST*>::iterator i;
+    for (i = clients.begin(); i != clients.end(); i++) {
+      if ((*i) == conn) {
+        int status = listConn->iGetStatus();
+        if (status == 3) {
+          (*i)->close(0);
+        } else {
+          (*i)->setStatus(status);
+        }
+        break;
+      }
+    }
+  }
+}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
new file mode 100644
index 0000000..bc15b7f
--- /dev/null
+++ b/common/rfb/VNCServerST.h
@@ -0,0 +1,245 @@
+/* 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.
+ */
+
+// -=- VNCServerST.h
+
+// Single-threaded VNCServer implementation
+
+#ifndef __RFB_VNCSERVERST_H__
+#define __RFB_VNCSERVERST_H__
+
+#include <list>
+
+#include <rfb/SDesktop.h>
+#include <rfb/VNCServer.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Blacklist.h>
+#include <rfb/Cursor.h>
+#include <network/Socket.h>
+#include <rfb/ListConnInfo.h>
+#include <rfb/SFileTransferManager.h>
+
+namespace rfb {
+
+  class VNCSConnectionST;
+  class ComparingUpdateTracker;
+  class PixelBuffer;
+  class KeyRemapper;
+
+  class VNCServerST : public VNCServer, public network::SocketServer {
+  public:
+    // -=- Constructors
+
+    //   Create a server exporting the supplied desktop.
+    VNCServerST(const char* name_, SDesktop* desktop_,
+                SSecurityFactory* securityFactory_=0);
+    virtual ~VNCServerST();
+
+
+    // Methods overridden from SocketServer
+
+    // 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);
+
+    // removeSocket
+    //   Clean up any resources associated with the Socket
+    virtual void removeSocket(network::Socket* sock);
+
+    // 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);
+
+    // 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();
+
+
+    // Methods overridden from VNCServer
+
+    virtual void setPixelBuffer(PixelBuffer* pb);
+    virtual void setColourMapEntries(int firstColour=0, int nColours=0);
+    virtual void serverCutText(const char* str, int len);
+    virtual void add_changed(const Region &region);
+    virtual void add_copied(const Region &dest, const Point &delta);
+    virtual bool clientsReadyForUpdate();
+    virtual void tryUpdate();
+    virtual void setCursor(int width, int height, const Point& hotspot,
+                           void* cursorData, void* mask);
+    virtual void setCursorPos(const Point& p);
+    virtual void setSSecurityFactory(SSecurityFactory* f) {securityFactory=f;}
+
+    virtual void bell();
+
+    // - Close all currently-connected clients, by calling
+    //   their close() method with the supplied reason.
+    virtual void closeClients(const char* reason) {closeClients(reason, 0);}
+
+    // VNCServerST-only methods
+
+    // 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);
+
+    // getSockets() gets a list of sockets.  This can be used to generate an
+    // fd_set for calling select().
+
+    void getSockets(std::list<network::Socket*>* sockets);
+
+    // getSConnection() gets the SConnection for a particular Socket.  If
+    // the Socket is not recognised then null is returned.
+
+    SConnection* getSConnection(network::Socket* sock);
+
+    // getDesktopSize() returns the size of the SDesktop exported by this
+    // server.
+    Point getDesktopSize() const {return desktop->getFbSize();}
+
+    // getName() returns the name of this VNC Server.  NB: The value returned
+    // is the server's internal buffer which may change after any other methods
+    // are called - take a copy if necessary.
+    const char* getName() const {return name.buf;}
+
+    // setName() specifies the desktop name that the server should provide to
+    // clients
+    void setName(const char* name_) {name.replaceBuf(strDup(name_));}
+
+    // A QueryConnectionHandler, if supplied, is passed details of incoming
+    // connections to approve, reject, or query the user about.
+    //
+    // queryConnection() is called when a connection has been
+    // successfully authenticated.  The sock and userName arguments identify
+    // the socket and the name of the authenticated user, if any.  It should
+    // return ACCEPT if the connection should be accepted, REJECT if it should
+    // be rejected, or PENDING if a decision cannot yet be reached.  If REJECT
+    // is returned, *reason can be set to a string describing the reason - this
+    // will be delete[]ed when it is finished with.  If PENDING is returned,
+    // approveConnection() must be called some time later to accept or reject
+    // the connection.
+    enum queryResult { ACCEPT, REJECT, PENDING };
+    struct QueryConnectionHandler {
+      virtual ~QueryConnectionHandler() {}
+      virtual queryResult queryConnection(network::Socket* sock,
+                                          const char* userName,
+                                          char** reason) = 0;
+    };
+    void setQueryConnectionHandler(QueryConnectionHandler* qch) {
+      queryConnectionHandler = qch;
+    }
+
+    // queryConnection is called as described above, and either passes the
+    // request on to the registered handler, or accepts the connection if
+    // no handler has been specified.
+    virtual queryResult queryConnection(network::Socket* sock,
+                                        const char* userName,
+                                        char** reason) {
+      return queryConnectionHandler
+        ? queryConnectionHandler->queryConnection(sock, userName, reason)
+        : ACCEPT;
+    }
+
+    // approveConnection() is called by the active QueryConnectionHandler,
+    // some time after queryConnection() has returned with PENDING, to accept
+    // or reject the connection.  The accept argument should be true for
+    // acceptance, or false for rejection, in which case a string reason may
+    // also be given.
+    void approveConnection(network::Socket* sock, bool accept,
+                           const char* reason);
+
+    // setBlacklist() is called to replace the VNCServerST's internal
+    // Blacklist instance with another instance.  This allows a single
+    // Blacklist to be shared by multiple VNCServerST instances.
+    void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}
+
+    // 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.
+    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);
+
+    bool getDisable() { return disableclients;};
+    void setDisable(bool disable) { disableclients = disable;};
+
+    void setFTManager(rfb::SFileTransferManager *pFTManager) { m_pFTManager = pFTManager; };
+
+  protected:
+
+    friend class VNCSConnectionST;
+
+    void startDesktop();
+
+    static LogWriter connectionsLog;
+    Blacklist blacklist;
+    Blacklist* blHosts;
+
+    SDesktop* desktop;
+    bool desktopStarted;
+    PixelBuffer* pb;
+
+    SFileTransferManager *m_pFTManager;
+
+    CharArray name;
+
+    std::list<VNCSConnectionST*> clients;
+    VNCSConnectionST* pointerClient;
+    std::list<network::Socket*> closingSockets;
+
+    ComparingUpdateTracker* comparer;
+
+    Point cursorPos;
+    Cursor cursor;
+    Point cursorTL() { return cursorPos.subtract(cursor.hotspot); }
+    Point renderedCursorTL;
+    ManagedPixelBuffer renderedCursor;
+    bool renderedCursorInvalid;
+
+    // - Check how many of the clients are authenticated.
+    int authClientCount();
+
+    bool needRenderedCursor();
+    void checkUpdate();
+
+    SSecurityFactory* securityFactory;
+    QueryConnectionHandler* queryConnectionHandler;
+    KeyRemapper* keyRemapper;
+    bool useEconomicTranslate;
+    
+    time_t lastUserInputTime;
+    time_t lastDisconnectTime;
+    time_t lastConnectionTime;
+
+    bool disableclients;
+  };
+
+};
+
+#endif
+
diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx
new file mode 100644
index 0000000..b7c6912
--- /dev/null
+++ b/common/rfb/ZRLEDecoder.cxx
@@ -0,0 +1,91 @@
+/* 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 <rfb/CMsgReader.h>
+#include <rfb/CMsgHandler.h>
+#include <rfb/ZRLEDecoder.h>
+
+using namespace rfb;
+
+#define EXTRA_ARGS CMsgHandler* handler
+#define FILL_RECT(r, p) handler->fillRect(r, p)
+#define IMAGE_RECT(r, p) handler->imageRect(r, p)
+#define BPP 8
+#include <rfb/zrleDecode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/zrleDecode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/zrleDecode.h>
+#define CPIXEL 24A
+#include <rfb/zrleDecode.h>
+#undef CPIXEL
+#define CPIXEL 24B
+#include <rfb/zrleDecode.h>
+#undef CPIXEL
+#undef BPP
+
+Decoder* ZRLEDecoder::create(CMsgReader* reader)
+{
+  return new ZRLEDecoder(reader);
+}
+
+ZRLEDecoder::ZRLEDecoder(CMsgReader* reader_) : reader(reader_)
+{
+}
+
+ZRLEDecoder::~ZRLEDecoder()
+{
+}
+
+void ZRLEDecoder::readRect(const Rect& r, CMsgHandler* handler)
+{
+  rdr::InStream* is = reader->getInStream();
+  rdr::U8* buf = reader->getImageBuf(64 * 64 * 4);
+  switch (reader->bpp()) {
+  case 8:  zrleDecode8 (r, is, &zis, (rdr::U8*) buf, handler); break;
+  case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, handler); break;
+  case 32:
+    {
+      const rfb::PixelFormat& pf = handler->cp.pf();
+      bool fitsInLS3Bytes = ((pf.redMax   << pf.redShift)   < (1<<24) &&
+                             (pf.greenMax << pf.greenShift) < (1<<24) &&
+                             (pf.blueMax  << pf.blueShift)  < (1<<24));
+
+      bool fitsInMS3Bytes = (pf.redShift   > 7  &&
+                             pf.greenShift > 7  &&
+                             pf.blueShift  > 7);
+
+      if ((fitsInLS3Bytes && !pf.bigEndian) ||
+          (fitsInMS3Bytes && pf.bigEndian))
+      {
+        zrleDecode24A(r, is, &zis, (rdr::U32*)buf, handler);
+      }
+      else if ((fitsInLS3Bytes && pf.bigEndian) ||
+               (fitsInMS3Bytes && !pf.bigEndian))
+      {
+        zrleDecode24B(r, is, &zis, (rdr::U32*)buf, handler);
+      }
+      else
+      {
+        zrleDecode32(r, is, &zis, (rdr::U32*)buf, handler);
+      }
+      break;
+    }
+  }
+}
diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h
new file mode 100644
index 0000000..fe96c73
--- /dev/null
+++ b/common/rfb/ZRLEDecoder.h
@@ -0,0 +1,37 @@
+/* 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_ZRLEDECODER_H__
+#define __RFB_ZRLEDECODER_H__
+
+#include <rdr/ZlibInStream.h>
+#include <rfb/Decoder.h>
+
+namespace rfb {
+
+  class ZRLEDecoder : public Decoder {
+  public:
+    static Decoder* create(CMsgReader* reader);
+    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual ~ZRLEDecoder();
+  private:
+    ZRLEDecoder(CMsgReader* reader);
+    CMsgReader* reader;
+    rdr::ZlibInStream zis;
+  };
+}
+#endif
diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx
new file mode 100644
index 0000000..d84c4cf
--- /dev/null
+++ b/common/rfb/ZRLEEncoder.cxx
@@ -0,0 +1,122 @@
+/* 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 <rdr/OutStream.h>
+#include <rfb/Exception.h>
+#include <rfb/ImageGetter.h>
+#include <rfb/encodings.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriter.h>
+#include <rfb/ZRLEEncoder.h>
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+rdr::MemOutStream* ZRLEEncoder::sharedMos = 0;
+int ZRLEEncoder::maxLen = 4097 * 1024; // enough for width 16384 32-bit pixels
+
+IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1);
+
+#define EXTRA_ARGS ImageGetter* ig
+#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
+#define BPP 8
+#include <rfb/zrleEncode.h>
+#undef BPP
+#define BPP 16
+#include <rfb/zrleEncode.h>
+#undef BPP
+#define BPP 32
+#include <rfb/zrleEncode.h>
+#define CPIXEL 24A
+#include <rfb/zrleEncode.h>
+#undef CPIXEL
+#define CPIXEL 24B
+#include <rfb/zrleEncode.h>
+#undef CPIXEL
+#undef BPP
+
+Encoder* ZRLEEncoder::create(SMsgWriter* writer)
+{
+  return new ZRLEEncoder(writer);
+}
+
+ZRLEEncoder::ZRLEEncoder(SMsgWriter* writer_)
+  : writer(writer_), zos(0,0,zlibLevel)
+{
+  if (sharedMos)
+    mos = sharedMos;
+  else
+    mos = new rdr::MemOutStream(129*1024);
+}
+
+ZRLEEncoder::~ZRLEEncoder()
+{
+  if (!sharedMos)
+    delete mos;
+}
+
+bool ZRLEEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+{
+  rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4);
+  mos->clear();
+  bool wroteAll = true;
+  *actual = r;
+
+  switch (writer->bpp()) {
+  case 8:
+    wroteAll = zrleEncode8(r, mos, &zos, imageBuf, maxLen, actual, ig);
+    break;
+  case 16:
+    wroteAll = zrleEncode16(r, mos, &zos, imageBuf, maxLen, actual, ig);
+    break;
+  case 32:
+    {
+      const PixelFormat& pf = writer->getConnParams()->pf();
+
+      bool fitsInLS3Bytes = ((pf.redMax   << pf.redShift)   < (1<<24) &&
+                             (pf.greenMax << pf.greenShift) < (1<<24) &&
+                             (pf.blueMax  << pf.blueShift)  < (1<<24));
+
+      bool fitsInMS3Bytes = (pf.redShift   > 7  &&
+                             pf.greenShift > 7  &&
+                             pf.blueShift  > 7);
+
+      if ((fitsInLS3Bytes && !pf.bigEndian) ||
+          (fitsInMS3Bytes && pf.bigEndian))
+      {
+        wroteAll = zrleEncode24A(r, mos, &zos, imageBuf, maxLen, actual, ig);
+      }
+      else if ((fitsInLS3Bytes && pf.bigEndian) ||
+               (fitsInMS3Bytes && !pf.bigEndian))
+      {
+        wroteAll = zrleEncode24B(r, mos, &zos, imageBuf, maxLen, actual, ig);
+      }
+      else
+      {
+        wroteAll = zrleEncode32(r, mos, &zos, imageBuf, maxLen, actual, ig);
+      }
+      break;
+    }
+  }
+
+  writer->startRect(*actual, encodingZRLE);
+  rdr::OutStream* os = writer->getOutStream();
+  os->writeU32(mos->length());
+  os->writeBytes(mos->data(), mos->length());
+  writer->endRect();
+  return wroteAll;
+}
diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h
new file mode 100644
index 0000000..7768917
--- /dev/null
+++ b/common/rfb/ZRLEEncoder.h
@@ -0,0 +1,54 @@
+/* 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_ZRLEENCODER_H__
+#define __RFB_ZRLEENCODER_H__
+
+#include <rdr/MemOutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <rfb/Encoder.h>
+
+namespace rfb {
+
+  class ZRLEEncoder : public Encoder {
+  public:
+    static Encoder* create(SMsgWriter* writer);
+    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual ~ZRLEEncoder();
+
+    // setMaxLen() sets the maximum size in bytes of any ZRLE rectangle.  This
+    // 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 (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
+    // ZRLEEncoders.  Should be called before any ZRLEEncoders are created.
+    static void setSharedMos(rdr::MemOutStream* mos_) { sharedMos = mos_; }
+
+  private:
+    ZRLEEncoder(SMsgWriter* writer);
+    SMsgWriter* writer;
+    rdr::ZlibOutStream zos;
+    rdr::MemOutStream* mos;
+    static rdr::MemOutStream* sharedMos;
+    static int maxLen;
+  };
+}
+#endif
diff --git a/common/rfb/d3des.c b/common/rfb/d3des.c
new file mode 100644
index 0000000..eaca581
--- /dev/null
+++ b/common/rfb/d3des.c
@@ -0,0 +1,434 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static unsigned short bytebit[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static unsigned char totrot[16] = {
+	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+		}
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+			}
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+		    }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+			}
+		}
+	cookey(kn);
+	return;
+	}
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+		}
+	usekey(dough);
+	return;
+	}
+
+void cpkey(into)
+register unsigned long *into;
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+	}
+
+void usekey(from)
+register unsigned long *from;
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+	}
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+	}
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+	}
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+	*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;
+	}
+
+static unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+		}
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+	}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/common/rfb/d3des.h b/common/rfb/d3des.h
new file mode 100644
index 0000000..ea3da44
--- /dev/null
+++ b/common/rfb/d3des.h
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * 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.
+ */
+
+/* d3des.h -
+ *
+ *	Headers and defines for d3des.c
+ *	Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *	(GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0	0	/* MODE == encrypt */
+#define DE1	1	/* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/*		      hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/*		    cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/*		   cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/*		    from[8]	      to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/common/rfb/encodings.cxx b/common/rfb/encodings.cxx
new file mode 100644
index 0000000..6aa81c4
--- /dev/null
+++ b/common/rfb/encodings.cxx
@@ -0,0 +1,49 @@
+/* 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 <string.h>
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+#include <rfb/encodings.h>
+#include <rfb/util.h>
+
+int rfb::encodingNum(const char* name)
+{
+  if (strcasecmp(name, "raw") == 0)      return encodingRaw;
+  if (strcasecmp(name, "copyRect") == 0) return encodingCopyRect;
+  if (strcasecmp(name, "RRE") == 0)      return encodingRRE;
+  if (strcasecmp(name, "CoRRE") == 0)    return encodingCoRRE;
+  if (strcasecmp(name, "hextile") == 0)  return encodingHextile;
+  if (strcasecmp(name, "ZRLE") == 0)     return encodingZRLE;
+  if (strcasecmp(name, "Tight") == 0)    return encodingTight;
+  return -1;
+}
+
+const char* rfb::encodingName(unsigned int num)
+{
+  switch (num) {
+  case encodingRaw:      return "raw";
+  case encodingCopyRect: return "copyRect";
+  case encodingRRE:      return "RRE";
+  case encodingCoRRE:    return "CoRRE";
+  case encodingHextile:  return "hextile";
+  case encodingZRLE:     return "ZRLE";
+  case encodingTight:    return "Tight";
+  default:               return "[unknown encoding]";
+  }
+}
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
new file mode 100644
index 0000000..51f6f1e
--- /dev/null
+++ b/common/rfb/encodings.h
@@ -0,0 +1,47 @@
+/* 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_ENCODINGS_H__
+#define __RFB_ENCODINGS_H__
+
+namespace rfb {
+
+  const unsigned int encodingRaw = 0;
+  const unsigned int encodingCopyRect = 1;
+  const unsigned int encodingRRE = 2;
+  const unsigned int encodingCoRRE = 4;
+  const unsigned int encodingHextile = 5;
+  const unsigned int encodingTight = 7;
+  const unsigned int encodingZRLE = 16;
+
+  const unsigned int encodingMax = 255;
+
+  const unsigned int pseudoEncodingXCursor = 0xffffff10;
+  const unsigned int pseudoEncodingCursor = 0xffffff11;
+  const unsigned int pseudoEncodingDesktopSize = 0xffffff21;
+
+  // TightVNC-specific
+  const unsigned int pseudoEncodingLastRect = 0xFFFFFF20;
+  const unsigned int pseudoEncodingQualityLevel0 = 0xFFFFFFE0;
+  const unsigned int pseudoEncodingQualityLevel9 = 0xFFFFFFE9;
+  const unsigned int pseudoEncodingCompressLevel0 = 0xFFFFFF00;
+  const unsigned int pseudoEncodingCompressLevel9 = 0xFFFFFF09;
+
+  int encodingNum(const char* name);
+  const char* encodingName(unsigned int num);
+}
+#endif
diff --git a/common/rfb/fttypes.h b/common/rfb/fttypes.h
new file mode 100644
index 0000000..4404508
--- /dev/null
+++ b/common/rfb/fttypes.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *    
+ * 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.
+ */
+
+// -=- fttypes.h
+
+#ifndef __RFB_FTTYPES_H__
+#define __RFB_FTTYPES_H__
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+
+#define FT_FILENAME_SIZE 256
+
+#define FT_MAX_STATUS_STRINGS		 255
+#define FT_MAX_LENGTH_STATUS_STRINGS 130
+
+#define FT_MAX_SENDING_SIZE 8192
+
+#define FT_NET_ATTR_DIR ((unsigned int)-1)
+
+#define FT_ATTR_UNKNOWN			    0x00000000
+#define FT_ATTR_FILE			    0x00000001
+#define FT_ATTR_DIR 			    0x00000002
+
+#define FT_ATTR_RESIZE_NEEDED	    0x00040000
+#define FT_ATTR_FOLDER_EXISTS	    0x00080000
+#define FT_ATTR_COPY_OVERWRITE	    0x00100000
+#define FT_ATTR_FLR_UPLOAD_CHECK	0x00200000
+#define FT_ATTR_FLR_UPLOAD_ADD	    0x00400000
+#define FT_ATTR_COPY_UPLOAD	        0x00800000
+#define FT_ATTR_FLR_DOWNLOAD_CHECK  0x01000000
+#define FT_ATTR_FLR_DOWNLOAD_ADD	0x02000000
+#define FT_ATTR_COPY_DOWNLOAD	    0x04000000
+#define FT_ATTR_DELETE_LOCAL	    0x08000000
+#define FT_ATTR_DELETE_REMOTE	    0x10000000
+#define FT_ATTR_RENAME_LOCAL	    0x20000000
+#define FT_ATTR_RENAME_REMOTE	    0x40000000
+
+#define FT_FLR_DEST_MAIN     101
+#define FT_FLR_DEST_BROWSE   102
+#define FT_FLR_DEST_DOWNLOAD 103
+#define FT_FLR_DEST_UPLOAD   104
+#define FT_FLR_DEST_DELETE   105
+#define FT_FLR_DEST_RENAME   106
+
+typedef struct tagSIZEDATAINFO
+{
+	unsigned int size;
+	unsigned int data;
+} SIZEDATAINFO;
+
+typedef struct tagSIZEDATAFLAGSINFO
+{
+	unsigned int size;
+	unsigned int data;
+	unsigned int flags;
+} SIZEDATAFLAGSINFO;
+
+typedef struct tagFILEINFO
+{
+	char name[FT_FILENAME_SIZE];
+	SIZEDATAFLAGSINFO info;
+} FILEINFO;
+
+typedef struct tagFILEINFOEX
+{
+	char locPath[FT_FILENAME_SIZE];
+	char locName[FT_FILENAME_SIZE];
+	char remPath[FT_FILENAME_SIZE];
+	char remName[FT_FILENAME_SIZE];
+	SIZEDATAFLAGSINFO info;
+} FILEINFOEX;
+
+#endif // __RFB_FTTYPES_H__
diff --git a/common/rfb/hextileConstants.h b/common/rfb/hextileConstants.h
new file mode 100644
index 0000000..b8713cb
--- /dev/null
+++ b/common/rfb/hextileConstants.h
@@ -0,0 +1,27 @@
+/* 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_HEXTILECONSTANTS_H__
+#define __RFB_HEXTILECONSTANTS_H__
+namespace rfb {
+  const int hextileRaw = (1 << 0);
+  const int hextileBgSpecified = (1 << 1);
+  const int hextileFgSpecified = (1 << 2);
+  const int hextileAnySubrects = (1 << 3);
+  const int hextileSubrectsColoured = (1 << 4);
+}
+#endif
diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h
new file mode 100644
index 0000000..77befc7
--- /dev/null
+++ b/common/rfb/hextileDecode.h
@@ -0,0 +1,126 @@
+/* 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.
+ */
+//
+// Hextile decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// FILL_RECT          - fill a rectangle with a single colour
+// IMAGE_RECT         - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rfb/hextileConstants.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP)
+
+void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf
+#ifdef EXTRA_ARGS
+                     , EXTRA_ARGS
+#endif
+                     )
+{
+  Rect t;
+  PIXEL_T bg = 0;
+  PIXEL_T fg = 0;
+
+  for (t.tl.y = r.tl.y; t.tl.y < 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 = __rfbmin(r.br.x, t.tl.x + 16);
+
+      int tileType = is->readU8();
+
+      if (tileType & hextileRaw) {
+	is->readBytes(buf, t.area() * (BPP/8));
+	IMAGE_RECT(t, buf);
+	continue;
+      }
+
+      if (tileType & hextileBgSpecified)
+	bg = is->READ_PIXEL();
+
+#ifdef FAVOUR_FILL_RECT
+      FILL_RECT(t, bg);
+#else
+      int len = t.area();
+      PIXEL_T* ptr = (PIXEL_T*)buf;
+      while (len-- > 0) *ptr++ = bg;
+#endif
+
+      if (tileType & hextileFgSpecified)
+	fg = is->READ_PIXEL();
+
+      if (tileType & hextileAnySubrects) {
+        int nSubrects = is->readU8();
+
+        for (int i = 0; i < nSubrects; i++) {
+
+          if (tileType & hextileSubrectsColoured)
+            fg = is->READ_PIXEL();
+
+          int xy = is->readU8();
+          int wh = is->readU8();
+
+#ifdef FAVOUR_FILL_RECT
+          Rect s;
+          s.tl.x = t.tl.x + ((xy >> 4) & 15);
+          s.tl.y = t.tl.y + (xy & 15);
+          s.br.x = s.tl.x + ((wh >> 4) & 15) + 1;
+          s.br.y = s.tl.y + (wh & 15) + 1;
+          FILL_RECT(s, fg);
+#else
+          int x = ((xy >> 4) & 15);
+          int y = (xy & 15);
+          int w = ((wh >> 4) & 15) + 1;
+          int h = (wh & 15) + 1;
+          PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x;
+          int rowAdd = t.width() - w;
+          while (h-- > 0) {
+            int len = w;
+            while (len-- > 0) *ptr++ = fg;
+            ptr += rowAdd;
+          }
+#endif
+        }
+      }
+#ifndef FAVOUR_FILL_RECT
+      IMAGE_RECT(t, buf);
+#endif
+    }
+  }
+}
+
+#undef PIXEL_T
+#undef READ_PIXEL
+#undef HEXTILE_DECODE
+}
diff --git a/common/rfb/hextileEncode.h b/common/rfb/hextileEncode.h
new file mode 100644
index 0000000..9f8bd55
--- /dev/null
+++ b/common/rfb/hextileEncode.h
@@ -0,0 +1,229 @@
+/* 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
+ * (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.
+ */
+//
+// Hextile encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+
+#include <rdr/OutStream.h>
+#include <rfb/hextileConstants.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define HEXTILE_ENCODE CONCAT2E(hextileEncode,BPP)
+#define HEXTILE_ENCODE_TILE CONCAT2E(hextileEncodeTile,BPP)
+#define TEST_TILE_TYPE CONCAT2E(hextileTestTileType,BPP)
+
+int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg);
+int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
+                         rdr::U8* encoded, PIXEL_T bg);
+
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os
+#ifdef EXTRA_ARGS
+                    , EXTRA_ARGS
+#endif
+                    )
+{
+  Rect t;
+  PIXEL_T buf[256];
+  PIXEL_T oldBg = 0, oldFg = 0;
+  bool oldBgValid = false;
+  bool oldFgValid = false;
+  rdr::U8 encoded[256*(BPP/8)];
+
+  for (t.tl.y = r.tl.y; t.tl.y < 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 = __rfbmin(r.br.x, t.tl.x + 16);
+
+      GET_IMAGE_INTO_BUF(t,buf);
+
+      PIXEL_T bg, fg;
+      int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg);
+
+      if (!oldBgValid || oldBg != bg) {
+        tileType |= hextileBgSpecified;
+        oldBg = bg;
+        oldBgValid = true;
+      }
+
+      int encodedLen = 0;
+
+      if (tileType & hextileAnySubrects) {
+
+        if (tileType & hextileSubrectsColoured) {
+          oldFgValid = false;
+        } else {
+          if (!oldFgValid || oldFg != fg) {
+            tileType |= hextileFgSpecified;
+            oldFg = fg;
+            oldFgValid = true;
+          }
+        }
+
+        encodedLen = HEXTILE_ENCODE_TILE(buf, t.width(), t.height(), tileType,
+                                         encoded, bg);
+
+        if (encodedLen < 0) {
+          GET_IMAGE_INTO_BUF(t,buf);
+          os->writeU8(hextileRaw);
+          os->writeBytes(buf, t.width() * t.height() * (BPP/8));
+          oldBgValid = oldFgValid = false;
+          continue;
+        }
+      }
+
+      os->writeU8(tileType);
+      if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
+      if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
+      if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+    }
+  }
+}
+
+
+int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
+                         rdr::U8* encoded, PIXEL_T bg)
+{
+  rdr::U8* nSubrectsPtr = encoded;
+  *nSubrectsPtr = 0;
+  encoded++;
+
+  for (int y = 0; y < h; y++)
+  {
+    int x = 0;
+    while (x < w) {
+      if (*data == bg) {
+        x++;
+        data++;
+        continue;
+      }
+
+      // Find horizontal subrect first
+      PIXEL_T* ptr = data+1;
+      PIXEL_T* eol = data+w-x;
+      while (ptr < eol && *ptr == *data) ptr++;
+      int sw = ptr - data;
+
+      ptr = data + w;
+      int sh = 1;
+      while (sh < h-y) {
+        eol = ptr + sw;
+        while (ptr < eol)
+          if (*ptr++ != *data) goto endOfSubrect;
+        ptr += w - sw;
+        sh++;
+      }
+    endOfSubrect:
+
+      (*nSubrectsPtr)++;
+
+      if (tileType & hextileSubrectsColoured) {
+        if (encoded - nSubrectsPtr + (BPP/8) > w*h*(BPP/8)) return -1;
+#if (BPP == 8)
+        *encoded++ = *data;
+#elif (BPP == 16)
+        *encoded++ = ((rdr::U8*)data)[0];
+        *encoded++ = ((rdr::U8*)data)[1];
+#elif (BPP == 32)
+        *encoded++ = ((rdr::U8*)data)[0];
+        *encoded++ = ((rdr::U8*)data)[1];
+        *encoded++ = ((rdr::U8*)data)[2];
+        *encoded++ = ((rdr::U8*)data)[3];
+#endif
+      }
+
+      if (encoded - nSubrectsPtr + 2 > w*h*(BPP/8)) return -1;
+      *encoded++ = (x << 4) | y;
+      *encoded++ = ((sw-1) << 4) | (sh-1);
+
+      ptr = data+w;
+      PIXEL_T* eor = data+w*sh;
+      while (ptr < eor) {
+        eol = ptr + sw;
+        while (ptr < eol) *ptr++ = bg;
+        ptr += w - sw;
+      }
+      x += sw;
+      data += sw;
+    }
+  }
+  return encoded - nSubrectsPtr;
+}
+
+
+int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg)
+{
+  PIXEL_T pix1 = *data;
+  PIXEL_T* end = data + w * h;
+
+  PIXEL_T* ptr = data + 1;
+  while (ptr < end && *ptr == pix1)
+    ptr++;
+
+  if (ptr == end) {
+    *bg = pix1;
+    return 0;                   // solid-color tile
+  }
+
+  int count1 = ptr - data;
+  int count2 = 1;
+  PIXEL_T pix2 = *ptr++;
+  int tileType = hextileAnySubrects;
+
+  for (; ptr < end; ptr++) {
+    if (*ptr == pix1) {
+      count1++;
+    } else if (*ptr == pix2) {
+      count2++;
+    } else {
+      tileType |= hextileSubrectsColoured;
+      break;
+    }
+  }
+
+  if (count1 >= count2) {
+    *bg = pix1; *fg = pix2;
+  } else {
+    *bg = pix2; *fg = pix1;
+  }
+  return tileType;
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef HEXTILE_ENCODE
+#undef HEXTILE_ENCODE_TILE
+#undef TEST_TILE_TYPE
+}
diff --git a/common/rfb/hextileEncodeBetter.h b/common/rfb/hextileEncodeBetter.h
new file mode 100644
index 0000000..2b6b160
--- /dev/null
+++ b/common/rfb/hextileEncodeBetter.h
@@ -0,0 +1,352 @@
+/* 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
+ * (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.
+ */
+//
+// Hextile encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+
+#include <rdr/OutStream.h>
+#include <rfb/hextileConstants.h>
+#include <rfb/TightPalette.h>
+
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define HEXTILE_TILE CONCAT2E(HextileTile,BPP)
+#define HEXTILE_ENCODE CONCAT2E(hextileEncodeBetter,BPP)
+
+//
+// This class analyzes a separate tile and encodes its subrectangles.
+//
+
+class HEXTILE_TILE {
+
+ public:
+
+  HEXTILE_TILE ();
+
+  //
+  // Initialize existing object instance with new tile data.
+  //
+  void newTile(const PIXEL_T *src, int w, int h);
+
+  //
+  // Flags can include: hextileRaw, hextileAnySubrects and
+  // hextileSubrectsColoured. Note that if hextileRaw is set, other
+  // flags make no sense. Also, hextileSubrectsColoured is meaningful
+  // only when hextileAnySubrects is set as well.
+  //
+  int getFlags() const { return m_flags; }
+
+  //
+  // Returns the size of encoded subrects data, including subrect count.
+  // The size is zero if flags do not include hextileAnySubrects.
+  //
+  int getSize() const { return m_size; }
+
+  //
+  // Return optimal background.
+  //
+  int getBackground() const { return m_background; }
+
+  //
+  // Return foreground if flags include hextileSubrectsColoured.
+  //
+  int getForeground() const { return m_foreground; }
+
+  //
+  // Encode subrects. This function may be called only if
+  // hextileAnySubrects bit is set in flags. The buffer size should be
+  // big enough to store at least the number of bytes returned by the
+  // getSize() method.
+  //
+  void encode(rdr::U8* dst) const;
+
+ protected:
+
+  //
+  // Analyze the tile pixels, fill in all the data fields.
+  //
+  void analyze();
+
+  const PIXEL_T *m_tile;
+  int m_width;
+  int m_height;
+
+  int m_size;
+  int m_flags;
+  PIXEL_T m_background;
+  PIXEL_T m_foreground;
+
+  int m_numSubrects;
+  rdr::U8 m_coords[256 * 2];
+  PIXEL_T m_colors[256];
+
+ private:
+
+  bool m_processed[16][16];
+  TightPalette m_pal;
+};
+
+HEXTILE_TILE::HEXTILE_TILE()
+  : m_tile(NULL), m_width(0), m_height(0),
+    m_size(0), m_flags(0), m_background(0), m_foreground(0),
+    m_numSubrects(0), m_pal(48 + 2 * BPP)
+{
+}
+
+void HEXTILE_TILE::newTile(const PIXEL_T *src, int w, int h)
+{
+  m_tile = src;
+  m_width = w;
+  m_height = h;
+
+  analyze();
+}
+
+void HEXTILE_TILE::analyze()
+{
+  assert(m_tile && m_width && m_height);
+
+  const PIXEL_T *ptr = m_tile;
+  const PIXEL_T *end = &m_tile[m_width * m_height];
+  PIXEL_T color = *ptr++;
+  while (ptr != end && *ptr == color)
+    ptr++;
+
+  // Handle solid tile
+  if (ptr == end) {
+    m_background = m_tile[0];
+    m_flags = 0;
+    m_size = 0;
+    return;
+  }
+
+  // Compute number of complete rows of the same color, at the top
+  int y = (ptr - m_tile) / m_width;
+
+  PIXEL_T *colorsPtr = m_colors;
+  rdr::U8 *coordsPtr = m_coords;
+  m_pal.reset();
+  m_numSubrects = 0;
+
+  // Have we found the first subrect already?
+  if (y > 0) {
+    *colorsPtr++ = color;
+    *coordsPtr++ = 0;
+    *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F));
+    m_pal.insert(color, 1);
+    m_numSubrects++;
+  }
+
+  memset(m_processed, 0, 16 * 16 * sizeof(bool));
+
+  int x, sx, sy, sw, sh, max_x;
+
+  for (; y < m_height; y++) {
+    for (x = 0; x < m_width; x++) {
+      // Skip pixels that were processed earlier
+      if (m_processed[y][x]) {
+        continue;
+      }
+      // Determine dimensions of the horizontal subrect
+      color = m_tile[y * m_width + x];
+      for (sx = x + 1; sx < m_width; sx++) {
+        if (m_tile[y * m_width + sx] != color)
+          break;
+      }
+      sw = sx - x;
+      max_x = sx;
+      for (sy = y + 1; sy < m_height; sy++) {
+        for (sx = x; sx < max_x; sx++) {
+          if (m_tile[sy * m_width + sx] != color)
+            goto done;
+        }
+      }
+    done:
+      sh = sy - y;
+
+      // Save properties of this subrect
+      *colorsPtr++ = color;
+      *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F));
+      *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F));
+
+      if (m_pal.insert(color, 1) == 0) {
+        // Handle palette overflow
+        m_flags = hextileRaw;
+        m_size = 0;
+        return;
+      }
+
+      m_numSubrects++;
+
+      // Mark pixels of this subrect as processed, below this row
+      for (sy = y + 1; sy < y + sh; sy++) {
+        for (sx = x; sx < x + sw; sx++)
+          m_processed[sy][sx] = true;
+      }
+
+      // Skip processed pixels of this row
+      x += (sw - 1);
+    }
+  }
+
+  // Save number of colors in this tile (should be no less than 2)
+  int numColors = m_pal.getNumColors();
+  assert(numColors >= 2);
+
+  m_background = (PIXEL_T)m_pal.getEntry(0);
+  m_flags = hextileAnySubrects;
+  int numSubrects = m_numSubrects - m_pal.getCount(0);
+
+  if (numColors == 2) {
+    // Monochrome tile
+    m_foreground = (PIXEL_T)m_pal.getEntry(1);
+    m_size = 1 + 2 * numSubrects;
+  } else {
+    // Colored tile
+    m_flags |= hextileSubrectsColoured;
+    m_size = 1 + (2 + (BPP/8)) * numSubrects;
+  }
+}
+
+void HEXTILE_TILE::encode(rdr::U8 *dst) const
+{
+  assert(m_numSubrects && (m_flags & hextileAnySubrects));
+
+  // Zero subrects counter
+  rdr::U8 *numSubrectsPtr = dst;
+  *dst++ = 0;
+
+  for (int i = 0; i < m_numSubrects; i++) {
+    if (m_colors[i] == m_background)
+      continue;
+
+    if (m_flags & hextileSubrectsColoured) {
+#if (BPP == 8)
+      *dst++ = m_colors[i];
+#elif (BPP == 16)
+      *dst++ = ((rdr::U8*)&m_colors[i])[0];
+      *dst++ = ((rdr::U8*)&m_colors[i])[1];
+#elif (BPP == 32)
+      *dst++ = ((rdr::U8*)&m_colors[i])[0];
+      *dst++ = ((rdr::U8*)&m_colors[i])[1];
+      *dst++ = ((rdr::U8*)&m_colors[i])[2];
+      *dst++ = ((rdr::U8*)&m_colors[i])[3];
+#endif
+    }
+    *dst++ = m_coords[i * 2];
+    *dst++ = m_coords[i * 2 + 1];
+
+    (*numSubrectsPtr)++;
+  }
+
+  assert(dst - numSubrectsPtr == m_size);
+}
+
+//
+// Main encoding function.
+//
+
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os
+#ifdef EXTRA_ARGS
+                    , EXTRA_ARGS
+#endif
+                    )
+{
+  Rect t;
+  PIXEL_T buf[256];
+  PIXEL_T oldBg = 0, oldFg = 0;
+  bool oldBgValid = false;
+  bool oldFgValid = false;
+  rdr::U8 encoded[256*(BPP/8)];
+
+  HEXTILE_TILE tile;
+
+  for (t.tl.y = r.tl.y; t.tl.y < 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 = __rfbmin(r.br.x, t.tl.x + 16);
+
+      GET_IMAGE_INTO_BUF(t,buf);
+
+      tile.newTile(buf, t.width(), t.height());
+      int tileType = tile.getFlags();
+      int encodedLen = tile.getSize();
+
+      if ( (tileType & hextileRaw) != 0 ||
+           encodedLen >= t.width() * t.height() * (BPP/8)) {
+        os->writeU8(hextileRaw);
+        os->writeBytes(buf, t.width() * t.height() * (BPP/8));
+        oldBgValid = oldFgValid = false;
+        continue;
+      }
+
+      PIXEL_T bg = tile.getBackground();
+      PIXEL_T fg = 0;
+
+      if (!oldBgValid || oldBg != bg) {
+        tileType |= hextileBgSpecified;
+        oldBg = bg;
+        oldBgValid = true;
+      }
+
+      if (tileType & hextileAnySubrects) {
+        if (tileType & hextileSubrectsColoured) {
+          oldFgValid = false;
+        } else {
+          fg = tile.getForeground();
+          if (!oldFgValid || oldFg != fg) {
+            tileType |= hextileFgSpecified;
+            oldFg = fg;
+            oldFgValid = true;
+          }
+        }
+        tile.encode(encoded);
+      }
+
+      os->writeU8(tileType);
+      if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
+      if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
+      if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
+    }
+  }
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef HEXTILE_TILE
+#undef HEXTILE_ENCODE
+}
diff --git a/common/rfb/keysymdef.h b/common/rfb/keysymdef.h
new file mode 100644
index 0000000..979ebdd
--- /dev/null
+++ b/common/rfb/keysymdef.h
@@ -0,0 +1,1595 @@
+/* $TOG: keysymdef.h /main/28 1998/05/22 16:18:01 kaleb $ */
+
+/***********************************************************
+Copyright 1987, 1994, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#define XK_VoidSymbol		0xFFFFFF	/* void symbol */
+
+#ifdef XK_MISCELLANY
+/*
+ * TTY Functions, cleverly chosen to map to ascii, for convenience of
+ * programming, but could have been arbitrary (at the cost of lookup
+ * tables in client code.
+ */
+
+#define XK_BackSpace		0xFF08	/* back space, back char */
+#define XK_Tab			0xFF09
+#define XK_Linefeed		0xFF0A	/* Linefeed, LF */
+#define XK_Clear		0xFF0B
+#define XK_Return		0xFF0D	/* Return, enter */
+#define XK_Pause		0xFF13	/* Pause, hold */
+#define XK_Scroll_Lock		0xFF14
+#define XK_Sys_Req		0xFF15
+#define XK_Escape		0xFF1B
+#define XK_Delete		0xFFFF	/* Delete, rubout */
+
+
+
+/* International & multi-key character composition */
+
+#define XK_Multi_key		0xFF20  /* Multi-key character compose */
+#define XK_Codeinput		0xFF37
+#define XK_SingleCandidate	0xFF3C
+#define XK_MultipleCandidate	0xFF3D
+#define XK_PreviousCandidate	0xFF3E
+
+/* Japanese keyboard support */
+
+#define XK_Kanji		0xFF21	/* Kanji, Kanji convert */
+#define XK_Muhenkan		0xFF22  /* Cancel Conversion */
+#define XK_Henkan_Mode		0xFF23  /* Start/Stop Conversion */
+#define XK_Henkan		0xFF23  /* Alias for Henkan_Mode */
+#define XK_Romaji		0xFF24  /* to Romaji */
+#define XK_Hiragana		0xFF25  /* to Hiragana */
+#define XK_Katakana		0xFF26  /* to Katakana */
+#define XK_Hiragana_Katakana	0xFF27  /* Hiragana/Katakana toggle */
+#define XK_Zenkaku		0xFF28  /* to Zenkaku */
+#define XK_Hankaku		0xFF29  /* to Hankaku */
+#define XK_Zenkaku_Hankaku	0xFF2A  /* Zenkaku/Hankaku toggle */
+#define XK_Touroku		0xFF2B  /* Add to Dictionary */
+#define XK_Massyo		0xFF2C  /* Delete from Dictionary */
+#define XK_Kana_Lock		0xFF2D  /* Kana Lock */
+#define XK_Kana_Shift		0xFF2E  /* Kana Shift */
+#define XK_Eisu_Shift		0xFF2F  /* Alphanumeric Shift */
+#define XK_Eisu_toggle		0xFF30  /* Alphanumeric toggle */
+#define XK_Kanji_Bangou		0xFF37  /* Codeinput */
+#define XK_Zen_Koho		0xFF3D	/* Multiple/All Candidate(s) */
+#define XK_Mae_Koho		0xFF3E	/* Previous Candidate */
+
+/* 0xFF31 thru 0xFF3F are under XK_KOREAN */
+
+/* Cursor control & motion */
+
+#define XK_Home			0xFF50
+#define XK_Left			0xFF51	/* Move left, left arrow */
+#define XK_Up			0xFF52	/* Move up, up arrow */
+#define XK_Right		0xFF53	/* Move right, right arrow */
+#define XK_Down			0xFF54	/* Move down, down arrow */
+#define XK_Prior		0xFF55	/* Prior, previous */
+#define XK_Page_Up		0xFF55
+#define XK_Next			0xFF56	/* Next */
+#define XK_Page_Down		0xFF56
+#define XK_End			0xFF57	/* EOL */
+#define XK_Begin		0xFF58	/* BOL */
+
+
+/* Misc Functions */
+
+#define XK_Select		0xFF60	/* Select, mark */
+#define XK_Print		0xFF61
+#define XK_Execute		0xFF62	/* Execute, run, do */
+#define XK_Insert		0xFF63	/* Insert, insert here */
+#define XK_Undo			0xFF65	/* Undo, oops */
+#define XK_Redo			0xFF66	/* redo, again */
+#define XK_Menu			0xFF67
+#define XK_Find			0xFF68	/* Find, search */
+#define XK_Cancel		0xFF69	/* Cancel, stop, abort, exit */
+#define XK_Help			0xFF6A	/* Help */
+#define XK_Break		0xFF6B
+#define XK_Mode_switch		0xFF7E	/* Character set switch */
+#define XK_script_switch        0xFF7E  /* Alias for mode_switch */
+#define XK_Num_Lock		0xFF7F
+
+/* Keypad Functions, keypad numbers cleverly chosen to map to ascii */
+
+#define XK_KP_Space		0xFF80	/* space */
+#define XK_KP_Tab		0xFF89
+#define XK_KP_Enter		0xFF8D	/* enter */
+#define XK_KP_F1		0xFF91	/* PF1, KP_A, ... */
+#define XK_KP_F2		0xFF92
+#define XK_KP_F3		0xFF93
+#define XK_KP_F4		0xFF94
+#define XK_KP_Home		0xFF95
+#define XK_KP_Left		0xFF96
+#define XK_KP_Up		0xFF97
+#define XK_KP_Right		0xFF98
+#define XK_KP_Down		0xFF99
+#define XK_KP_Prior		0xFF9A
+#define XK_KP_Page_Up		0xFF9A
+#define XK_KP_Next		0xFF9B
+#define XK_KP_Page_Down		0xFF9B
+#define XK_KP_End		0xFF9C
+#define XK_KP_Begin		0xFF9D
+#define XK_KP_Insert		0xFF9E
+#define XK_KP_Delete		0xFF9F
+#define XK_KP_Equal		0xFFBD	/* equals */
+#define XK_KP_Multiply		0xFFAA
+#define XK_KP_Add		0xFFAB
+#define XK_KP_Separator		0xFFAC	/* separator, often comma */
+#define XK_KP_Subtract		0xFFAD
+#define XK_KP_Decimal		0xFFAE
+#define XK_KP_Divide		0xFFAF
+
+#define XK_KP_0			0xFFB0
+#define XK_KP_1			0xFFB1
+#define XK_KP_2			0xFFB2
+#define XK_KP_3			0xFFB3
+#define XK_KP_4			0xFFB4
+#define XK_KP_5			0xFFB5
+#define XK_KP_6			0xFFB6
+#define XK_KP_7			0xFFB7
+#define XK_KP_8			0xFFB8
+#define XK_KP_9			0xFFB9
+
+
+
+/*
+ * Auxilliary Functions; note the duplicate definitions for left and right
+ * function keys;  Sun keyboards and a few other manufactures have such
+ * function key groups on the left and/or right sides of the keyboard.
+ * We've not found a keyboard with more than 35 function keys total.
+ */
+
+#define XK_F1			0xFFBE
+#define XK_F2			0xFFBF
+#define XK_F3			0xFFC0
+#define XK_F4			0xFFC1
+#define XK_F5			0xFFC2
+#define XK_F6			0xFFC3
+#define XK_F7			0xFFC4
+#define XK_F8			0xFFC5
+#define XK_F9			0xFFC6
+#define XK_F10			0xFFC7
+#define XK_F11			0xFFC8
+#define XK_L1			0xFFC8
+#define XK_F12			0xFFC9
+#define XK_L2			0xFFC9
+#define XK_F13			0xFFCA
+#define XK_L3			0xFFCA
+#define XK_F14			0xFFCB
+#define XK_L4			0xFFCB
+#define XK_F15			0xFFCC
+#define XK_L5			0xFFCC
+#define XK_F16			0xFFCD
+#define XK_L6			0xFFCD
+#define XK_F17			0xFFCE
+#define XK_L7			0xFFCE
+#define XK_F18			0xFFCF
+#define XK_L8			0xFFCF
+#define XK_F19			0xFFD0
+#define XK_L9			0xFFD0
+#define XK_F20			0xFFD1
+#define XK_L10			0xFFD1
+#define XK_F21			0xFFD2
+#define XK_R1			0xFFD2
+#define XK_F22			0xFFD3
+#define XK_R2			0xFFD3
+#define XK_F23			0xFFD4
+#define XK_R3			0xFFD4
+#define XK_F24			0xFFD5
+#define XK_R4			0xFFD5
+#define XK_F25			0xFFD6
+#define XK_R5			0xFFD6
+#define XK_F26			0xFFD7
+#define XK_R6			0xFFD7
+#define XK_F27			0xFFD8
+#define XK_R7			0xFFD8
+#define XK_F28			0xFFD9
+#define XK_R8			0xFFD9
+#define XK_F29			0xFFDA
+#define XK_R9			0xFFDA
+#define XK_F30			0xFFDB
+#define XK_R10			0xFFDB
+#define XK_F31			0xFFDC
+#define XK_R11			0xFFDC
+#define XK_F32			0xFFDD
+#define XK_R12			0xFFDD
+#define XK_F33			0xFFDE
+#define XK_R13			0xFFDE
+#define XK_F34			0xFFDF
+#define XK_R14			0xFFDF
+#define XK_F35			0xFFE0
+#define XK_R15			0xFFE0
+
+/* Modifiers */
+
+#define XK_Shift_L		0xFFE1	/* Left shift */
+#define XK_Shift_R		0xFFE2	/* Right shift */
+#define XK_Control_L		0xFFE3	/* Left control */
+#define XK_Control_R		0xFFE4	/* Right control */
+#define XK_Caps_Lock		0xFFE5	/* Caps lock */
+#define XK_Shift_Lock		0xFFE6	/* Shift lock */
+
+#define XK_Meta_L		0xFFE7	/* Left meta */
+#define XK_Meta_R		0xFFE8	/* Right meta */
+#define XK_Alt_L		0xFFE9	/* Left alt */
+#define XK_Alt_R		0xFFEA	/* Right alt */
+#define XK_Super_L		0xFFEB	/* Left super */
+#define XK_Super_R		0xFFEC	/* Right super */
+#define XK_Hyper_L		0xFFED	/* Left hyper */
+#define XK_Hyper_R		0xFFEE	/* Right hyper */
+#endif /* XK_MISCELLANY */
+
+/*
+ * ISO 9995 Function and Modifier Keys
+ * Byte 3 = 0xFE
+ */
+
+#ifdef XK_XKB_KEYS
+#define	XK_ISO_Lock					0xFE01
+#define	XK_ISO_Level2_Latch				0xFE02
+#define	XK_ISO_Level3_Shift				0xFE03
+#define	XK_ISO_Level3_Latch				0xFE04
+#define	XK_ISO_Level3_Lock				0xFE05
+#define	XK_ISO_Group_Shift		0xFF7E	/* Alias for mode_switch */
+#define	XK_ISO_Group_Latch				0xFE06
+#define	XK_ISO_Group_Lock				0xFE07
+#define	XK_ISO_Next_Group				0xFE08
+#define	XK_ISO_Next_Group_Lock				0xFE09
+#define	XK_ISO_Prev_Group				0xFE0A
+#define	XK_ISO_Prev_Group_Lock				0xFE0B
+#define	XK_ISO_First_Group				0xFE0C
+#define	XK_ISO_First_Group_Lock				0xFE0D
+#define	XK_ISO_Last_Group				0xFE0E
+#define	XK_ISO_Last_Group_Lock				0xFE0F
+
+#define	XK_ISO_Left_Tab					0xFE20
+#define	XK_ISO_Move_Line_Up				0xFE21
+#define	XK_ISO_Move_Line_Down				0xFE22
+#define	XK_ISO_Partial_Line_Up				0xFE23
+#define	XK_ISO_Partial_Line_Down			0xFE24
+#define	XK_ISO_Partial_Space_Left			0xFE25
+#define	XK_ISO_Partial_Space_Right			0xFE26
+#define	XK_ISO_Set_Margin_Left				0xFE27
+#define	XK_ISO_Set_Margin_Right				0xFE28
+#define	XK_ISO_Release_Margin_Left			0xFE29
+#define	XK_ISO_Release_Margin_Right			0xFE2A
+#define	XK_ISO_Release_Both_Margins			0xFE2B
+#define	XK_ISO_Fast_Cursor_Left				0xFE2C
+#define	XK_ISO_Fast_Cursor_Right			0xFE2D
+#define	XK_ISO_Fast_Cursor_Up				0xFE2E
+#define	XK_ISO_Fast_Cursor_Down				0xFE2F
+#define	XK_ISO_Continuous_Underline			0xFE30
+#define	XK_ISO_Discontinuous_Underline			0xFE31
+#define	XK_ISO_Emphasize				0xFE32
+#define	XK_ISO_Center_Object				0xFE33
+#define	XK_ISO_Enter					0xFE34
+
+#define	XK_dead_grave					0xFE50
+#define	XK_dead_acute					0xFE51
+#define	XK_dead_circumflex				0xFE52
+#define	XK_dead_tilde					0xFE53
+#define	XK_dead_macron					0xFE54
+#define	XK_dead_breve					0xFE55
+#define	XK_dead_abovedot				0xFE56
+#define	XK_dead_diaeresis				0xFE57
+#define	XK_dead_abovering				0xFE58
+#define	XK_dead_doubleacute				0xFE59
+#define	XK_dead_caron					0xFE5A
+#define	XK_dead_cedilla					0xFE5B
+#define	XK_dead_ogonek					0xFE5C
+#define	XK_dead_iota					0xFE5D
+#define	XK_dead_voiced_sound				0xFE5E
+#define	XK_dead_semivoiced_sound			0xFE5F
+#define	XK_dead_belowdot				0xFE60
+
+#define	XK_First_Virtual_Screen				0xFED0
+#define	XK_Prev_Virtual_Screen				0xFED1
+#define	XK_Next_Virtual_Screen				0xFED2
+#define	XK_Last_Virtual_Screen				0xFED4
+#define	XK_Terminate_Server				0xFED5
+
+#define	XK_AccessX_Enable				0xFE70
+#define	XK_AccessX_Feedback_Enable			0xFE71
+#define	XK_RepeatKeys_Enable				0xFE72
+#define	XK_SlowKeys_Enable				0xFE73
+#define	XK_BounceKeys_Enable				0xFE74
+#define	XK_StickyKeys_Enable				0xFE75
+#define	XK_MouseKeys_Enable				0xFE76
+#define	XK_MouseKeys_Accel_Enable			0xFE77
+#define	XK_Overlay1_Enable				0xFE78
+#define	XK_Overlay2_Enable				0xFE79
+#define	XK_AudibleBell_Enable				0xFE7A
+
+#define	XK_Pointer_Left					0xFEE0
+#define	XK_Pointer_Right				0xFEE1
+#define	XK_Pointer_Up					0xFEE2
+#define	XK_Pointer_Down					0xFEE3
+#define	XK_Pointer_UpLeft				0xFEE4
+#define	XK_Pointer_UpRight				0xFEE5
+#define	XK_Pointer_DownLeft				0xFEE6
+#define	XK_Pointer_DownRight				0xFEE7
+#define	XK_Pointer_Button_Dflt				0xFEE8
+#define	XK_Pointer_Button1				0xFEE9
+#define	XK_Pointer_Button2				0xFEEA
+#define	XK_Pointer_Button3				0xFEEB
+#define	XK_Pointer_Button4				0xFEEC
+#define	XK_Pointer_Button5				0xFEED
+#define	XK_Pointer_DblClick_Dflt			0xFEEE
+#define	XK_Pointer_DblClick1				0xFEEF
+#define	XK_Pointer_DblClick2				0xFEF0
+#define	XK_Pointer_DblClick3				0xFEF1
+#define	XK_Pointer_DblClick4				0xFEF2
+#define	XK_Pointer_DblClick5				0xFEF3
+#define	XK_Pointer_Drag_Dflt				0xFEF4
+#define	XK_Pointer_Drag1				0xFEF5
+#define	XK_Pointer_Drag2				0xFEF6
+#define	XK_Pointer_Drag3				0xFEF7
+#define	XK_Pointer_Drag4				0xFEF8
+#define	XK_Pointer_Drag5				0xFEFD
+
+#define	XK_Pointer_EnableKeys				0xFEF9
+#define	XK_Pointer_Accelerate				0xFEFA
+#define	XK_Pointer_DfltBtnNext				0xFEFB
+#define	XK_Pointer_DfltBtnPrev				0xFEFC
+
+#endif
+
+/*
+ * 3270 Terminal Keys
+ * Byte 3 = 0xFD
+ */
+
+#ifdef XK_3270
+#define XK_3270_Duplicate      0xFD01
+#define XK_3270_FieldMark      0xFD02
+#define XK_3270_Right2         0xFD03
+#define XK_3270_Left2          0xFD04
+#define XK_3270_BackTab        0xFD05
+#define XK_3270_EraseEOF       0xFD06
+#define XK_3270_EraseInput     0xFD07
+#define XK_3270_Reset          0xFD08
+#define XK_3270_Quit           0xFD09
+#define XK_3270_PA1            0xFD0A
+#define XK_3270_PA2            0xFD0B
+#define XK_3270_PA3            0xFD0C
+#define XK_3270_Test           0xFD0D
+#define XK_3270_Attn           0xFD0E
+#define XK_3270_CursorBlink    0xFD0F
+#define XK_3270_AltCursor      0xFD10
+#define XK_3270_KeyClick       0xFD11
+#define XK_3270_Jump           0xFD12
+#define XK_3270_Ident          0xFD13
+#define XK_3270_Rule           0xFD14
+#define XK_3270_Copy           0xFD15
+#define XK_3270_Play           0xFD16
+#define XK_3270_Setup          0xFD17
+#define XK_3270_Record         0xFD18
+#define XK_3270_ChangeScreen   0xFD19
+#define XK_3270_DeleteWord     0xFD1A
+#define XK_3270_ExSelect       0xFD1B
+#define XK_3270_CursorSelect   0xFD1C
+#define XK_3270_PrintScreen    0xFD1D
+#define XK_3270_Enter          0xFD1E
+#endif
+
+/*
+ *  Latin 1
+ *  Byte 3 = 0
+ */
+#ifdef XK_LATIN1
+#define XK_space               0x020
+#define XK_exclam              0x021
+#define XK_quotedbl            0x022
+#define XK_numbersign          0x023
+#define XK_dollar              0x024
+#define XK_percent             0x025
+#define XK_ampersand           0x026
+#define XK_apostrophe          0x027
+#define XK_quoteright          0x027	/* deprecated */
+#define XK_parenleft           0x028
+#define XK_parenright          0x029
+#define XK_asterisk            0x02a
+#define XK_plus                0x02b
+#define XK_comma               0x02c
+#define XK_minus               0x02d
+#define XK_period              0x02e
+#define XK_slash               0x02f
+#define XK_0                   0x030
+#define XK_1                   0x031
+#define XK_2                   0x032
+#define XK_3                   0x033
+#define XK_4                   0x034
+#define XK_5                   0x035
+#define XK_6                   0x036
+#define XK_7                   0x037
+#define XK_8                   0x038
+#define XK_9                   0x039
+#define XK_colon               0x03a
+#define XK_semicolon           0x03b
+#define XK_less                0x03c
+#define XK_equal               0x03d
+#define XK_greater             0x03e
+#define XK_question            0x03f
+#define XK_at                  0x040
+#define XK_A                   0x041
+#define XK_B                   0x042
+#define XK_C                   0x043
+#define XK_D                   0x044
+#define XK_E                   0x045
+#define XK_F                   0x046
+#define XK_G                   0x047
+#define XK_H                   0x048
+#define XK_I                   0x049
+#define XK_J                   0x04a
+#define XK_K                   0x04b
+#define XK_L                   0x04c
+#define XK_M                   0x04d
+#define XK_N                   0x04e
+#define XK_O                   0x04f
+#define XK_P                   0x050
+#define XK_Q                   0x051
+#define XK_R                   0x052
+#define XK_S                   0x053
+#define XK_T                   0x054
+#define XK_U                   0x055
+#define XK_V                   0x056
+#define XK_W                   0x057
+#define XK_X                   0x058
+#define XK_Y                   0x059
+#define XK_Z                   0x05a
+#define XK_bracketleft         0x05b
+#define XK_backslash           0x05c
+#define XK_bracketright        0x05d
+#define XK_asciicircum         0x05e
+#define XK_underscore          0x05f
+#define XK_grave               0x060
+#define XK_quoteleft           0x060	/* deprecated */
+#define XK_a                   0x061
+#define XK_b                   0x062
+#define XK_c                   0x063
+#define XK_d                   0x064
+#define XK_e                   0x065
+#define XK_f                   0x066
+#define XK_g                   0x067
+#define XK_h                   0x068
+#define XK_i                   0x069
+#define XK_j                   0x06a
+#define XK_k                   0x06b
+#define XK_l                   0x06c
+#define XK_m                   0x06d
+#define XK_n                   0x06e
+#define XK_o                   0x06f
+#define XK_p                   0x070
+#define XK_q                   0x071
+#define XK_r                   0x072
+#define XK_s                   0x073
+#define XK_t                   0x074
+#define XK_u                   0x075
+#define XK_v                   0x076
+#define XK_w                   0x077
+#define XK_x                   0x078
+#define XK_y                   0x079
+#define XK_z                   0x07a
+#define XK_braceleft           0x07b
+#define XK_bar                 0x07c
+#define XK_braceright          0x07d
+#define XK_asciitilde          0x07e
+
+#define XK_nobreakspace        0x0a0
+#define XK_exclamdown          0x0a1
+#define XK_cent        	       0x0a2
+#define XK_sterling            0x0a3
+#define XK_currency            0x0a4
+#define XK_yen                 0x0a5
+#define XK_brokenbar           0x0a6
+#define XK_section             0x0a7
+#define XK_diaeresis           0x0a8
+#define XK_copyright           0x0a9
+#define XK_ordfeminine         0x0aa
+#define XK_guillemotleft       0x0ab	/* left angle quotation mark */
+#define XK_notsign             0x0ac
+#define XK_hyphen              0x0ad
+#define XK_registered          0x0ae
+#define XK_macron              0x0af
+#define XK_degree              0x0b0
+#define XK_plusminus           0x0b1
+#define XK_twosuperior         0x0b2
+#define XK_threesuperior       0x0b3
+#define XK_acute               0x0b4
+#define XK_mu                  0x0b5
+#define XK_paragraph           0x0b6
+#define XK_periodcentered      0x0b7
+#define XK_cedilla             0x0b8
+#define XK_onesuperior         0x0b9
+#define XK_masculine           0x0ba
+#define XK_guillemotright      0x0bb	/* right angle quotation mark */
+#define XK_onequarter          0x0bc
+#define XK_onehalf             0x0bd
+#define XK_threequarters       0x0be
+#define XK_questiondown        0x0bf
+#define XK_Agrave              0x0c0
+#define XK_Aacute              0x0c1
+#define XK_Acircumflex         0x0c2
+#define XK_Atilde              0x0c3
+#define XK_Adiaeresis          0x0c4
+#define XK_Aring               0x0c5
+#define XK_AE                  0x0c6
+#define XK_Ccedilla            0x0c7
+#define XK_Egrave              0x0c8
+#define XK_Eacute              0x0c9
+#define XK_Ecircumflex         0x0ca
+#define XK_Ediaeresis          0x0cb
+#define XK_Igrave              0x0cc
+#define XK_Iacute              0x0cd
+#define XK_Icircumflex         0x0ce
+#define XK_Idiaeresis          0x0cf
+#define XK_ETH                 0x0d0
+#define XK_Eth                 0x0d0	/* deprecated */
+#define XK_Ntilde              0x0d1
+#define XK_Ograve              0x0d2
+#define XK_Oacute              0x0d3
+#define XK_Ocircumflex         0x0d4
+#define XK_Otilde              0x0d5
+#define XK_Odiaeresis          0x0d6
+#define XK_multiply            0x0d7
+#define XK_Ooblique            0x0d8
+#define XK_Ugrave              0x0d9
+#define XK_Uacute              0x0da
+#define XK_Ucircumflex         0x0db
+#define XK_Udiaeresis          0x0dc
+#define XK_Yacute              0x0dd
+#define XK_THORN               0x0de
+#define XK_Thorn               0x0de	/* deprecated */
+#define XK_ssharp              0x0df
+#define XK_agrave              0x0e0
+#define XK_aacute              0x0e1
+#define XK_acircumflex         0x0e2
+#define XK_atilde              0x0e3
+#define XK_adiaeresis          0x0e4
+#define XK_aring               0x0e5
+#define XK_ae                  0x0e6
+#define XK_ccedilla            0x0e7
+#define XK_egrave              0x0e8
+#define XK_eacute              0x0e9
+#define XK_ecircumflex         0x0ea
+#define XK_ediaeresis          0x0eb
+#define XK_igrave              0x0ec
+#define XK_iacute              0x0ed
+#define XK_icircumflex         0x0ee
+#define XK_idiaeresis          0x0ef
+#define XK_eth                 0x0f0
+#define XK_ntilde              0x0f1
+#define XK_ograve              0x0f2
+#define XK_oacute              0x0f3
+#define XK_ocircumflex         0x0f4
+#define XK_otilde              0x0f5
+#define XK_odiaeresis          0x0f6
+#define XK_division            0x0f7
+#define XK_oslash              0x0f8
+#define XK_ugrave              0x0f9
+#define XK_uacute              0x0fa
+#define XK_ucircumflex         0x0fb
+#define XK_udiaeresis          0x0fc
+#define XK_yacute              0x0fd
+#define XK_thorn               0x0fe
+#define XK_ydiaeresis          0x0ff
+#endif /* XK_LATIN1 */
+
+/*
+ *   Latin 2
+ *   Byte 3 = 1
+ */
+
+#ifdef XK_LATIN2
+#define XK_Aogonek             0x1a1
+#define XK_breve               0x1a2
+#define XK_Lstroke             0x1a3
+#define XK_Lcaron              0x1a5
+#define XK_Sacute              0x1a6
+#define XK_Scaron              0x1a9
+#define XK_Scedilla            0x1aa
+#define XK_Tcaron              0x1ab
+#define XK_Zacute              0x1ac
+#define XK_Zcaron              0x1ae
+#define XK_Zabovedot           0x1af
+#define XK_aogonek             0x1b1
+#define XK_ogonek              0x1b2
+#define XK_lstroke             0x1b3
+#define XK_lcaron              0x1b5
+#define XK_sacute              0x1b6
+#define XK_caron               0x1b7
+#define XK_scaron              0x1b9
+#define XK_scedilla            0x1ba
+#define XK_tcaron              0x1bb
+#define XK_zacute              0x1bc
+#define XK_doubleacute         0x1bd
+#define XK_zcaron              0x1be
+#define XK_zabovedot           0x1bf
+#define XK_Racute              0x1c0
+#define XK_Abreve              0x1c3
+#define XK_Lacute              0x1c5
+#define XK_Cacute              0x1c6
+#define XK_Ccaron              0x1c8
+#define XK_Eogonek             0x1ca
+#define XK_Ecaron              0x1cc
+#define XK_Dcaron              0x1cf
+#define XK_Dstroke             0x1d0
+#define XK_Nacute              0x1d1
+#define XK_Ncaron              0x1d2
+#define XK_Odoubleacute        0x1d5
+#define XK_Rcaron              0x1d8
+#define XK_Uring               0x1d9
+#define XK_Udoubleacute        0x1db
+#define XK_Tcedilla            0x1de
+#define XK_racute              0x1e0
+#define XK_abreve              0x1e3
+#define XK_lacute              0x1e5
+#define XK_cacute              0x1e6
+#define XK_ccaron              0x1e8
+#define XK_eogonek             0x1ea
+#define XK_ecaron              0x1ec
+#define XK_dcaron              0x1ef
+#define XK_dstroke             0x1f0
+#define XK_nacute              0x1f1
+#define XK_ncaron              0x1f2
+#define XK_odoubleacute        0x1f5
+#define XK_udoubleacute        0x1fb
+#define XK_rcaron              0x1f8
+#define XK_uring               0x1f9
+#define XK_tcedilla            0x1fe
+#define XK_abovedot            0x1ff
+#endif /* XK_LATIN2 */
+
+/*
+ *   Latin 3
+ *   Byte 3 = 2
+ */
+
+#ifdef XK_LATIN3
+#define XK_Hstroke             0x2a1
+#define XK_Hcircumflex         0x2a6
+#define XK_Iabovedot           0x2a9
+#define XK_Gbreve              0x2ab
+#define XK_Jcircumflex         0x2ac
+#define XK_hstroke             0x2b1
+#define XK_hcircumflex         0x2b6
+#define XK_idotless            0x2b9
+#define XK_gbreve              0x2bb
+#define XK_jcircumflex         0x2bc
+#define XK_Cabovedot           0x2c5
+#define XK_Ccircumflex         0x2c6
+#define XK_Gabovedot           0x2d5
+#define XK_Gcircumflex         0x2d8
+#define XK_Ubreve              0x2dd
+#define XK_Scircumflex         0x2de
+#define XK_cabovedot           0x2e5
+#define XK_ccircumflex         0x2e6
+#define XK_gabovedot           0x2f5
+#define XK_gcircumflex         0x2f8
+#define XK_ubreve              0x2fd
+#define XK_scircumflex         0x2fe
+#endif /* XK_LATIN3 */
+
+
+/*
+ *   Latin 4
+ *   Byte 3 = 3
+ */
+
+#ifdef XK_LATIN4
+#define XK_kra                 0x3a2
+#define XK_kappa               0x3a2	/* deprecated */
+#define XK_Rcedilla            0x3a3
+#define XK_Itilde              0x3a5
+#define XK_Lcedilla            0x3a6
+#define XK_Emacron             0x3aa
+#define XK_Gcedilla            0x3ab
+#define XK_Tslash              0x3ac
+#define XK_rcedilla            0x3b3
+#define XK_itilde              0x3b5
+#define XK_lcedilla            0x3b6
+#define XK_emacron             0x3ba
+#define XK_gcedilla            0x3bb
+#define XK_tslash              0x3bc
+#define XK_ENG                 0x3bd
+#define XK_eng                 0x3bf
+#define XK_Amacron             0x3c0
+#define XK_Iogonek             0x3c7
+#define XK_Eabovedot           0x3cc
+#define XK_Imacron             0x3cf
+#define XK_Ncedilla            0x3d1
+#define XK_Omacron             0x3d2
+#define XK_Kcedilla            0x3d3
+#define XK_Uogonek             0x3d9
+#define XK_Utilde              0x3dd
+#define XK_Umacron             0x3de
+#define XK_amacron             0x3e0
+#define XK_iogonek             0x3e7
+#define XK_eabovedot           0x3ec
+#define XK_imacron             0x3ef
+#define XK_ncedilla            0x3f1
+#define XK_omacron             0x3f2
+#define XK_kcedilla            0x3f3
+#define XK_uogonek             0x3f9
+#define XK_utilde              0x3fd
+#define XK_umacron             0x3fe
+#endif /* XK_LATIN4 */
+
+/*
+ * Latin-9 (a.k.a. Latin-0)
+ * Byte 3 = 19
+ */
+
+#ifdef XK_LATIN9
+#define XK_OE                  0x13bc
+#define XK_oe                  0x13bd
+#define XK_Ydiaeresis          0x13be
+#endif /* XK_LATIN9 */
+
+/*
+ * Katakana
+ * Byte 3 = 4
+ */
+
+#ifdef XK_KATAKANA
+#define XK_overline				       0x47e
+#define XK_kana_fullstop                               0x4a1
+#define XK_kana_openingbracket                         0x4a2
+#define XK_kana_closingbracket                         0x4a3
+#define XK_kana_comma                                  0x4a4
+#define XK_kana_conjunctive                            0x4a5
+#define XK_kana_middledot                              0x4a5  /* deprecated */
+#define XK_kana_WO                                     0x4a6
+#define XK_kana_a                                      0x4a7
+#define XK_kana_i                                      0x4a8
+#define XK_kana_u                                      0x4a9
+#define XK_kana_e                                      0x4aa
+#define XK_kana_o                                      0x4ab
+#define XK_kana_ya                                     0x4ac
+#define XK_kana_yu                                     0x4ad
+#define XK_kana_yo                                     0x4ae
+#define XK_kana_tsu                                    0x4af
+#define XK_kana_tu                                     0x4af  /* deprecated */
+#define XK_prolongedsound                              0x4b0
+#define XK_kana_A                                      0x4b1
+#define XK_kana_I                                      0x4b2
+#define XK_kana_U                                      0x4b3
+#define XK_kana_E                                      0x4b4
+#define XK_kana_O                                      0x4b5
+#define XK_kana_KA                                     0x4b6
+#define XK_kana_KI                                     0x4b7
+#define XK_kana_KU                                     0x4b8
+#define XK_kana_KE                                     0x4b9
+#define XK_kana_KO                                     0x4ba
+#define XK_kana_SA                                     0x4bb
+#define XK_kana_SHI                                    0x4bc
+#define XK_kana_SU                                     0x4bd
+#define XK_kana_SE                                     0x4be
+#define XK_kana_SO                                     0x4bf
+#define XK_kana_TA                                     0x4c0
+#define XK_kana_CHI                                    0x4c1
+#define XK_kana_TI                                     0x4c1  /* deprecated */
+#define XK_kana_TSU                                    0x4c2
+#define XK_kana_TU                                     0x4c2  /* deprecated */
+#define XK_kana_TE                                     0x4c3
+#define XK_kana_TO                                     0x4c4
+#define XK_kana_NA                                     0x4c5
+#define XK_kana_NI                                     0x4c6
+#define XK_kana_NU                                     0x4c7
+#define XK_kana_NE                                     0x4c8
+#define XK_kana_NO                                     0x4c9
+#define XK_kana_HA                                     0x4ca
+#define XK_kana_HI                                     0x4cb
+#define XK_kana_FU                                     0x4cc
+#define XK_kana_HU                                     0x4cc  /* deprecated */
+#define XK_kana_HE                                     0x4cd
+#define XK_kana_HO                                     0x4ce
+#define XK_kana_MA                                     0x4cf
+#define XK_kana_MI                                     0x4d0
+#define XK_kana_MU                                     0x4d1
+#define XK_kana_ME                                     0x4d2
+#define XK_kana_MO                                     0x4d3
+#define XK_kana_YA                                     0x4d4
+#define XK_kana_YU                                     0x4d5
+#define XK_kana_YO                                     0x4d6
+#define XK_kana_RA                                     0x4d7
+#define XK_kana_RI                                     0x4d8
+#define XK_kana_RU                                     0x4d9
+#define XK_kana_RE                                     0x4da
+#define XK_kana_RO                                     0x4db
+#define XK_kana_WA                                     0x4dc
+#define XK_kana_N                                      0x4dd
+#define XK_voicedsound                                 0x4de
+#define XK_semivoicedsound                             0x4df
+#define XK_kana_switch          0xFF7E  /* Alias for mode_switch */
+#endif /* XK_KATAKANA */
+
+/*
+ *  Arabic
+ *  Byte 3 = 5
+ */
+
+#ifdef XK_ARABIC
+#define XK_Arabic_comma                                0x5ac
+#define XK_Arabic_semicolon                            0x5bb
+#define XK_Arabic_question_mark                        0x5bf
+#define XK_Arabic_hamza                                0x5c1
+#define XK_Arabic_maddaonalef                          0x5c2
+#define XK_Arabic_hamzaonalef                          0x5c3
+#define XK_Arabic_hamzaonwaw                           0x5c4
+#define XK_Arabic_hamzaunderalef                       0x5c5
+#define XK_Arabic_hamzaonyeh                           0x5c6
+#define XK_Arabic_alef                                 0x5c7
+#define XK_Arabic_beh                                  0x5c8
+#define XK_Arabic_tehmarbuta                           0x5c9
+#define XK_Arabic_teh                                  0x5ca
+#define XK_Arabic_theh                                 0x5cb
+#define XK_Arabic_jeem                                 0x5cc
+#define XK_Arabic_hah                                  0x5cd
+#define XK_Arabic_khah                                 0x5ce
+#define XK_Arabic_dal                                  0x5cf
+#define XK_Arabic_thal                                 0x5d0
+#define XK_Arabic_ra                                   0x5d1
+#define XK_Arabic_zain                                 0x5d2
+#define XK_Arabic_seen                                 0x5d3
+#define XK_Arabic_sheen                                0x5d4
+#define XK_Arabic_sad                                  0x5d5
+#define XK_Arabic_dad                                  0x5d6
+#define XK_Arabic_tah                                  0x5d7
+#define XK_Arabic_zah                                  0x5d8
+#define XK_Arabic_ain                                  0x5d9
+#define XK_Arabic_ghain                                0x5da
+#define XK_Arabic_tatweel                              0x5e0
+#define XK_Arabic_feh                                  0x5e1
+#define XK_Arabic_qaf                                  0x5e2
+#define XK_Arabic_kaf                                  0x5e3
+#define XK_Arabic_lam                                  0x5e4
+#define XK_Arabic_meem                                 0x5e5
+#define XK_Arabic_noon                                 0x5e6
+#define XK_Arabic_ha                                   0x5e7
+#define XK_Arabic_heh                                  0x5e7  /* deprecated */
+#define XK_Arabic_waw                                  0x5e8
+#define XK_Arabic_alefmaksura                          0x5e9
+#define XK_Arabic_yeh                                  0x5ea
+#define XK_Arabic_fathatan                             0x5eb
+#define XK_Arabic_dammatan                             0x5ec
+#define XK_Arabic_kasratan                             0x5ed
+#define XK_Arabic_fatha                                0x5ee
+#define XK_Arabic_damma                                0x5ef
+#define XK_Arabic_kasra                                0x5f0
+#define XK_Arabic_shadda                               0x5f1
+#define XK_Arabic_sukun                                0x5f2
+#define XK_Arabic_switch        0xFF7E  /* Alias for mode_switch */
+#endif /* XK_ARABIC */
+
+/*
+ * Cyrillic
+ * Byte 3 = 6
+ */
+#ifdef XK_CYRILLIC
+#define XK_Serbian_dje                                 0x6a1
+#define XK_Macedonia_gje                               0x6a2
+#define XK_Cyrillic_io                                 0x6a3
+#define XK_Ukrainian_ie                                0x6a4
+#define XK_Ukranian_je                                 0x6a4  /* deprecated */
+#define XK_Macedonia_dse                               0x6a5
+#define XK_Ukrainian_i                                 0x6a6
+#define XK_Ukranian_i                                  0x6a6  /* deprecated */
+#define XK_Ukrainian_yi                                0x6a7
+#define XK_Ukranian_yi                                 0x6a7  /* deprecated */
+#define XK_Cyrillic_je                                 0x6a8
+#define XK_Serbian_je                                  0x6a8  /* deprecated */
+#define XK_Cyrillic_lje                                0x6a9
+#define XK_Serbian_lje                                 0x6a9  /* deprecated */
+#define XK_Cyrillic_nje                                0x6aa
+#define XK_Serbian_nje                                 0x6aa  /* deprecated */
+#define XK_Serbian_tshe                                0x6ab
+#define XK_Macedonia_kje                               0x6ac
+#define XK_Byelorussian_shortu                         0x6ae
+#define XK_Cyrillic_dzhe                               0x6af
+#define XK_Serbian_dze                                 0x6af  /* deprecated */
+#define XK_numerosign                                  0x6b0
+#define XK_Serbian_DJE                                 0x6b1
+#define XK_Macedonia_GJE                               0x6b2
+#define XK_Cyrillic_IO                                 0x6b3
+#define XK_Ukrainian_IE                                0x6b4
+#define XK_Ukranian_JE                                 0x6b4  /* deprecated */
+#define XK_Macedonia_DSE                               0x6b5
+#define XK_Ukrainian_I                                 0x6b6
+#define XK_Ukranian_I                                  0x6b6  /* deprecated */
+#define XK_Ukrainian_YI                                0x6b7
+#define XK_Ukranian_YI                                 0x6b7  /* deprecated */
+#define XK_Cyrillic_JE                                 0x6b8
+#define XK_Serbian_JE                                  0x6b8  /* deprecated */
+#define XK_Cyrillic_LJE                                0x6b9
+#define XK_Serbian_LJE                                 0x6b9  /* deprecated */
+#define XK_Cyrillic_NJE                                0x6ba
+#define XK_Serbian_NJE                                 0x6ba  /* deprecated */
+#define XK_Serbian_TSHE                                0x6bb
+#define XK_Macedonia_KJE                               0x6bc
+#define XK_Byelorussian_SHORTU                         0x6be
+#define XK_Cyrillic_DZHE                               0x6bf
+#define XK_Serbian_DZE                                 0x6bf  /* deprecated */
+#define XK_Cyrillic_yu                                 0x6c0
+#define XK_Cyrillic_a                                  0x6c1
+#define XK_Cyrillic_be                                 0x6c2
+#define XK_Cyrillic_tse                                0x6c3
+#define XK_Cyrillic_de                                 0x6c4
+#define XK_Cyrillic_ie                                 0x6c5
+#define XK_Cyrillic_ef                                 0x6c6
+#define XK_Cyrillic_ghe                                0x6c7
+#define XK_Cyrillic_ha                                 0x6c8
+#define XK_Cyrillic_i                                  0x6c9
+#define XK_Cyrillic_shorti                             0x6ca
+#define XK_Cyrillic_ka                                 0x6cb
+#define XK_Cyrillic_el                                 0x6cc
+#define XK_Cyrillic_em                                 0x6cd
+#define XK_Cyrillic_en                                 0x6ce
+#define XK_Cyrillic_o                                  0x6cf
+#define XK_Cyrillic_pe                                 0x6d0
+#define XK_Cyrillic_ya                                 0x6d1
+#define XK_Cyrillic_er                                 0x6d2
+#define XK_Cyrillic_es                                 0x6d3
+#define XK_Cyrillic_te                                 0x6d4
+#define XK_Cyrillic_u                                  0x6d5
+#define XK_Cyrillic_zhe                                0x6d6
+#define XK_Cyrillic_ve                                 0x6d7
+#define XK_Cyrillic_softsign                           0x6d8
+#define XK_Cyrillic_yeru                               0x6d9
+#define XK_Cyrillic_ze                                 0x6da
+#define XK_Cyrillic_sha                                0x6db
+#define XK_Cyrillic_e                                  0x6dc
+#define XK_Cyrillic_shcha                              0x6dd
+#define XK_Cyrillic_che                                0x6de
+#define XK_Cyrillic_hardsign                           0x6df
+#define XK_Cyrillic_YU                                 0x6e0
+#define XK_Cyrillic_A                                  0x6e1
+#define XK_Cyrillic_BE                                 0x6e2
+#define XK_Cyrillic_TSE                                0x6e3
+#define XK_Cyrillic_DE                                 0x6e4
+#define XK_Cyrillic_IE                                 0x6e5
+#define XK_Cyrillic_EF                                 0x6e6
+#define XK_Cyrillic_GHE                                0x6e7
+#define XK_Cyrillic_HA                                 0x6e8
+#define XK_Cyrillic_I                                  0x6e9
+#define XK_Cyrillic_SHORTI                             0x6ea
+#define XK_Cyrillic_KA                                 0x6eb
+#define XK_Cyrillic_EL                                 0x6ec
+#define XK_Cyrillic_EM                                 0x6ed
+#define XK_Cyrillic_EN                                 0x6ee
+#define XK_Cyrillic_O                                  0x6ef
+#define XK_Cyrillic_PE                                 0x6f0
+#define XK_Cyrillic_YA                                 0x6f1
+#define XK_Cyrillic_ER                                 0x6f2
+#define XK_Cyrillic_ES                                 0x6f3
+#define XK_Cyrillic_TE                                 0x6f4
+#define XK_Cyrillic_U                                  0x6f5
+#define XK_Cyrillic_ZHE                                0x6f6
+#define XK_Cyrillic_VE                                 0x6f7
+#define XK_Cyrillic_SOFTSIGN                           0x6f8
+#define XK_Cyrillic_YERU                               0x6f9
+#define XK_Cyrillic_ZE                                 0x6fa
+#define XK_Cyrillic_SHA                                0x6fb
+#define XK_Cyrillic_E                                  0x6fc
+#define XK_Cyrillic_SHCHA                              0x6fd
+#define XK_Cyrillic_CHE                                0x6fe
+#define XK_Cyrillic_HARDSIGN                           0x6ff
+#endif /* XK_CYRILLIC */
+
+/*
+ * Greek
+ * Byte 3 = 7
+ */
+
+#ifdef XK_GREEK
+#define XK_Greek_ALPHAaccent                           0x7a1
+#define XK_Greek_EPSILONaccent                         0x7a2
+#define XK_Greek_ETAaccent                             0x7a3
+#define XK_Greek_IOTAaccent                            0x7a4
+#define XK_Greek_IOTAdiaeresis                         0x7a5
+#define XK_Greek_OMICRONaccent                         0x7a7
+#define XK_Greek_UPSILONaccent                         0x7a8
+#define XK_Greek_UPSILONdieresis                       0x7a9
+#define XK_Greek_OMEGAaccent                           0x7ab
+#define XK_Greek_accentdieresis                        0x7ae
+#define XK_Greek_horizbar                              0x7af
+#define XK_Greek_alphaaccent                           0x7b1
+#define XK_Greek_epsilonaccent                         0x7b2
+#define XK_Greek_etaaccent                             0x7b3
+#define XK_Greek_iotaaccent                            0x7b4
+#define XK_Greek_iotadieresis                          0x7b5
+#define XK_Greek_iotaaccentdieresis                    0x7b6
+#define XK_Greek_omicronaccent                         0x7b7
+#define XK_Greek_upsilonaccent                         0x7b8
+#define XK_Greek_upsilondieresis                       0x7b9
+#define XK_Greek_upsilonaccentdieresis                 0x7ba
+#define XK_Greek_omegaaccent                           0x7bb
+#define XK_Greek_ALPHA                                 0x7c1
+#define XK_Greek_BETA                                  0x7c2
+#define XK_Greek_GAMMA                                 0x7c3
+#define XK_Greek_DELTA                                 0x7c4
+#define XK_Greek_EPSILON                               0x7c5
+#define XK_Greek_ZETA                                  0x7c6
+#define XK_Greek_ETA                                   0x7c7
+#define XK_Greek_THETA                                 0x7c8
+#define XK_Greek_IOTA                                  0x7c9
+#define XK_Greek_KAPPA                                 0x7ca
+#define XK_Greek_LAMDA                                 0x7cb
+#define XK_Greek_LAMBDA                                0x7cb
+#define XK_Greek_MU                                    0x7cc
+#define XK_Greek_NU                                    0x7cd
+#define XK_Greek_XI                                    0x7ce
+#define XK_Greek_OMICRON                               0x7cf
+#define XK_Greek_PI                                    0x7d0
+#define XK_Greek_RHO                                   0x7d1
+#define XK_Greek_SIGMA                                 0x7d2
+#define XK_Greek_TAU                                   0x7d4
+#define XK_Greek_UPSILON                               0x7d5
+#define XK_Greek_PHI                                   0x7d6
+#define XK_Greek_CHI                                   0x7d7
+#define XK_Greek_PSI                                   0x7d8
+#define XK_Greek_OMEGA                                 0x7d9
+#define XK_Greek_alpha                                 0x7e1
+#define XK_Greek_beta                                  0x7e2
+#define XK_Greek_gamma                                 0x7e3
+#define XK_Greek_delta                                 0x7e4
+#define XK_Greek_epsilon                               0x7e5
+#define XK_Greek_zeta                                  0x7e6
+#define XK_Greek_eta                                   0x7e7
+#define XK_Greek_theta                                 0x7e8
+#define XK_Greek_iota                                  0x7e9
+#define XK_Greek_kappa                                 0x7ea
+#define XK_Greek_lamda                                 0x7eb
+#define XK_Greek_lambda                                0x7eb
+#define XK_Greek_mu                                    0x7ec
+#define XK_Greek_nu                                    0x7ed
+#define XK_Greek_xi                                    0x7ee
+#define XK_Greek_omicron                               0x7ef
+#define XK_Greek_pi                                    0x7f0
+#define XK_Greek_rho                                   0x7f1
+#define XK_Greek_sigma                                 0x7f2
+#define XK_Greek_finalsmallsigma                       0x7f3
+#define XK_Greek_tau                                   0x7f4
+#define XK_Greek_upsilon                               0x7f5
+#define XK_Greek_phi                                   0x7f6
+#define XK_Greek_chi                                   0x7f7
+#define XK_Greek_psi                                   0x7f8
+#define XK_Greek_omega                                 0x7f9
+#define XK_Greek_switch         0xFF7E  /* Alias for mode_switch */
+#endif /* XK_GREEK */
+
+/*
+ * Technical
+ * Byte 3 = 8
+ */
+
+#ifdef XK_TECHNICAL
+#define XK_leftradical                                 0x8a1
+#define XK_topleftradical                              0x8a2
+#define XK_horizconnector                              0x8a3
+#define XK_topintegral                                 0x8a4
+#define XK_botintegral                                 0x8a5
+#define XK_vertconnector                               0x8a6
+#define XK_topleftsqbracket                            0x8a7
+#define XK_botleftsqbracket                            0x8a8
+#define XK_toprightsqbracket                           0x8a9
+#define XK_botrightsqbracket                           0x8aa
+#define XK_topleftparens                               0x8ab
+#define XK_botleftparens                               0x8ac
+#define XK_toprightparens                              0x8ad
+#define XK_botrightparens                              0x8ae
+#define XK_leftmiddlecurlybrace                        0x8af
+#define XK_rightmiddlecurlybrace                       0x8b0
+#define XK_topleftsummation                            0x8b1
+#define XK_botleftsummation                            0x8b2
+#define XK_topvertsummationconnector                   0x8b3
+#define XK_botvertsummationconnector                   0x8b4
+#define XK_toprightsummation                           0x8b5
+#define XK_botrightsummation                           0x8b6
+#define XK_rightmiddlesummation                        0x8b7
+#define XK_lessthanequal                               0x8bc
+#define XK_notequal                                    0x8bd
+#define XK_greaterthanequal                            0x8be
+#define XK_integral                                    0x8bf
+#define XK_therefore                                   0x8c0
+#define XK_variation                                   0x8c1
+#define XK_infinity                                    0x8c2
+#define XK_nabla                                       0x8c5
+#define XK_approximate                                 0x8c8
+#define XK_similarequal                                0x8c9
+#define XK_ifonlyif                                    0x8cd
+#define XK_implies                                     0x8ce
+#define XK_identical                                   0x8cf
+#define XK_radical                                     0x8d6
+#define XK_includedin                                  0x8da
+#define XK_includes                                    0x8db
+#define XK_intersection                                0x8dc
+#define XK_union                                       0x8dd
+#define XK_logicaland                                  0x8de
+#define XK_logicalor                                   0x8df
+#define XK_partialderivative                           0x8ef
+#define XK_function                                    0x8f6
+#define XK_leftarrow                                   0x8fb
+#define XK_uparrow                                     0x8fc
+#define XK_rightarrow                                  0x8fd
+#define XK_downarrow                                   0x8fe
+#endif /* XK_TECHNICAL */
+
+/*
+ *  Special
+ *  Byte 3 = 9
+ */
+
+#ifdef XK_SPECIAL
+#define XK_blank                                       0x9df
+#define XK_soliddiamond                                0x9e0
+#define XK_checkerboard                                0x9e1
+#define XK_ht                                          0x9e2
+#define XK_ff                                          0x9e3
+#define XK_cr                                          0x9e4
+#define XK_lf                                          0x9e5
+#define XK_nl                                          0x9e8
+#define XK_vt                                          0x9e9
+#define XK_lowrightcorner                              0x9ea
+#define XK_uprightcorner                               0x9eb
+#define XK_upleftcorner                                0x9ec
+#define XK_lowleftcorner                               0x9ed
+#define XK_crossinglines                               0x9ee
+#define XK_horizlinescan1                              0x9ef
+#define XK_horizlinescan3                              0x9f0
+#define XK_horizlinescan5                              0x9f1
+#define XK_horizlinescan7                              0x9f2
+#define XK_horizlinescan9                              0x9f3
+#define XK_leftt                                       0x9f4
+#define XK_rightt                                      0x9f5
+#define XK_bott                                        0x9f6
+#define XK_topt                                        0x9f7
+#define XK_vertbar                                     0x9f8
+#endif /* XK_SPECIAL */
+
+/*
+ *  Publishing
+ *  Byte 3 = a
+ */
+
+#ifdef XK_PUBLISHING
+#define XK_emspace                                     0xaa1
+#define XK_enspace                                     0xaa2
+#define XK_em3space                                    0xaa3
+#define XK_em4space                                    0xaa4
+#define XK_digitspace                                  0xaa5
+#define XK_punctspace                                  0xaa6
+#define XK_thinspace                                   0xaa7
+#define XK_hairspace                                   0xaa8
+#define XK_emdash                                      0xaa9
+#define XK_endash                                      0xaaa
+#define XK_signifblank                                 0xaac
+#define XK_ellipsis                                    0xaae
+#define XK_doubbaselinedot                             0xaaf
+#define XK_onethird                                    0xab0
+#define XK_twothirds                                   0xab1
+#define XK_onefifth                                    0xab2
+#define XK_twofifths                                   0xab3
+#define XK_threefifths                                 0xab4
+#define XK_fourfifths                                  0xab5
+#define XK_onesixth                                    0xab6
+#define XK_fivesixths                                  0xab7
+#define XK_careof                                      0xab8
+#define XK_figdash                                     0xabb
+#define XK_leftanglebracket                            0xabc
+#define XK_decimalpoint                                0xabd
+#define XK_rightanglebracket                           0xabe
+#define XK_marker                                      0xabf
+#define XK_oneeighth                                   0xac3
+#define XK_threeeighths                                0xac4
+#define XK_fiveeighths                                 0xac5
+#define XK_seveneighths                                0xac6
+#define XK_trademark                                   0xac9
+#define XK_signaturemark                               0xaca
+#define XK_trademarkincircle                           0xacb
+#define XK_leftopentriangle                            0xacc
+#define XK_rightopentriangle                           0xacd
+#define XK_emopencircle                                0xace
+#define XK_emopenrectangle                             0xacf
+#define XK_leftsinglequotemark                         0xad0
+#define XK_rightsinglequotemark                        0xad1
+#define XK_leftdoublequotemark                         0xad2
+#define XK_rightdoublequotemark                        0xad3
+#define XK_prescription                                0xad4
+#define XK_minutes                                     0xad6
+#define XK_seconds                                     0xad7
+#define XK_latincross                                  0xad9
+#define XK_hexagram                                    0xada
+#define XK_filledrectbullet                            0xadb
+#define XK_filledlefttribullet                         0xadc
+#define XK_filledrighttribullet                        0xadd
+#define XK_emfilledcircle                              0xade
+#define XK_emfilledrect                                0xadf
+#define XK_enopencircbullet                            0xae0
+#define XK_enopensquarebullet                          0xae1
+#define XK_openrectbullet                              0xae2
+#define XK_opentribulletup                             0xae3
+#define XK_opentribulletdown                           0xae4
+#define XK_openstar                                    0xae5
+#define XK_enfilledcircbullet                          0xae6
+#define XK_enfilledsqbullet                            0xae7
+#define XK_filledtribulletup                           0xae8
+#define XK_filledtribulletdown                         0xae9
+#define XK_leftpointer                                 0xaea
+#define XK_rightpointer                                0xaeb
+#define XK_club                                        0xaec
+#define XK_diamond                                     0xaed
+#define XK_heart                                       0xaee
+#define XK_maltesecross                                0xaf0
+#define XK_dagger                                      0xaf1
+#define XK_doubledagger                                0xaf2
+#define XK_checkmark                                   0xaf3
+#define XK_ballotcross                                 0xaf4
+#define XK_musicalsharp                                0xaf5
+#define XK_musicalflat                                 0xaf6
+#define XK_malesymbol                                  0xaf7
+#define XK_femalesymbol                                0xaf8
+#define XK_telephone                                   0xaf9
+#define XK_telephonerecorder                           0xafa
+#define XK_phonographcopyright                         0xafb
+#define XK_caret                                       0xafc
+#define XK_singlelowquotemark                          0xafd
+#define XK_doublelowquotemark                          0xafe
+#define XK_cursor                                      0xaff
+#endif /* XK_PUBLISHING */
+
+/*
+ *  APL
+ *  Byte 3 = b
+ */
+
+#ifdef XK_APL
+#define XK_leftcaret                                   0xba3
+#define XK_rightcaret                                  0xba6
+#define XK_downcaret                                   0xba8
+#define XK_upcaret                                     0xba9
+#define XK_overbar                                     0xbc0
+#define XK_downtack                                    0xbc2
+#define XK_upshoe                                      0xbc3
+#define XK_downstile                                   0xbc4
+#define XK_underbar                                    0xbc6
+#define XK_jot                                         0xbca
+#define XK_quad                                        0xbcc
+#define XK_uptack                                      0xbce
+#define XK_circle                                      0xbcf
+#define XK_upstile                                     0xbd3
+#define XK_downshoe                                    0xbd6
+#define XK_rightshoe                                   0xbd8
+#define XK_leftshoe                                    0xbda
+#define XK_lefttack                                    0xbdc
+#define XK_righttack                                   0xbfc
+#endif /* XK_APL */
+
+/*
+ * Hebrew
+ * Byte 3 = c
+ */
+
+#ifdef XK_HEBREW
+#define XK_hebrew_doublelowline                        0xcdf
+#define XK_hebrew_aleph                                0xce0
+#define XK_hebrew_bet                                  0xce1
+#define XK_hebrew_beth                                 0xce1  /* deprecated */
+#define XK_hebrew_gimel                                0xce2
+#define XK_hebrew_gimmel                               0xce2  /* deprecated */
+#define XK_hebrew_dalet                                0xce3
+#define XK_hebrew_daleth                               0xce3  /* deprecated */
+#define XK_hebrew_he                                   0xce4
+#define XK_hebrew_waw                                  0xce5
+#define XK_hebrew_zain                                 0xce6
+#define XK_hebrew_zayin                                0xce6  /* deprecated */
+#define XK_hebrew_chet                                 0xce7
+#define XK_hebrew_het                                  0xce7  /* deprecated */
+#define XK_hebrew_tet                                  0xce8
+#define XK_hebrew_teth                                 0xce8  /* deprecated */
+#define XK_hebrew_yod                                  0xce9
+#define XK_hebrew_finalkaph                            0xcea
+#define XK_hebrew_kaph                                 0xceb
+#define XK_hebrew_lamed                                0xcec
+#define XK_hebrew_finalmem                             0xced
+#define XK_hebrew_mem                                  0xcee
+#define XK_hebrew_finalnun                             0xcef
+#define XK_hebrew_nun                                  0xcf0
+#define XK_hebrew_samech                               0xcf1
+#define XK_hebrew_samekh                               0xcf1  /* deprecated */
+#define XK_hebrew_ayin                                 0xcf2
+#define XK_hebrew_finalpe                              0xcf3
+#define XK_hebrew_pe                                   0xcf4
+#define XK_hebrew_finalzade                            0xcf5
+#define XK_hebrew_finalzadi                            0xcf5  /* deprecated */
+#define XK_hebrew_zade                                 0xcf6
+#define XK_hebrew_zadi                                 0xcf6  /* deprecated */
+#define XK_hebrew_qoph                                 0xcf7
+#define XK_hebrew_kuf                                  0xcf7  /* deprecated */
+#define XK_hebrew_resh                                 0xcf8
+#define XK_hebrew_shin                                 0xcf9
+#define XK_hebrew_taw                                  0xcfa
+#define XK_hebrew_taf                                  0xcfa  /* deprecated */
+#define XK_Hebrew_switch        0xFF7E  /* Alias for mode_switch */
+#endif /* XK_HEBREW */
+
+/*
+ * Thai
+ * Byte 3 = d
+ */
+
+#ifdef XK_THAI
+#define XK_Thai_kokai					0xda1
+#define XK_Thai_khokhai					0xda2
+#define XK_Thai_khokhuat				0xda3
+#define XK_Thai_khokhwai				0xda4
+#define XK_Thai_khokhon					0xda5
+#define XK_Thai_khorakhang			        0xda6  
+#define XK_Thai_ngongu					0xda7  
+#define XK_Thai_chochan					0xda8  
+#define XK_Thai_choching				0xda9   
+#define XK_Thai_chochang				0xdaa  
+#define XK_Thai_soso					0xdab
+#define XK_Thai_chochoe					0xdac
+#define XK_Thai_yoying					0xdad
+#define XK_Thai_dochada					0xdae
+#define XK_Thai_topatak					0xdaf
+#define XK_Thai_thothan					0xdb0
+#define XK_Thai_thonangmontho			        0xdb1
+#define XK_Thai_thophuthao			        0xdb2
+#define XK_Thai_nonen					0xdb3
+#define XK_Thai_dodek					0xdb4
+#define XK_Thai_totao					0xdb5
+#define XK_Thai_thothung				0xdb6
+#define XK_Thai_thothahan				0xdb7
+#define XK_Thai_thothong	 			0xdb8
+#define XK_Thai_nonu					0xdb9
+#define XK_Thai_bobaimai				0xdba
+#define XK_Thai_popla					0xdbb
+#define XK_Thai_phophung				0xdbc
+#define XK_Thai_fofa					0xdbd
+#define XK_Thai_phophan					0xdbe
+#define XK_Thai_fofan					0xdbf
+#define XK_Thai_phosamphao			        0xdc0
+#define XK_Thai_moma					0xdc1
+#define XK_Thai_yoyak					0xdc2
+#define XK_Thai_rorua					0xdc3
+#define XK_Thai_ru					0xdc4
+#define XK_Thai_loling					0xdc5
+#define XK_Thai_lu					0xdc6
+#define XK_Thai_wowaen					0xdc7
+#define XK_Thai_sosala					0xdc8
+#define XK_Thai_sorusi					0xdc9
+#define XK_Thai_sosua					0xdca
+#define XK_Thai_hohip					0xdcb
+#define XK_Thai_lochula					0xdcc
+#define XK_Thai_oang					0xdcd
+#define XK_Thai_honokhuk				0xdce
+#define XK_Thai_paiyannoi				0xdcf
+#define XK_Thai_saraa					0xdd0
+#define XK_Thai_maihanakat				0xdd1
+#define XK_Thai_saraaa					0xdd2
+#define XK_Thai_saraam					0xdd3
+#define XK_Thai_sarai					0xdd4   
+#define XK_Thai_saraii					0xdd5   
+#define XK_Thai_saraue					0xdd6    
+#define XK_Thai_sarauee					0xdd7    
+#define XK_Thai_sarau					0xdd8    
+#define XK_Thai_sarauu					0xdd9   
+#define XK_Thai_phinthu					0xdda
+#define XK_Thai_maihanakat_maitho   			0xdde
+#define XK_Thai_baht					0xddf
+#define XK_Thai_sarae					0xde0    
+#define XK_Thai_saraae					0xde1
+#define XK_Thai_sarao					0xde2
+#define XK_Thai_saraaimaimuan				0xde3   
+#define XK_Thai_saraaimaimalai				0xde4  
+#define XK_Thai_lakkhangyao				0xde5
+#define XK_Thai_maiyamok				0xde6
+#define XK_Thai_maitaikhu				0xde7
+#define XK_Thai_maiek					0xde8   
+#define XK_Thai_maitho					0xde9
+#define XK_Thai_maitri					0xdea
+#define XK_Thai_maichattawa				0xdeb
+#define XK_Thai_thanthakhat				0xdec
+#define XK_Thai_nikhahit				0xded
+#define XK_Thai_leksun					0xdf0 
+#define XK_Thai_leknung					0xdf1  
+#define XK_Thai_leksong					0xdf2 
+#define XK_Thai_leksam					0xdf3
+#define XK_Thai_leksi					0xdf4  
+#define XK_Thai_lekha					0xdf5  
+#define XK_Thai_lekhok					0xdf6  
+#define XK_Thai_lekchet					0xdf7  
+#define XK_Thai_lekpaet					0xdf8  
+#define XK_Thai_lekkao					0xdf9 
+#endif /* XK_THAI */
+
+/*
+ *   Korean
+ *   Byte 3 = e
+ */
+
+#ifdef XK_KOREAN
+
+#define XK_Hangul		0xff31    /* Hangul start/stop(toggle) */
+#define XK_Hangul_Start		0xff32    /* Hangul start */
+#define XK_Hangul_End		0xff33    /* Hangul end, English start */
+#define XK_Hangul_Hanja		0xff34    /* Start Hangul->Hanja Conversion */
+#define XK_Hangul_Jamo		0xff35    /* Hangul Jamo mode */
+#define XK_Hangul_Romaja	0xff36    /* Hangul Romaja mode */
+#define XK_Hangul_Codeinput	0xff37    /* Hangul code input mode */
+#define XK_Hangul_Jeonja	0xff38    /* Jeonja mode */
+#define XK_Hangul_Banja		0xff39    /* Banja mode */
+#define XK_Hangul_PreHanja	0xff3a    /* Pre Hanja conversion */
+#define XK_Hangul_PostHanja	0xff3b    /* Post Hanja conversion */
+#define XK_Hangul_SingleCandidate	0xff3c    /* Single candidate */
+#define XK_Hangul_MultipleCandidate	0xff3d    /* Multiple candidate */
+#define XK_Hangul_PreviousCandidate	0xff3e    /* Previous candidate */
+#define XK_Hangul_Special	0xff3f    /* Special symbols */
+#define XK_Hangul_switch	0xFF7E    /* Alias for mode_switch */
+
+/* Hangul Consonant Characters */
+#define XK_Hangul_Kiyeog				0xea1
+#define XK_Hangul_SsangKiyeog				0xea2
+#define XK_Hangul_KiyeogSios				0xea3
+#define XK_Hangul_Nieun					0xea4
+#define XK_Hangul_NieunJieuj				0xea5
+#define XK_Hangul_NieunHieuh				0xea6
+#define XK_Hangul_Dikeud				0xea7
+#define XK_Hangul_SsangDikeud				0xea8
+#define XK_Hangul_Rieul					0xea9
+#define XK_Hangul_RieulKiyeog				0xeaa
+#define XK_Hangul_RieulMieum				0xeab
+#define XK_Hangul_RieulPieub				0xeac
+#define XK_Hangul_RieulSios				0xead
+#define XK_Hangul_RieulTieut				0xeae
+#define XK_Hangul_RieulPhieuf				0xeaf
+#define XK_Hangul_RieulHieuh				0xeb0
+#define XK_Hangul_Mieum					0xeb1
+#define XK_Hangul_Pieub					0xeb2
+#define XK_Hangul_SsangPieub				0xeb3
+#define XK_Hangul_PieubSios				0xeb4
+#define XK_Hangul_Sios					0xeb5
+#define XK_Hangul_SsangSios				0xeb6
+#define XK_Hangul_Ieung					0xeb7
+#define XK_Hangul_Jieuj					0xeb8
+#define XK_Hangul_SsangJieuj				0xeb9
+#define XK_Hangul_Cieuc					0xeba
+#define XK_Hangul_Khieuq				0xebb
+#define XK_Hangul_Tieut					0xebc
+#define XK_Hangul_Phieuf				0xebd
+#define XK_Hangul_Hieuh					0xebe
+
+/* Hangul Vowel Characters */
+#define XK_Hangul_A					0xebf
+#define XK_Hangul_AE					0xec0
+#define XK_Hangul_YA					0xec1
+#define XK_Hangul_YAE					0xec2
+#define XK_Hangul_EO					0xec3
+#define XK_Hangul_E					0xec4
+#define XK_Hangul_YEO					0xec5
+#define XK_Hangul_YE					0xec6
+#define XK_Hangul_O					0xec7
+#define XK_Hangul_WA					0xec8
+#define XK_Hangul_WAE					0xec9
+#define XK_Hangul_OE					0xeca
+#define XK_Hangul_YO					0xecb
+#define XK_Hangul_U					0xecc
+#define XK_Hangul_WEO					0xecd
+#define XK_Hangul_WE					0xece
+#define XK_Hangul_WI					0xecf
+#define XK_Hangul_YU					0xed0
+#define XK_Hangul_EU					0xed1
+#define XK_Hangul_YI					0xed2
+#define XK_Hangul_I					0xed3
+
+/* Hangul syllable-final (JongSeong) Characters */
+#define XK_Hangul_J_Kiyeog				0xed4
+#define XK_Hangul_J_SsangKiyeog				0xed5
+#define XK_Hangul_J_KiyeogSios				0xed6
+#define XK_Hangul_J_Nieun				0xed7
+#define XK_Hangul_J_NieunJieuj				0xed8
+#define XK_Hangul_J_NieunHieuh				0xed9
+#define XK_Hangul_J_Dikeud				0xeda
+#define XK_Hangul_J_Rieul				0xedb
+#define XK_Hangul_J_RieulKiyeog				0xedc
+#define XK_Hangul_J_RieulMieum				0xedd
+#define XK_Hangul_J_RieulPieub				0xede
+#define XK_Hangul_J_RieulSios				0xedf
+#define XK_Hangul_J_RieulTieut				0xee0
+#define XK_Hangul_J_RieulPhieuf				0xee1
+#define XK_Hangul_J_RieulHieuh				0xee2
+#define XK_Hangul_J_Mieum				0xee3
+#define XK_Hangul_J_Pieub				0xee4
+#define XK_Hangul_J_PieubSios				0xee5
+#define XK_Hangul_J_Sios				0xee6
+#define XK_Hangul_J_SsangSios				0xee7
+#define XK_Hangul_J_Ieung				0xee8
+#define XK_Hangul_J_Jieuj				0xee9
+#define XK_Hangul_J_Cieuc				0xeea
+#define XK_Hangul_J_Khieuq				0xeeb
+#define XK_Hangul_J_Tieut				0xeec
+#define XK_Hangul_J_Phieuf				0xeed
+#define XK_Hangul_J_Hieuh				0xeee
+
+/* Ancient Hangul Consonant Characters */
+#define XK_Hangul_RieulYeorinHieuh			0xeef
+#define XK_Hangul_SunkyeongeumMieum			0xef0
+#define XK_Hangul_SunkyeongeumPieub			0xef1
+#define XK_Hangul_PanSios				0xef2
+#define XK_Hangul_KkogjiDalrinIeung			0xef3
+#define XK_Hangul_SunkyeongeumPhieuf			0xef4
+#define XK_Hangul_YeorinHieuh				0xef5
+
+/* Ancient Hangul Vowel Characters */
+#define XK_Hangul_AraeA					0xef6
+#define XK_Hangul_AraeAE				0xef7
+
+/* Ancient Hangul syllable-final (JongSeong) Characters */
+#define XK_Hangul_J_PanSios				0xef8
+#define XK_Hangul_J_KkogjiDalrinIeung			0xef9
+#define XK_Hangul_J_YeorinHieuh				0xefa
+
+/* Korean currency symbol */
+#define XK_Korean_Won					0xeff
+
+#endif /* XK_KOREAN */
+
+#ifdef XK_CURRENCY
+#define XK_EcuSign					0x20a0
+#define XK_ColonSign					0x20a1
+#define XK_CruzeiroSign					0x20a2
+#define XK_FFrancSign					0x20a3
+#define XK_LiraSign					0x20a4
+#define XK_MillSign					0x20a5
+#define XK_NairaSign					0x20a6
+#define XK_PesetaSign					0x20a7
+#define XK_RupeeSign					0x20a8
+#define XK_WonSign					0x20a9
+#define XK_NewSheqelSign				0x20aa
+#define XK_DongSign					0x20ab
+#define XK_EuroSign					0x20ac
+#endif
diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h
new file mode 100644
index 0000000..f6f8d5c
--- /dev/null
+++ b/common/rfb/msgTypes.h
@@ -0,0 +1,57 @@
+/* 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_MSGTYPES_H__
+#define __RFB_MSGTYPES_H__
+
+namespace rfb {
+  // server to client
+
+  const int msgTypeFramebufferUpdate = 0;
+  const int msgTypeSetColourMapEntries = 1;
+  const int msgTypeBell = 2;
+  const int msgTypeServerCutText = 3;
+
+  const int msgTypeFileListData = 130;
+  const int msgTypeFileDownloadData = 131;
+  const int msgTypeFileUploadCancel = 132;
+  const int msgTypeFileDownloadFailed = 133;
+  const int msgTypeFileDirSizeData = 134;
+  const int msgTypeFileLastRequestFailed = 135;
+
+  // client to server
+
+  const int msgTypeSetPixelFormat = 0;
+  const int msgTypeFixColourMapEntries = 1;
+  const int msgTypeSetEncodings = 2;
+  const int msgTypeFramebufferUpdateRequest = 3;
+  const int msgTypeKeyEvent = 4;
+  const int msgTypePointerEvent = 5;
+  const int msgTypeClientCutText = 6;
+
+  const int msgTypeFileListRequest = 130;
+  const int msgTypeFileDownloadRequest = 131;
+  const int msgTypeFileUploadRequest = 132;
+  const int msgTypeFileUploadData = 133;
+  const int msgTypeFileDownloadCancel = 134;
+  const int msgTypeFileUploadFailed = 135;
+  const int msgTypeFileCreateDirRequest = 136;
+  const int msgTypeFileDirSizeRequest = 137;
+  const int	msgTypeFileRenameRequest = 138;
+  const int msgTypeFileDeleteRequest = 139;
+}
+#endif
diff --git a/common/rfb/rfb.dsp b/common/rfb/rfb.dsp
new file mode 100644
index 0000000..aef5e43
--- /dev/null
+++ b/common/rfb/rfb.dsp
@@ -0,0 +1,767 @@
+# Microsoft Developer Studio Project File - Name="rfb" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Static Library" 0x0104

+

+CFG=rfb - Win32 Debug Unicode

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "rfb.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "rfb.mak" CFG="rfb - Win32 Debug Unicode"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "rfb - Win32 Release" (based on "Win32 (x86) Static Library")

+!MESSAGE "rfb - Win32 Debug" (based on "Win32 (x86) Static Library")

+!MESSAGE "rfb - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+CPP=cl.exe

+RSC=rc.exe

+

+!IF  "$(CFG)" == "rfb - Win32 Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "Release"

+# PROP BASE Intermediate_Dir "Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "..\Release"

+# PROP Intermediate_Dir "..\Release\rfb"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c

+# ADD CPP /nologo /MT /W3 /GX /O1 /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c

+# ADD BASE RSC /l 0x809 /d "NDEBUG"

+# ADD RSC /l 0x809 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ELSEIF  "$(CFG)" == "rfb - Win32 Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "Debug"

+# PROP BASE Intermediate_Dir "Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug"

+# PROP Intermediate_Dir "..\Debug\rfb"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c

+# ADD BASE RSC /l 0x809 /d "_DEBUG"

+# ADD RSC /l 0x809 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ELSEIF  "$(CFG)" == "rfb - Win32 Debug Unicode"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "rfb___Win32_Debug_Unicode"

+# PROP BASE Intermediate_Dir "rfb___Win32_Debug_Unicode"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "..\Debug_Unicode"

+# PROP Intermediate_Dir "..\Debug_Unicode\rfb"

+# PROP Target_Dir ""

+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /I "../../win" /FI"rdr/msvcwarning.h" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c

+# ADD BASE RSC /l 0x809 /d "_DEBUG"

+# ADD RSC /l 0x809 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo

+# ADD LIB32 /nologo

+

+!ENDIF 

+

+# Begin Target

+

+# Name "rfb - Win32 Release"

+# Name "rfb - Win32 Debug"

+# Name "rfb - Win32 Debug Unicode"

+# Begin Group "Source Files"

+

+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"

+# Begin Source File

+

+SOURCE=.\Blacklist.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnection.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CFTMsgReader.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CFTMsgWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgHandler.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgReader.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgReaderV3.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgWriterV3.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ComparingUpdateTracker.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Configuration.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnParams.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\CSecurityVncAuth.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Cursor.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\d3des.c

+# End Source File

+# Begin Source File

+

+SOURCE=.\Decoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Encoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\encodings.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileInfo.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileManager.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileReader.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\HextileDecoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\HextileEncoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\HTTPServer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\KeyRemapper.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger_file.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger_stdio.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\LogWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Password.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelBuffer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelFormat.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\RawDecoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\RawEncoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\Region.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\RREDecoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\RREEncoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ScaledPixelBuffer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SConnection.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\secTypes.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ServerCore.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFileTransfer.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFileTransferManager.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFTMsgReader.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFTMsgWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgHandler.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgReader.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgReaderV3.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgWriter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgWriterV3.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurityFactoryStandard.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurityVncAuth.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightDecoder.cxx

+# ADD CPP /I "../jpeg"

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightEncoder.cxx

+# ADD CPP /I "../jpeg"

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightPalette.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\TransferQueue.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\TransImageGetter.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\UpdateTracker.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\util.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\VNCSConnectionST.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\VNCServerST.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZRLEDecoder.cxx

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZRLEEncoder.cxx

+# End Source File

+# End Group

+# Begin Group "Header Files"

+

+# PROP Default_Filter "h;hpp;hxx;hm;inl"

+# Begin Source File

+

+SOURCE=.\Blacklist.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CConnection.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CFTMsgReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CFTMsgWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgHandler.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgReaderV3.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CMsgWriterV3.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ColourCube.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ColourMap.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ComparingUpdateTracker.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Configuration.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ConnParams.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CSecurity.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CSecurityNone.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\CSecurityVncAuth.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Cursor.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\d3des.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Decoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\DirManager.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Encoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\encodings.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Exception.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileInfo.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileManager.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\FileWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\hextileConstants.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\hextileDecode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\HextileDecoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\hextileEncode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\hextileEncodeBetter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\HextileEncoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Hostname.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\HTTPServer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ImageGetter.h

+# 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

+

+SOURCE=.\ListConnInfo.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger_file.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Logger_stdio.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\LogWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\msgTypes.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\msvcwarning.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Password.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Pixel.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelBuffer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\PixelFormat.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RawDecoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RawEncoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Rect.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Region.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\rreDecode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RREDecoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\rreEncode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\RREEncoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ScaledPixelBuffer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SConnection.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SDesktop.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\secTypes.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ServerCore.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFileTransfer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFileTransferManager.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFTMsgReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SFTMsgWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgHandler.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgReader.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgReaderV3.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgWriter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SMsgWriterV3.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurity.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurityFactoryStandard.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurityNone.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\SSecurityVncAuth.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\Threading.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\tightDecode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightDecoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\tightEncode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightEncoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TightPalette.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TransferQueue.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TransImageGetter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\transInitTempl.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\transTempl.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\TrueColourMap.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\UpdateTracker.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\UserPasswdGetter.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\util.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\VNCSConnectionST.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\VNCServer.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\VNCServerST.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\zrleDecode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZRLEDecoder.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\zrleEncode.h

+# End Source File

+# Begin Source File

+

+SOURCE=.\ZRLEEncoder.h

+# End Source File

+# End Group

+# End Target

+# End Project

diff --git a/common/rfb/rreDecode.h b/common/rfb/rreDecode.h
new file mode 100644
index 0000000..1f5bdf8
--- /dev/null
+++ b/common/rfb/rreDecode.h
@@ -0,0 +1,64 @@
+/* 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.
+ */
+//
+// RRE decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// FILL_RECT          - fill a rectangle with a single colour
+
+#include <rdr/InStream.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define RRE_DECODE CONCAT2E(rreDecode,BPP)
+
+void RRE_DECODE (const Rect& r, rdr::InStream* is
+#ifdef EXTRA_ARGS
+                 , EXTRA_ARGS
+#endif
+                 )
+{
+  int nSubrects = is->readU32();
+  PIXEL_T bg = is->READ_PIXEL();
+  FILL_RECT(r, bg);
+
+  for (int i = 0; i < nSubrects; i++) {
+    PIXEL_T pix = is->READ_PIXEL();
+    int x = is->readU16();
+    int y = is->readU16();
+    int w = is->readU16();
+    int h = is->readU16();
+    FILL_RECT(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
+  }
+}
+
+#undef PIXEL_T
+#undef READ_PIXEL
+#undef RRE_DECODE
+}
diff --git a/common/rfb/rreEncode.h b/common/rfb/rreEncode.h
new file mode 100644
index 0000000..3f83487
--- /dev/null
+++ b/common/rfb/rreEncode.h
@@ -0,0 +1,164 @@
+/* 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.
+ */
+//
+// RRE encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+//
+// The data argument to RRE_ENCODE contains the pixel data, and it writes the
+// encoded version to the given OutStream.  If the encoded version exceeds w*h
+// it aborts and returns -1, otherwise it returns the number of subrectangles.
+//
+
+#include <rdr/OutStream.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define RRE_ENCODE CONCAT2E(rreEncode,BPP)
+
+int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg);
+
+int RRE_ENCODE (void* data, int w, int h, rdr::OutStream* os)
+{
+  // Find the background colour - count occurrences of up to 4 different pixel
+  // values, and choose the one which occurs most often.
+
+  const int nCols = 4;
+  PIXEL_T pix[nCols];
+  int count[nCols] = { 0, };
+  PIXEL_T* ptr = (PIXEL_T*)data;
+  PIXEL_T* end = ptr + w*h;
+
+  while (ptr < end) {
+    int i;
+    for (i = 0; i < nCols; i++) {
+      if (count[i] == 0)
+        pix[i] = *ptr;
+
+      if (pix[i] == *ptr) {
+        count[i]++;
+        break;
+      }
+    }
+
+    if (i == nCols) break;
+    ptr++;
+  }
+  
+  int bg = 0;
+  for (int i = 1; i < nCols; i++)
+    if (count[i] > count[bg]) bg = i;
+
+  // Now call the function to do the encoding.
+
+  return RRE_ENCODE ((PIXEL_T*)data, w, h, os, pix[bg]);
+}
+
+int RRE_ENCODE (PIXEL_T* data, int w, int h, rdr::OutStream* os, PIXEL_T bg)
+{
+  int oldLen = os->length();
+  os->WRITE_PIXEL(bg);
+
+  int nSubrects = 0;
+
+  for (int y = 0; y < h; y++)
+  {
+    int x = 0;
+    while (x < w) {
+      if (*data == bg) {
+        x++;
+        data++;
+        continue;
+      }
+
+      // Find horizontal subrect first
+      PIXEL_T* ptr = data+1;
+      PIXEL_T* eol = data+w-x;
+      while (ptr < eol && *ptr == *data) ptr++;
+      int sw = ptr - data;
+
+      ptr = data + w;
+      int sh = 1;
+      while (sh < h-y) {
+        eol = ptr + sw;
+        while (ptr < eol)
+          if (*ptr++ != *data) goto endOfHorizSubrect;
+        ptr += w - sw;
+        sh++;
+      }
+    endOfHorizSubrect:
+
+      // Find vertical subrect
+      int vh;
+      for (vh = sh; vh < h-y; vh++)
+        if (data[vh*w] != *data) break;
+
+      if (vh != sh) {
+        ptr = data+1;
+        int vw;
+        for (vw = 1; vw < sw; vw++) {
+          for (int i = 0; i < vh; i++)
+            if (ptr[i*w] != *data) goto endOfVertSubrect;
+          ptr++;
+        }
+      endOfVertSubrect:
+
+        // If vertical subrect bigger than horizontal then use that.
+        if (sw*sh < vw*vh) {
+          sw = vw;
+          sh = vh;
+        }
+      }
+
+      nSubrects++;
+      os->WRITE_PIXEL(*data);
+      os->writeU16(x);
+      os->writeU16(y);
+      os->writeU16(sw);
+      os->writeU16(sh);
+      if (os->length() > oldLen + w*h) return -1;
+
+      ptr = data+w;
+      PIXEL_T* eor = data+w*sh;
+      while (ptr < eor) {
+        eol = ptr + sw;
+        while (ptr < eol) *ptr++ = bg;
+        ptr += w - sw;
+      }
+      x += sw;
+      data += sw;
+    }
+  }
+
+  return nSubrects;
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef RRE_ENCODE
+}
diff --git a/common/rfb/secTypes.cxx b/common/rfb/secTypes.cxx
new file mode 100644
index 0000000..830d844
--- /dev/null
+++ b/common/rfb/secTypes.cxx
@@ -0,0 +1,73 @@
+/* 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 <string.h>
+#ifdef _WIN32
+#define strcasecmp _stricmp
+#endif
+#include <rfb/secTypes.h>
+#include <rfb/util.h>
+
+int rfb::secTypeNum(const char* name)
+{
+  if (strcasecmp(name, "None") == 0)       return secTypeNone;
+  if (strcasecmp(name, "VncAuth") == 0)    return secTypeVncAuth;
+  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;
+}
+
+const char* rfb::secTypeName(int num)
+{
+  switch (num) {
+  case secTypeNone:       return "None";
+  case secTypeVncAuth:    return "VncAuth";
+  case secTypeTight:      return "Tight";
+  case secTypeRA2:        return "RA2";
+  case secTypeRA2ne:      return "RA2ne";
+  case secTypeSSPI:       return "SSPI";
+  case secTypeSSPIne:     return "SSPIne";
+  default:                return "[unknown secType]";
+  }
+}
+
+bool rfb::secTypeEncrypts(int num)
+{
+  switch (num) {
+  case secTypeRA2:
+  case secTypeSSPI:
+    return true;
+  default:
+    return false;
+  }
+}
+
+std::list<int> rfb::parseSecTypes(const char* types_)
+{
+  std::list<int> result;
+  CharArray types(strDup(types_)), type;
+  while (types.buf) {
+    strSplit(types.buf, ',', &type.buf, &types.buf);
+    int typeNum = secTypeNum(type.buf);
+    if (typeNum != secTypeInvalid)
+      result.push_back(typeNum);
+  }
+  return result;
+}
diff --git a/common/rfb/secTypes.h b/common/rfb/secTypes.h
new file mode 100644
index 0000000..3cf783b
--- /dev/null
+++ b/common/rfb/secTypes.h
@@ -0,0 +1,54 @@
+/* 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.
+ */
+//
+// secTypes.h - constants for the various security types.
+//
+
+#ifndef __RFB_SECTYPES_H__
+#define __RFB_SECTYPES_H__
+
+#include <list>
+
+namespace rfb {
+  const int secTypeInvalid = 0;
+  const int secTypeNone    = 1;
+  const int secTypeVncAuth = 2;
+
+  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;
+
+  // result types
+
+  const int secResultOK = 0;
+  const int secResultFailed = 1;
+  const int secResultTooMany = 2; // deprecated
+
+  const char* secTypeName(int num);
+  int secTypeNum(const char* name);
+  bool secTypeEncrypts(int num);
+  std::list<int> parseSecTypes(const char* types);
+}
+
+#endif
diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h
new file mode 100644
index 0000000..dd0c4d9
--- /dev/null
+++ b/common/rfb/tightDecode.h
@@ -0,0 +1,412 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky.  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
+ * (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.
+ */
+
+//
+// Tight decoding functions.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// FILL_RECT          - fill a rectangle with a single color
+// IMAGE_RECT         - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rdr/ZlibInStream.h>
+#include <rfb/Exception.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define TIGHT_DECODE CONCAT2E(tightDecode,BPP)
+
+#define TIGHT_MIN_TO_COMPRESS 12
+static bool DecompressJpegRect(const Rect& r, rdr::InStream* is,
+			       PIXEL_T* buf, CMsgHandler* handler);
+static void FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+			   PIXEL_T* buf, CMsgHandler* handler);
+#if BPP == 32
+static void FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+			     PIXEL_T* buf, CMsgHandler* handler);
+#endif
+
+// Main function implementing Tight decoder
+
+void TIGHT_DECODE (const Rect& r, rdr::InStream* is,
+                   rdr::ZlibInStream zis[], PIXEL_T* buf
+#ifdef EXTRA_ARGS
+                      , EXTRA_ARGS
+#endif
+                      )
+{
+  rdr::U8 *bytebuf = (rdr::U8*) buf;
+  bool cutZeros = false;
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+#if BPP == 32
+  if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+      myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+    cutZeros = true;
+  } 
+#endif
+
+  rdr::U8 comp_ctl = is->readU8();
+
+  // Flush zlib streams if we are told by the server to do so.
+  for (int i = 0; i < 4; i++) {
+    if (comp_ctl & 1) {
+      zis[i].reset();
+    }
+    comp_ctl >>= 1;
+  }
+
+  // "Fill" compression type.
+  if (comp_ctl == rfbTightFill) {
+    PIXEL_T pix;
+    if (cutZeros) {
+      is->readBytes(bytebuf, 3);
+      pix = RGB24_TO_PIXEL32(bytebuf[0], bytebuf[1], bytebuf[2]);
+    } else {
+      pix = is->READ_PIXEL();
+    }
+    FILL_RECT(r, pix);
+    return;
+  }
+
+  // "JPEG" compression type.
+  if (comp_ctl == rfbTightJpeg) {
+    DecompressJpegRect(r, is, buf, handler);
+    return;
+  }
+
+  // Quit on unsupported compression type.
+  if (comp_ctl > rfbTightMaxSubencoding) {
+    throw Exception("TightDecoder: bad subencoding value received");
+    return;
+  }
+
+  // "Basic" compression type.
+  int palSize = 0;
+  static PIXEL_T palette[256];
+  bool useGradient = false;
+
+  if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+    rdr::U8 filterId = is->readU8();
+
+    switch (filterId) {
+    case rfbTightFilterPalette: 
+      palSize = is->readU8() + 1;
+      if (cutZeros) {
+	rdr::U8 *tightPalette = (rdr::U8*) palette;
+	is->readBytes(tightPalette, palSize*3);
+	for (int i = palSize - 1; i >= 0; i--) {
+	  palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+					tightPalette[i*3+1],
+					tightPalette[i*3+2]);
+        }
+      } else {
+	for (int i = 0; i < palSize; i++)
+	  palette[i] = is->READ_PIXEL();
+      }
+      break;
+    case rfbTightFilterGradient: 
+      useGradient = true;
+      break;
+    case rfbTightFilterCopy:
+      break;
+    default:
+      throw Exception("TightDecoder: unknown filter code received");
+      return;
+    }
+  }
+
+  int bppp = BPP;
+  if (palSize != 0) {
+    bppp = (palSize <= 2) ? 1 : 8;
+  } else if (cutZeros) {
+    bppp = 24;
+  }
+
+  // Determine if the data should be decompressed or just copied.
+  int rowSize = (r.width() * bppp + 7) / 8;
+  int dataSize = r.height() * rowSize;
+  int streamId = -1;
+  rdr::InStream *input;
+  if (dataSize < TIGHT_MIN_TO_COMPRESS) {
+    input = is;
+  } else {
+    int length = is->readCompactLength();
+    streamId = comp_ctl & 0x03;
+    zis[streamId].setUnderlying(is, length);
+    input = &zis[streamId];
+  }
+
+  if (palSize == 0) {
+    // Truecolor data
+    if (useGradient) {
+#if BPP == 32
+      if (cutZeros) {
+	FilterGradient24(r, input, dataSize, buf, handler);
+      } else 
+#endif
+	{
+	  FilterGradient(r, input, dataSize, buf, handler);
+	}
+    } else {
+      input->readBytes(buf, dataSize); 
+      if (cutZeros) {
+	for (int p = r.height() * r.width() - 1; p >= 0; p--) {
+	  buf[p] = RGB24_TO_PIXEL32(bytebuf[p*3],
+				    bytebuf[p*3+1],
+				    bytebuf[p*3+2]);
+	}
+      }
+    }
+  } else {
+    int x, y, b, w;
+    PIXEL_T *ptr = buf;
+    rdr::U8 bits;
+    if (palSize <= 2) {
+      // 2-color palette
+      w = (r.width() + 7) / 8;
+      for (y = 0; y < r.height(); y++) {
+        for (x = 0; x < r.width() / 8; x++) {
+          bits = input->readU8();
+          for (b = 7; b >= 0; b--) {
+            *ptr++ = palette[bits >> b & 1];
+	  }
+        }
+        if (r.width() % 8 != 0) {
+          bits = input->readU8();
+          for (b = 7; b >= 8 - r.width() % 8; b--) {
+            *ptr++ = palette[bits >> b & 1];
+          }
+        }
+      }
+    } else {
+      // 256-color palette
+      for (y = 0; y < r.height(); y++) {
+        for (x = 0; x < r.width(); x++) {
+          *ptr++ = palette[input->readU8()];
+	}
+      }
+    }
+  }
+
+  IMAGE_RECT(r, buf);
+
+  if (streamId != -1) {
+    zis[streamId].reset();
+  }
+}
+
+static bool
+DecompressJpegRect(const Rect& r, rdr::InStream* is,
+		   PIXEL_T* buf, CMsgHandler* handler)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  PIXEL_T *pixelPtr = buf;
+  static rdr::U8 scanline_buffer[TIGHT_MAX_WIDTH*3];
+  JSAMPROW scanline = scanline_buffer;
+
+  // Read length
+  int compressedLen = is->readCompactLength();
+  if (compressedLen <= 0) {
+      throw Exception("Incorrect data received from the server.\n");
+  }
+
+  // Allocate netbuf and read in data
+  rdr::U8* netbuf = new rdr::U8[compressedLen];
+  if (!netbuf) {
+    throw Exception("rfb::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, compressedLen);
+
+  // Set up JPEG decompression
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo);
+  JpegSetSrcManager(&cinfo, (char*)netbuf, compressedLen);
+  jpeg_read_header(&cinfo, TRUE);
+  cinfo.out_color_space = JCS_RGB;
+
+  jpeg_start_decompress(&cinfo);
+  if (cinfo.output_width != (unsigned)r.width() || cinfo.output_height != (unsigned)r.height() ||
+      cinfo.output_components != 3) {
+      jpeg_destroy_decompress(&cinfo);
+      throw Exception("Tight Encoding: Wrong JPEG data received.\n");
+  }
+
+  // Decompress
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  while (cinfo.output_scanline < cinfo.output_height) {
+    jpeg_read_scanlines(&cinfo, &scanline, 1);
+    if (jpegError) {
+      break;
+    }
+
+    for (int dx = 0; dx < r.width(); dx++) {
+      *pixelPtr++ = 
+	RGB24_TO_PIXEL(scanline[dx*3], scanline[dx*3+1], scanline[dx*3+2]);
+    }
+  }
+
+  IMAGE_RECT(r, buf);
+
+  if (!jpegError) {
+    jpeg_finish_decompress(&cinfo);
+  }
+
+  jpeg_destroy_decompress(&cinfo);
+
+  delete [] netbuf;
+
+  return !jpegError;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24(const Rect& r, rdr::InStream* is, int dataSize,
+		 PIXEL_T* buf, CMsgHandler* handler)
+{
+  int x, y, c;
+  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+  rdr::U8 pix[3]; 
+  int est[3]; 
+
+  memset(prevRow, 0, sizeof(prevRow));
+
+  // Allocate netbuf and read in data
+  rdr::U8 *netbuf = new rdr::U8[dataSize];
+  if (!netbuf) {
+    throw Exception("rfb::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, dataSize);
+
+  // Set up shortcut variables
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  int rectHeight = r.height();
+  int rectWidth = r.width();
+
+  for (y = 0; y < rectHeight; y++) {
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+      thisRow[c] = pix[c];
+    }
+    buf[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+	if (est[c] > 0xff) {
+	  est[c] = 0xff;
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+	thisRow[x*3+c] = pix[c];
+      }
+      buf[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(prevRow, thisRow, sizeof(prevRow));
+  }
+
+  delete [] netbuf;
+}
+
+#endif
+
+static void
+FilterGradient(const Rect& r, rdr::InStream* is, int dataSize,
+	       PIXEL_T* buf, CMsgHandler* handler)
+{
+  int x, y, c;
+  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+  int pix[3]; 
+  int max[3]; 
+  int shift[3]; 
+  int est[3]; 
+
+  memset(prevRow, 0, sizeof(prevRow));
+
+  // Allocate netbuf and read in data
+  PIXEL_T *netbuf = (PIXEL_T*)new rdr::U8[dataSize];
+  if (!netbuf) {
+    throw Exception("rfb::tightDecode unable to allocate buffer");
+  }
+  is->readBytes(netbuf, dataSize);
+
+  // Set up shortcut variables
+  const rfb::PixelFormat& myFormat = handler->cp.pf();
+  max[0] = myFormat.redMax; 
+  max[1] = myFormat.greenMax; 
+  max[2] = myFormat.blueMax; 
+  shift[0] = myFormat.redShift; 
+  shift[1] = myFormat.greenShift; 
+  shift[2] = myFormat.blueShift; 
+  int rectHeight = r.height();
+  int rectWidth = r.width();
+
+  for (y = 0; y < rectHeight; y++) {
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = (netbuf[y*rectWidth] >> shift[c]) + prevRow[c] & max[c];
+      thisRow[c] = pix[c];
+    }
+    buf[y*rectWidth] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+	if (est[c] > max[c]) {
+	  est[c] = max[c];
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = (netbuf[y*rectWidth+x] >> shift[c]) + est[c] & max[c];
+	thisRow[x*3+c] = pix[c];
+      }
+      buf[y*rectWidth+x] = RGB_TO_PIXEL(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(prevRow, thisRow, sizeof(prevRow));
+  }
+
+  delete [] netbuf;
+}
+
+#undef TIGHT_MIN_TO_COMPRESS
+#undef TIGHT_DECODE
+#undef READ_PIXEL
+#undef PIXEL_T
+}
diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h
new file mode 100644
index 0000000..71f076e
--- /dev/null
+++ b/common/rfb/tightEncode.h
@@ -0,0 +1,720 @@
+/* Copyright (C) 2000-2003 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
+ * (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.
+ */
+
+//
+// tightEncode.h - Tight encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+//
+
+#include <rdr/OutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define TIGHT_ENCODE CONCAT2E(tightEncode,BPP)
+#define SWAP_PIXEL CONCAT2E(SWAP,BPP)
+#define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP)
+#define PACK_PIXELS CONCAT2E(packPixels,BPP)
+#define DETECT_SMOOTH_IMAGE CONCAT2E(detectSmoothImage,BPP)
+#define ENCODE_SOLID_RECT CONCAT2E(encodeSolidRect,BPP)
+#define ENCODE_FULLCOLOR_RECT CONCAT2E(encodeFullColorRect,BPP)
+#define ENCODE_MONO_RECT CONCAT2E(encodeMonoRect,BPP)
+#define ENCODE_INDEXED_RECT CONCAT2E(encodeIndexedRect,BPP)
+#define PREPARE_JPEG_ROW CONCAT2E(prepareJpegRow,BPP)
+#define ENCODE_JPEG_RECT CONCAT2E(encodeJpegRect,BPP)
+#define FILL_PALETTE CONCAT2E(fillPalette,BPP)
+
+#ifndef TIGHT_ONCE
+#define TIGHT_ONCE
+
+//
+// C-style structures to store palette entries and compression paramentes.
+// Such code probably should be converted into C++ classes.
+//
+
+struct TIGHT_COLOR_LIST {
+  TIGHT_COLOR_LIST *next;
+  int idx;
+  rdr::U32 rgb;
+};
+
+struct TIGHT_PALETTE_ENTRY {
+  TIGHT_COLOR_LIST *listNode;
+  int numPixels;
+};
+
+struct TIGHT_PALETTE {
+  TIGHT_PALETTE_ENTRY entry[256];
+  TIGHT_COLOR_LIST *hash[256];
+  TIGHT_COLOR_LIST list[256];
+};
+
+// FIXME: Is it really a good idea to use static variables for this?
+static int s_endianMismatch;      // local/remote formats differ in byte order
+static bool s_pack24;             // use 24-bit packing for 32-bit pixels
+static int s_rs, s_gs, s_bs;      // shifts for 24-bit pixel conversion
+
+// FIXME: Make a separate class for palette operations.
+static int s_palMaxColors, s_palNumColors;
+static rdr::U32 s_monoBackground, s_monoForeground;
+static TIGHT_PALETTE s_palette;
+
+//
+// Swapping bytes in pixels.
+// FIXME: Use a sort of ImageGetter that does not convert pixel format?
+//
+
+#ifndef SWAP16
+#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
+#endif
+#ifndef SWAP32
+#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
+                   (((n) & 0x0000ff00) << 8) | ((n) << 24))
+#endif
+
+//
+// Functions to operate on palette structures.
+//
+
+#define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF))
+
+static void paletteReset(void)
+{
+  s_palNumColors = 0;
+  memset(s_palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
+}
+
+static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
+{
+  TIGHT_COLOR_LIST *pnode;
+  TIGHT_COLOR_LIST *prev_pnode = NULL;
+  int hash_key, idx, new_idx, count;
+
+  hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+  pnode = s_palette.hash[hash_key];
+
+  while (pnode != NULL) {
+    if (pnode->rgb == rgb) {
+      // Such palette entry already exists.
+      new_idx = idx = pnode->idx;
+      count = s_palette.entry[idx].numPixels + numPixels;
+      if (new_idx && s_palette.entry[new_idx-1].numPixels < count) {
+        do {
+          s_palette.entry[new_idx] = s_palette.entry[new_idx-1];
+          s_palette.entry[new_idx].listNode->idx = new_idx;
+          new_idx--;
+        }
+        while (new_idx &&
+          s_palette.entry[new_idx-1].numPixels < count);
+        s_palette.entry[new_idx].listNode = pnode;
+        pnode->idx = new_idx;
+      }
+      s_palette.entry[new_idx].numPixels = count;
+      return s_palNumColors;
+    }
+    prev_pnode = pnode;
+    pnode = pnode->next;
+  }
+
+  // Check if palette is full.
+  if ( s_palNumColors == 256 || s_palNumColors == s_palMaxColors ) {
+    s_palNumColors = 0;
+    return 0;
+  }
+
+  // Move palette entries with lesser pixel counts.
+  for ( idx = s_palNumColors;
+  idx > 0 && s_palette.entry[idx-1].numPixels < numPixels;
+  idx-- ) {
+    s_palette.entry[idx] = s_palette.entry[idx-1];
+    s_palette.entry[idx].listNode->idx = idx;
+  }
+
+  // Add new palette entry into the freed slot.
+  pnode = &s_palette.list[s_palNumColors];
+  if (prev_pnode != NULL) {
+    prev_pnode->next = pnode;
+  } else {
+    s_palette.hash[hash_key] = pnode;
+  }
+  pnode->next = NULL;
+  pnode->idx = idx;
+  pnode->rgb = rgb;
+  s_palette.entry[idx].listNode = pnode;
+  s_palette.entry[idx].numPixels = numPixels;
+
+  return (++s_palNumColors);
+}
+
+//
+// Compress the data (but do not perform actual compression if the data
+// size is less than TIGHT_MIN_TO_COMPRESS bytes.
+//
+
+static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+                         const void *buf, unsigned int length, int zlibLevel)
+{
+  if (length < TIGHT_MIN_TO_COMPRESS) {
+    os->writeBytes(buf, length);
+  } else {
+    // FIXME: Using a temporary MemOutStream may be not efficient.
+    //        Maybe use the same static object used in the JPEG coder?
+    rdr::MemOutStream mem_os;
+    zos->setUnderlying(&mem_os);
+    zos->setCompressionLevel(zlibLevel);
+    zos->writeBytes(buf, length);
+    zos->flush();
+    os->writeCompactLength(mem_os.length());
+    os->writeBytes(mem_os.data(), mem_os.length());
+  }
+}
+
+//
+// Destination manager implementation for the JPEG library.
+// FIXME: Implement JPEG compression in new rdr::JpegOutStream class.
+//
+
+// FIXME: Keeping a MemOutStream instance may consume too much space.
+rdr::MemOutStream s_jpeg_os;
+
+static struct jpeg_destination_mgr s_jpegDstManager;
+static JOCTET *s_jpegDstBuffer;
+static size_t s_jpegDstBufferLen;
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+  s_jpeg_os.clear();
+  s_jpegDstManager.next_output_byte = s_jpegDstBuffer;
+  s_jpegDstManager.free_in_buffer = s_jpegDstBufferLen;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+  s_jpeg_os.writeBytes(s_jpegDstBuffer, s_jpegDstBufferLen);
+  s_jpegDstManager.next_output_byte = s_jpegDstBuffer;
+  s_jpegDstManager.free_in_buffer = s_jpegDstBufferLen;
+
+  return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+  int dataLen = s_jpegDstBufferLen - s_jpegDstManager.free_in_buffer;
+  s_jpeg_os.writeBytes(s_jpegDstBuffer, dataLen);
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo, JOCTET *buf, size_t buflen)
+{
+  s_jpegDstBuffer = buf;
+  s_jpegDstBufferLen = buflen;
+  s_jpegDstManager.init_destination = JpegInitDestination;
+  s_jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+  s_jpegDstManager.term_destination = JpegTermDestination;
+  cinfo->dest = &s_jpegDstManager;
+}
+
+#endif  // #ifndef TIGHT_ONCE
+
+static void ENCODE_SOLID_RECT     (rdr::OutStream *os,
+                                   PIXEL_T *buf);
+static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                                   PIXEL_T *buf, const Rect& r);
+static void ENCODE_MONO_RECT      (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                                   PIXEL_T *buf, const Rect& r);
+#if (BPP != 8)
+static void ENCODE_INDEXED_RECT   (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                                   PIXEL_T *buf, const Rect& r);
+static void ENCODE_JPEG_RECT      (rdr::OutStream *os,
+                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
+#endif
+
+static void FILL_PALETTE (PIXEL_T *data, int count);
+
+//
+// Convert 32-bit color samples into 24-bit colors, in place.
+// Performs packing only when redMax, greenMax and blueMax are all 255.
+// Color components are assumed to be byte-aligned.
+//
+
+static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count)
+{
+#if (BPP != 32)
+  return count * sizeof(PIXEL_T);
+#else
+  if (!s_pack24)
+    return count * sizeof(PIXEL_T);
+
+  rdr::U32 pix;
+  rdr::U8 *dst = (rdr::U8 *)buf;
+  for (unsigned int i = 0; i < count; i++) {
+    pix = *buf++;
+    *dst++ = (rdr::U8)(pix >> s_rs);
+    *dst++ = (rdr::U8)(pix >> s_gs);
+    *dst++ = (rdr::U8)(pix >> s_bs);
+  }
+  return count * 3;
+#endif
+}
+
+//
+// Function to guess if a given rectangle is suitable for JPEG compression.
+// Returns true is it looks like a good data for JPEG, false otherwise.
+//
+// FIXME: Scan the image and determine is it really good for JPEG.
+//
+
+#if (BPP != 8)
+static bool DETECT_SMOOTH_IMAGE (PIXEL_T *buf, const Rect& r)
+{
+  if (r.width() < TIGHT_DETECT_MIN_WIDTH ||
+      r.height() < TIGHT_DETECT_MIN_HEIGHT ||
+      r.area() < TIGHT_JPEG_MIN_RECT_SIZE ||
+      s_pjconf == NULL)
+    return 0;
+
+  return 1;
+}
+#endif
+
+// FIXME: Split rectangles into smaller ones!
+// FIXME: Compare encoder code with 1.3 before the final version.
+
+//
+// Main function of the Tight encoder
+//
+
+void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os,
+                  rdr::ZlibOutStream zos[4], void* buf, ConnParams* cp
+#ifdef EXTRA_ARGS
+                  , EXTRA_ARGS
+#endif
+                  )
+{
+  const PixelFormat& pf = cp->pf();
+  GET_IMAGE_INTO_BUF(r, buf);
+  PIXEL_T* pixels = (PIXEL_T*)buf;
+
+#if (BPP != 8)
+  union {
+    rdr::U32 value32;
+    rdr::U8 test;
+  } littleEndian;
+  littleEndian.value32 = 1;
+  s_endianMismatch = (littleEndian.test != !pf.bigEndian);
+#endif
+
+#if (BPP == 32)
+  // Check if it's necessary to pack 24-bit pixels, and
+  // compute appropriate shift values if necessary.
+  s_pack24 = (pf.depth == 24 && pf.redMax == 0xFF &&
+              pf.greenMax == 0xFF && pf.blueMax == 0xFF);
+  if (s_pack24) {
+    if (!s_endianMismatch) {
+      s_rs = pf.redShift;
+      s_gs = pf.greenShift;
+      s_bs = pf.blueShift;
+    } else {
+      s_rs = 24 - pf.redShift;
+      s_gs = 24 - pf.greenShift;
+      s_bs = 24 - pf.blueShift;
+    }
+  }
+#endif
+
+  s_palMaxColors = r.area() / s_pconf->idxMaxColorsDivisor;
+  if (s_palMaxColors < 2 && r.area() >= s_pconf->monoMinRectSize) {
+    s_palMaxColors = 2;
+  }
+  // FIXME: Temporary limitation for switching to JPEG earlier.
+  if (s_palMaxColors > 96 && s_pjconf != NULL) {
+    s_palMaxColors = 96;
+  }
+
+  FILL_PALETTE(pixels, r.area());
+
+  switch (s_palNumColors) {
+  case 0:
+    // Truecolor image
+#if (BPP != 8)
+    if (s_pjconf != NULL && DETECT_SMOOTH_IMAGE(pixels, r)) {
+      ENCODE_JPEG_RECT(os, pixels, pf, r);
+      break;
+    }
+#endif
+    ENCODE_FULLCOLOR_RECT(os, zos, pixels, r);
+    break;
+  case 1:
+    // Solid rectangle
+    ENCODE_SOLID_RECT(os, pixels);
+    break;
+  case 2:
+    // Two-color rectangle
+    ENCODE_MONO_RECT(os, zos, pixels, r);
+    break;
+#if (BPP != 8)
+  default:
+    // Up to 256 different colors
+    ENCODE_INDEXED_RECT(os, zos, pixels, r);
+#endif
+  }
+}
+
+//
+// Subencoding implementations.
+//
+
+static void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf)
+{
+  os->writeU8(0x08 << 4);
+
+  int length = PACK_PIXELS(buf, 1);
+  os->writeBytes(buf, length);
+}
+
+static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                                   PIXEL_T *buf, const Rect& r)
+{
+  const int streamId = 0;
+  os->writeU8(streamId << 4);
+
+  int length = PACK_PIXELS(buf, r.area());
+  compressData(os, &zos[streamId], buf, length, s_pconf->rawZlibLevel);
+}
+
+static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                              PIXEL_T *buf, const Rect& r)
+{
+  const int streamId = 1;
+  os->writeU8((streamId | 0x04) << 4);
+  os->writeU8(0x01);
+
+  // Write the palette
+  PIXEL_T pal[2] = { (PIXEL_T)s_monoBackground, (PIXEL_T)s_monoForeground };
+  os->writeU8(1);
+  os->writeBytes(pal, PACK_PIXELS(pal, 2));
+
+  // Encode the data in-place
+  PIXEL_T *src = buf;
+  rdr::U8 *dst = (rdr::U8 *)buf;
+  int w = r.width();
+  int h = r.height();
+  PIXEL_T bg;
+  unsigned int value, mask;
+  int aligned_width;
+  int x, y, bg_bits;
+
+  bg = (PIXEL_T) s_monoBackground;
+  aligned_width = w - w % 8;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < aligned_width; x += 8) {
+      for (bg_bits = 0; bg_bits < 8; bg_bits++) {
+        if (*src++ != bg)
+          break;
+      }
+      if (bg_bits == 8) {
+        *dst++ = 0;
+        continue;
+      }
+      mask = 0x80 >> bg_bits;
+      value = mask;
+      for (bg_bits++; bg_bits < 8; bg_bits++) {
+        mask >>= 1;
+        if (*src++ != bg) {
+          value |= mask;
+        }
+      }
+      *dst++ = (rdr::U8)value;
+    }
+
+    mask = 0x80;
+    value = 0;
+    if (x >= w)
+      continue;
+
+    for (; x < w; x++) {
+      if (*src++ != bg) {
+        value |= mask;
+      }
+      mask >>= 1;
+    }
+    *dst++ = (rdr::U8)value;
+  }
+
+  // Write the data
+  int length = (w + 7) / 8;
+  length *= h;
+  compressData(os, &zos[streamId], buf, length, s_pconf->monoZlibLevel);
+}
+
+#if (BPP != 8)
+static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
+                                 PIXEL_T *buf, const Rect& r)
+{
+  const int streamId = 2;
+  os->writeU8((streamId | 0x04) << 4);
+  os->writeU8(0x01);
+
+  // Write the palette
+  {
+    PIXEL_T pal[256];
+    for (int i = 0; i < s_palNumColors; i++)
+      pal[i] = (PIXEL_T)s_palette.entry[i].listNode->rgb;
+    os->writeU8((rdr::U8)(s_palNumColors - 1));
+    os->writeBytes(pal, PACK_PIXELS(pal, s_palNumColors));
+  }
+
+  // Encode data in-place
+  PIXEL_T *src = buf;
+  rdr::U8 *dst = (rdr::U8 *)buf;
+  int count = r.area();
+  PIXEL_T rgb;
+  TIGHT_COLOR_LIST *pnode;
+  int rep = 0;
+
+  while (count--) {
+    rgb = *src++;
+    while (count && *src == rgb) {
+      rep++, src++, count--;
+    }
+    pnode = s_palette.hash[HASH_FUNCTION(rgb)];
+    while (pnode != NULL) {
+      if ((PIXEL_T)pnode->rgb == rgb) {
+        *dst++ = (rdr::U8)pnode->idx;
+        while (rep) {
+          *dst++ = (rdr::U8)pnode->idx;
+          rep--;
+        }
+        break;
+      }
+      pnode = pnode->next;
+    }
+  }
+
+  // Write the data
+  compressData(os, &zos[streamId], buf, r.area(), s_pconf->idxZlibLevel);
+}
+#endif  // #if (BPP != 8)
+
+//
+// JPEG compression.
+//
+
+#if (BPP != 8)
+static void PREPARE_JPEG_ROW (PIXEL_T *src, const PixelFormat& pf,
+                              rdr::U8 *dst, int count)
+{
+  // FIXME: Add a version of this function optimized for 24-bit colors?
+  PIXEL_T pix;
+  while (count--) {
+    pix = *src++;
+    if (s_endianMismatch)
+      pix = SWAP_PIXEL(pix);
+    *dst++ = (rdr::U8)((pix >> pf.redShift   & pf.redMax)   * 255 / pf.redMax);
+    *dst++ = (rdr::U8)((pix >> pf.greenShift & pf.greenMax) * 255 / pf.greenMax);
+    *dst++ = (rdr::U8)((pix >> pf.blueShift  & pf.blueMax)  * 255 / pf.blueMax);
+  }
+}
+#endif  // #if (BPP != 8)
+
+#if (BPP != 8)
+static void ENCODE_JPEG_RECT (rdr::OutStream *os, PIXEL_T *buf,
+                              const PixelFormat& pf, const Rect& r)
+{
+  int w = r.width();
+  int h = r.height();
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+
+  // FIXME: Make srcBuf[] and/or dstBuf[] static?
+  rdr::U8 *srcBuf = new rdr::U8[w * 3];
+  JSAMPROW rowPointer[1];
+  rowPointer[0] = (JSAMPROW)srcBuf;
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_compress(&cinfo);
+
+  cinfo.image_width = w;
+  cinfo.image_height = h;
+  cinfo.input_components = 3;
+  cinfo.in_color_space = JCS_RGB;
+
+  jpeg_set_defaults(&cinfo);
+  jpeg_set_quality(&cinfo, s_pjconf->jpegQuality, TRUE);
+
+  rdr::U8 *dstBuf = new rdr::U8[2048];
+  JpegSetDstManager(&cinfo, dstBuf, 2048);
+
+  jpeg_start_compress(&cinfo, TRUE);
+  for (int dy = 0; dy < h; dy++) {
+    PREPARE_JPEG_ROW(&buf[dy * w], pf, srcBuf, w);
+    jpeg_write_scanlines(&cinfo, rowPointer, 1);
+  }
+  jpeg_finish_compress(&cinfo);
+  jpeg_destroy_compress(&cinfo);
+
+  delete[] srcBuf;
+  delete[] dstBuf;
+
+  os->writeU8(0x09 << 4);
+  os->writeCompactLength(s_jpeg_os.length());
+  os->writeBytes(s_jpeg_os.data(), s_jpeg_os.length());
+}
+#endif  // #if (BPP != 8)
+
+//
+// Determine the number of colors in the rectangle, and fill in the palette.
+//
+
+#if (BPP == 8)
+static void FILL_PALETTE (PIXEL_T *data, int count)
+{
+  PIXEL_T c0, c1;
+  int i, n0, n1;
+
+  s_palNumColors = 0;
+
+  c0 = data[0];
+  for (i = 1; i < count && data[i] == c0; i++);
+  if (i == count) {
+    s_palNumColors = 1;
+    return;                       // Solid rectangle
+  }
+
+  if (s_palMaxColors < 2)
+    return;
+
+  n0 = i;
+  c1 = data[i];
+  n1 = 0;
+  for (i++; i < count; i++) {
+    if (data[i] == c0) {
+      n0++;
+    } else if (data[i] == c1) {
+      n1++;
+    } else
+      break;
+  }
+  if (i == count) {
+    if (n0 > n1) {
+      s_monoBackground = (rdr::U32)c0;
+      s_monoForeground = (rdr::U32)c1;
+    } else {
+      s_monoBackground = (rdr::U32)c1;
+      s_monoForeground = (rdr::U32)c0;
+    }
+    s_palNumColors = 2;           // Two colors
+  }
+}
+#else   // (BPP != 8)
+static void FILL_PALETTE (PIXEL_T *data, int count)
+{
+  PIXEL_T c0, c1, ci = 0;
+  int i, n0, n1, ni;
+
+  c0 = data[0];
+  for (i = 1; i < count && data[i] == c0; i++);
+  if (i >= count) {
+    s_palNumColors = 1;           // Solid rectangle
+    return;
+  }
+
+  if (s_palMaxColors < 2) {
+    s_palNumColors = 0;           // Full-color format preferred
+    return;
+  }
+
+  n0 = i;
+  c1 = data[i];
+  n1 = 0;
+  for (i++; i < count; i++) {
+    ci = data[i];
+    if (ci == c0) {
+      n0++;
+    } else if (ci == c1) {
+      n1++;
+    } else
+      break;
+  }
+  if (i >= count) {
+    if (n0 > n1) {
+      s_monoBackground = (rdr::U32)c0;
+      s_monoForeground = (rdr::U32)c1;
+    } else {
+      s_monoBackground = (rdr::U32)c1;
+      s_monoForeground = (rdr::U32)c0;
+    }
+    s_palNumColors = 2;           // Two colors
+    return;
+  }
+
+  paletteReset();
+  paletteInsert (c0, (rdr::U32)n0, BPP);
+  paletteInsert (c1, (rdr::U32)n1, BPP);
+
+  ni = 1;
+  for (i++; i < count; i++) {
+    if (data[i] == ci) {
+      ni++;
+    } else {
+      if (!paletteInsert (ci, (rdr::U32)ni, BPP))
+        return;
+      ci = data[i];
+      ni = 1;
+    }
+  }
+  paletteInsert (ci, (rdr::U32)ni, BPP);
+}
+#endif  // #if (BPP == 8)
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef TIGHT_ENCODE
+#undef SWAP_PIXEL
+#undef HASH_FUNCTION
+#undef PACK_PIXELS
+#undef DETECT_SMOOTH_IMAGE
+#undef ENCODE_SOLID_RECT
+#undef ENCODE_FULLCOLOR_RECT
+#undef ENCODE_MONO_RECT
+#undef ENCODE_INDEXED_RECT
+#undef PREPARE_JPEG_ROW
+#undef ENCODE_JPEG_RECT
+#undef FILL_PALETTE
+}
diff --git a/common/rfb/transInitTempl.h b/common/rfb/transInitTempl.h
new file mode 100644
index 0000000..464cfdf
--- /dev/null
+++ b/common/rfb/transInitTempl.h
@@ -0,0 +1,254 @@
+/* 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.
+ */
+//
+// transInitTempl.h - templates for functions to initialise lookup tables for
+// the translation functions.
+//
+// This file is #included after having set the following macros:
+// BPPOUT - 8, 16 or 32
+
+#if !defined(BPPOUT)
+#error "transInitTempl.h: BPPOUT not defined"
+#endif
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifndef SWAP16
+#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
+#endif
+
+#ifndef SWAP32
+#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
+                   (((n) & 0x0000ff00) << 8) | ((n) << 24))
+#endif
+
+#define OUTPIXEL rdr::CONCAT2E(U,BPPOUT)
+#define SWAPOUT CONCAT2E(SWAP,BPPOUT)
+#define initSimpleCMtoTCOUT    CONCAT2E(initSimpleCMtoTC,BPPOUT)
+#define initSimpleTCtoTCOUT    CONCAT2E(initSimpleTCtoTC,BPPOUT)
+#define initSimpleCMtoCubeOUT  CONCAT2E(initSimpleCMtoCube,BPPOUT)
+#define initSimpleTCtoCubeOUT  CONCAT2E(initSimpleTCtoCube,BPPOUT)
+#define initRGBTCtoTCOUT       CONCAT2E(initRGBTCtoTC,BPPOUT)
+#define initRGBTCtoCubeOUT     CONCAT2E(initRGBTCtoCube,BPPOUT)
+#define initOneRGBTableOUT     CONCAT2E(initOneRGBTable,BPPOUT)
+#define initOneRGBCubeTableOUT CONCAT2E(initOneRGBCubeTable,BPPOUT)
+
+#ifndef TRANS_INIT_TEMPL_ENDIAN_TEST
+#define TRANS_INIT_TEMPL_ENDIAN_TEST
+  static rdr::U32 endianTest = 1;
+  static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1;
+#endif
+
+void initSimpleCMtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                          ColourMap* cm, const PixelFormat& outPF)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = 1 << inPF.bpp;
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+  OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+  for (int i = 0; i < size; i++) {
+    int r,g,b;
+    cm->lookup(i,&r,&g,&b);
+
+    table[i] = ((((r * outPF.redMax   + 32767) / 65535) << outPF.redShift) |
+                (((g * outPF.greenMax + 32767) / 65535) << outPF.greenShift) |
+                (((b * outPF.blueMax  + 32767) / 65535) << outPF.blueShift));
+#if (BPPOUT != 8)
+    if (outPF.bigEndian != nativeBigEndian)
+      table[i] = SWAPOUT (table[i]);
+#endif
+  }
+}
+
+void initSimpleTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                          const PixelFormat& outPF)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = 1 << inPF.bpp;
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+  OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+  for (int i = 0; i < size; i++) {
+    int r = (i >> inPF.redShift)   & inPF.redMax;
+    int g = (i >> inPF.greenShift) & inPF.greenMax;
+    int b = (i >> inPF.blueShift)  & inPF.blueMax;
+      
+    r = (r * outPF.redMax   + inPF.redMax/2)   / inPF.redMax;
+    g = (g * outPF.greenMax + inPF.greenMax/2) / inPF.greenMax;
+    b = (b * outPF.blueMax  + inPF.blueMax/2)  / inPF.blueMax;
+      
+    table[i] = ((r << outPF.redShift)   |
+                (g << outPF.greenShift) |
+                (b << outPF.blueShift));
+#if (BPPOUT != 8)
+    if (outPF.bigEndian != nativeBigEndian)
+      table[i] = SWAPOUT (table[i]);
+#endif
+  }
+}
+
+void initSimpleCMtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                            ColourMap* cm, ColourCube* cube)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = 1 << inPF.bpp;
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+  OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+  for (int i = 0; i < size; i++) {
+    int r,g,b;
+    cm->lookup(i,&r,&g,&b);
+    r = (r * (cube->nRed-1)   + 32767) / 65535;
+    g = (g * (cube->nGreen-1) + 32767) / 65535;
+    b = (b * (cube->nBlue-1)  + 32767) / 65535;
+    table[i] = cube->lookup(r, g, b);
+  }
+}
+
+void initSimpleTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                            ColourCube* cube)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = 1 << inPF.bpp;
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+  OUTPIXEL* table = (OUTPIXEL*)*tablep;
+
+  for (int i = 0; i < size; i++) {
+    int r = (i >> inPF.redShift)   & inPF.redMax;
+    int g = (i >> inPF.greenShift) & inPF.greenMax;
+    int b = (i >> inPF.blueShift)  & inPF.blueMax;
+
+    r = (r * (cube->nRed-1)   + inPF.redMax/2)   / inPF.redMax;
+    g = (g * (cube->nGreen-1) + inPF.greenMax/2) / inPF.greenMax;
+    b = (b * (cube->nBlue-1)  + inPF.blueMax/2)  / inPF.blueMax;
+
+    table[i] = cube->lookup(r, g, b);
+  }
+}
+
+void initOneRGBTableOUT (OUTPIXEL* table, int inMax, int outMax,
+                         int outShift, bool swap)
+{
+  int size = inMax + 1;
+
+  for (int i = 0; i < size; i++) {
+    table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (BPPOUT != 8)
+    if (swap)
+      table[i] = SWAPOUT (table[i]);
+#endif
+  }
+}
+
+void initRGBTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                       const PixelFormat& outPF)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = inPF.redMax + inPF.greenMax + inPF.blueMax + 3;
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+
+  OUTPIXEL* redTable = (OUTPIXEL*)*tablep;
+  OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+  OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+
+  bool swap = (outPF.bigEndian != nativeBigEndian);
+
+  initOneRGBTableOUT (redTable, inPF.redMax, outPF.redMax, 
+                           outPF.redShift, swap);
+  initOneRGBTableOUT (greenTable, inPF.greenMax, outPF.greenMax,
+                           outPF.greenShift, swap);
+  initOneRGBTableOUT (blueTable, inPF.blueMax, outPF.blueMax,
+                           outPF.blueShift, swap);
+}
+
+
+void initOneRGBCubeTableOUT (OUTPIXEL* table, int inMax, int outMax,
+                             int outMult)
+{
+  int size = inMax + 1;
+
+  for (int i = 0; i < size; i++) {
+    table[i] = ((i * outMax + inMax / 2) / inMax) * outMult;
+  }
+}
+
+void initRGBTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF,
+                         ColourCube* cube)
+{
+  if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian)
+    throw Exception("Internal error: inPF is not native endian");
+
+  int size = inPF.redMax + inPF.greenMax + inPF.blueMax + 3 + cube->size();
+
+  delete [] *tablep;
+  *tablep = new rdr::U8[size * sizeof(OUTPIXEL)];
+
+  OUTPIXEL* redTable = (OUTPIXEL*)*tablep;
+  OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+  OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+  OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1;
+
+  initOneRGBCubeTableOUT (redTable,   inPF.redMax,   cube->nRed-1,
+                               cube->redMult());
+  initOneRGBCubeTableOUT (greenTable, inPF.greenMax, cube->nGreen-1,
+                               cube->greenMult());
+  initOneRGBCubeTableOUT (blueTable,  inPF.blueMax,  cube->nBlue-1,
+                               cube->blueMult());
+  for (int i = 0; i < cube->size(); i++) {
+    cubeTable[i] = cube->table[i];
+  }
+}
+
+#undef OUTPIXEL
+#undef initSimpleCMtoTCOUT
+#undef initSimpleTCtoTCOUT
+#undef initSimpleCMtoCubeOUT
+#undef initSimpleTCtoCubeOUT
+#undef initRGBTCtoTCOUT
+#undef initRGBTCtoCubeOUT
+#undef initOneRGBTableOUT
+#undef initOneRGBCubeTableOUT
+}
diff --git a/common/rfb/transTempl.h b/common/rfb/transTempl.h
new file mode 100644
index 0000000..09dc7f9
--- /dev/null
+++ b/common/rfb/transTempl.h
@@ -0,0 +1,151 @@
+/* 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.
+ */
+//
+// transTempl.h - templates for translation functions.
+//
+// This file is #included after having set the following macros:
+// BPPIN  - 8, 16 or 32
+// BPPOUT - 8, 16 or 32
+
+#if !defined(BPPIN) || !defined(BPPOUT)
+#error "transTempl.h: BPPIN or BPPOUT not defined"
+#endif
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifndef CONCAT4E
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+#endif
+
+#define INPIXEL rdr::CONCAT2E(U,BPPIN)
+#define OUTPIXEL rdr::CONCAT2E(U,BPPOUT)
+#define transSimpleINtoOUT CONCAT4E(transSimple,BPPIN,to,BPPOUT)
+#define transRGBINtoOUT CONCAT4E(transRGB,BPPIN,to,BPPOUT)
+#define transRGBCubeINtoOUT CONCAT4E(transRGBCube,BPPIN,to,BPPOUT)
+
+#if (BPPIN <= 16)
+
+// transSimpleINtoOUT uses a single table.  This can be used for any incoming
+// and outgoing pixel formats, as long as the incoming pixel format is not too
+// large (for 16bpp, the table needs 64K entries).
+
+void transSimpleINtoOUT (void* table_,
+                         const PixelFormat& inPF, void* inPtr, int inStride,
+                         const PixelFormat& outPF, void* outPtr, int outStride,
+                         int width, int height)
+{
+  OUTPIXEL* table = (OUTPIXEL*)table_;
+  INPIXEL* ip = (INPIXEL*)inPtr;
+  OUTPIXEL* op = (OUTPIXEL*)outPtr;
+  int inExtra = inStride - width;
+  int outExtra = outStride - width;
+
+  while (height > 0) {
+    OUTPIXEL* opEndOfRow = op + width;
+    while (op < opEndOfRow)
+      *op++ = table[*ip++];
+    ip += inExtra;
+    op += outExtra;
+    height--;
+  }
+}
+
+#endif
+
+#if (BPPIN >= 16)
+
+// transRGBINtoOUT uses three tables, one each for red, green and blue
+// components and adds the values to produce the result.  This can be used
+// where a single table would be too large (e.g. 32bpp).  It only works for a
+// trueColour incoming pixel format.  Usually the outgoing pixel format is
+// trueColour, but we add rather than ORing the three values so that it is also
+// possible to generate an index into a colour cube.  I believe that in most
+// cases adding is just as fast as ORing - if not then we should split this
+// into two different functions for efficiency.
+
+void transRGBINtoOUT (void* table,
+                      const PixelFormat& inPF, void* inPtr, int inStride,
+                      const PixelFormat& outPF, void* outPtr, int outStride,
+                      int width, int height)
+{
+  OUTPIXEL* redTable = (OUTPIXEL*)table;
+  OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+  OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+  INPIXEL* ip = (INPIXEL*)inPtr;
+  OUTPIXEL* op = (OUTPIXEL*)outPtr;
+  int inExtra = inStride - width;
+  int outExtra = outStride - width;
+
+  while (height > 0) {
+    OUTPIXEL* opEndOfRow = op + width;
+    while (op < opEndOfRow) {
+      *op++ = (redTable  [(*ip >> inPF.redShift)   & inPF.redMax] +
+               greenTable[(*ip >> inPF.greenShift) & inPF.greenMax] +
+               blueTable [(*ip >> inPF.blueShift)  & inPF.blueMax]);
+      ip++;
+    }
+    ip += inExtra;
+    op += outExtra;
+    height--;
+  }
+}
+
+// transRGBCubeINtoOUT is similar to transRGBINtoOUT but also looks up the
+// colour cube index in a fourth table to yield a pixel value.
+
+void transRGBCubeINtoOUT (void* table,
+                          const PixelFormat& inPF, void* inPtr, int inStride,
+                          const PixelFormat& outPF, void* outPtr,
+                          int outStride, int width, int height)
+{
+  OUTPIXEL* redTable = (OUTPIXEL*)table;
+  OUTPIXEL* greenTable = redTable + inPF.redMax + 1;
+  OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1;
+  OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1;
+  INPIXEL* ip = (INPIXEL*)inPtr;
+  OUTPIXEL* op = (OUTPIXEL*)outPtr;
+  int inExtra = inStride - width;
+  int outExtra = outStride - width;
+
+  while (height > 0) {
+    OUTPIXEL* opEndOfRow = op + width;
+    while (op < opEndOfRow) {
+      *op++ = cubeTable[(redTable  [(*ip >> inPF.redShift)   & inPF.redMax] +
+                         greenTable[(*ip >> inPF.greenShift) & inPF.greenMax] +
+                         blueTable [(*ip >> inPF.blueShift)  & inPF.blueMax])];
+      ip++;
+    }
+    ip += inExtra;
+    op += outExtra;
+    height--;
+  }
+}
+
+#endif
+
+#undef INPIXEL
+#undef OUTPIXEL
+#undef transSimpleINtoOUT
+#undef transRGBINtoOUT
+#undef transRGBCubeINtoOUT
diff --git a/common/rfb/util.cxx b/common/rfb/util.cxx
new file mode 100644
index 0000000..5745432
--- /dev/null
+++ b/common/rfb/util.cxx
@@ -0,0 +1,184 @@
+/* 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.
+ */
+
+/*
+ * The following applies to stcasecmp and strncasecmp implementations:
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <rfb/util.h>
+
+// Provide strcasecmp() and/or strncasecmp() if absent on this system.
+
+#ifndef WIN32
+#if !defined(HAVE_STRCASECMP) || !defined(HAVE_STRNCASECMP)
+
+extern "C" {
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char s_charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+#ifndef HAVE_STRCASECMP
+int
+strcasecmp(const char *s1, const char *s2)
+{
+    unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (s_charmap[u1] != s_charmap[u2]) {
+	    return s_charmap[u1] - s_charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+#endif // !defined(HAVE_STRCASECMP)
+
+#ifndef HAVE_STRNCASECMP
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+    unsigned char u1, u2;
+
+    for (; n != 0; --n) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (s_charmap[u1] != s_charmap[u2]) {
+	    return s_charmap[u1] - s_charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+    return 0;
+}
+#endif // !defined(HAVE_STRNCASECMP)
+
+} // extern "C"
+
+#endif // !defined(HAVE_STRCASECMP) || !defined(HAVE_STRNCASECMP)
+#endif // defined(WIN32)
+
+namespace rfb {
+
+  char* strDup(const char* s) {
+    if (!s) return 0;
+    int l = strlen(s);
+    char* r = new char[l+1];
+    memcpy(r, s, l+1);
+    return r;
+  };
+
+  void strFree(char* s) {
+    delete [] s;
+  }
+
+
+  bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
+    CharArray out1old, out2old;
+    if (out1) out1old.buf = *out1;
+    if (out2) out2old.buf = *out2;
+    int len = strlen(src);
+    int i=0, increment=1, limit=len;
+    if (fromEnd) {
+      i=len-1; increment = -1; limit = -1;
+    }
+    while (i!=limit) {
+      if (src[i] == limiter) {
+        if (out1) {
+          *out1 = new char[i+1];
+          if (i) memcpy(*out1, src, i);
+          (*out1)[i] = 0;
+        }
+        if (out2) {
+          *out2 = new char[len-i];
+          if (len-i-1) memcpy(*out2, &src[i+1], len-i-1);
+          (*out2)[len-i-1] = 0;
+        }
+        return true;
+      }
+      i+=increment;
+    }
+    if (out1) *out1 = strDup(src);
+    if (out2) *out2 = 0;
+    return false;
+  }
+
+  bool strContains(const char* src, char c) {
+    int l=strlen(src);
+    for (int i=0; i<l; i++)
+      if (src[i] == c) return true;
+    return false;
+  }
+
+  void strCopy(char* dest, const char* src, int destlen) {
+    if (src)
+      strncpy(dest, src, destlen-1);
+    dest[src ? destlen-1 : 0] = 0;
+  }
+
+};
diff --git a/common/rfb/util.h b/common/rfb/util.h
new file mode 100644
index 0000000..fa205f0
--- /dev/null
+++ b/common/rfb/util.h
@@ -0,0 +1,111 @@
+/* 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.
+ */
+
+//
+// util.h - miscellaneous useful bits
+//
+
+#ifndef __RFB_UTIL_H__
+#define __RFB_UTIL_H__
+
+#include <limits.h>
+#include <string.h>
+
+namespace rfb {
+
+  // -=- Class to handle cleanup of arrays of characters
+  class CharArray {
+  public:
+    CharArray() : buf(0) {}
+    CharArray(char* str) : buf(str) {} // note: assumes ownership
+    CharArray(int len) {
+      buf = new char[len];
+    }
+    ~CharArray() {
+      delete [] buf;
+    }
+    // Get the buffer pointer & clear it (i.e. caller takes ownership)
+    char* takeBuf() {char* tmp = buf; buf = 0; return tmp;}
+    void replaceBuf(char* b) {delete [] buf; buf = b;}
+    char* buf;
+  private:
+    CharArray(const CharArray&);
+    CharArray& operator=(const CharArray&);
+  };
+
+  char* strDup(const char* s);
+  void strFree(char* s);
+
+  // Returns true if split successful.  Returns false otherwise.
+  // ALWAYS *copies* first part of string to out1 buffer.
+  // If limiter not found, leaves out2 alone (null) and just copies to out1.
+  // If out1 or out2 non-zero, calls strFree and zeroes them.
+  // If fromEnd is true, splits at end of string rather than beginning.
+  // Either out1 or out2 may be null, in which case the split will not return
+  // that part of the string.  Obviously, setting both to 0 is not useful...
+  bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd=false);
+
+  // Returns true if src contains c
+  bool strContains(const char* src, char c);
+
+  // 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)
+extern "C" {
+  int strcasecmp(const char *s1, const char *s2);
+}
+#endif
+#if !defined(WIN32) && !defined(HAVE_STRNCASECMP)
+extern "C" {
+  int strncasecmp(const char *s1, const char *s2, size_t n);
+}
+#endif
+
+#endif
diff --git a/common/rfb/zrleDecode.h b/common/rfb/zrleDecode.h
new file mode 100644
index 0000000..15d2790
--- /dev/null
+++ b/common/rfb/zrleDecode.h
@@ -0,0 +1,251 @@
+/* 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.
+ */
+
+//
+// ZRLE decoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// FILL_RECT          - fill a rectangle with a single colour
+// IMAGE_RECT         - draw a rectangle of pixel data from a buffer
+
+#include <rdr/InStream.h>
+#include <rdr/ZlibInStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,CPIXEL)
+#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
+#else
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define READ_PIXEL CONCAT2E(readOpaque,BPP)
+#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP)
+#endif
+
+void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
+                      rdr::ZlibInStream* zis, PIXEL_T* buf
+#ifdef EXTRA_ARGS
+                      , EXTRA_ARGS
+#endif
+                      )
+{
+  int length = is->readU32();
+  zis->setUnderlying(is, length);
+  Rect t;
+
+  for (t.tl.y = r.tl.y; t.tl.y < 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 = __rfbmin(r.br.x, t.tl.x + 64);
+
+      int mode = zis->readU8();
+      bool rle = mode & 128;
+      int palSize = mode & 127;
+      PIXEL_T palette[128];
+
+      for (int i = 0; i < palSize; i++) {
+        palette[i] = zis->READ_PIXEL();
+      }
+
+      if (palSize == 1) {
+        PIXEL_T pix = palette[0];
+        FILL_RECT(t,pix);
+        continue;
+      }
+
+      if (!rle) {
+        if (palSize == 0) {
+
+          // raw
+
+#ifdef CPIXEL
+          for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
+            *ptr = zis->READ_PIXEL();
+          }
+#else
+          zis->readBytes(buf, t.area() * (BPP / 8));
+#endif
+
+        } else {
+
+          // packed pixels
+          int bppp = ((palSize > 16) ? 8 :
+                      ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+
+          PIXEL_T* ptr = buf;
+
+          for (int i = 0; i < t.height(); i++) {
+            PIXEL_T* eol = ptr + t.width();
+            rdr::U8 byte = 0;
+            rdr::U8 nbits = 0;
+
+            while (ptr < eol) {
+              if (nbits == 0) {
+                byte = zis->readU8();
+                nbits = 8;
+              }
+              nbits -= bppp;
+              rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
+              *ptr++ = palette[index];
+            }
+          }
+        }
+
+#ifdef FAVOUR_FILL_RECT
+       //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
+        //t.width(),t.height(),t.tl.x,t.tl.y);
+        IMAGE_RECT(t,buf);
+#endif
+
+      } else {
+
+        if (palSize == 0) {
+
+          // plain RLE
+
+          PIXEL_T* ptr = buf;
+          PIXEL_T* end = ptr + t.area();
+          while (ptr < end) {
+            PIXEL_T pix = zis->READ_PIXEL();
+            int len = 1;
+            int b;
+            do {
+              b = zis->readU8();
+              len += b;
+            } while (b == 255);
+
+            assert(len <= end - ptr);
+
+#ifdef FAVOUR_FILL_RECT
+            int i = ptr - buf;
+            ptr += len;
+
+            int runX = i % t.width();
+            int runY = i / t.width();
+
+            if (runX + len > t.width()) {
+              if (runX != 0) {
+                FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
+                          pix);
+                len -= t.width()-runX;
+                runX = 0;
+                runY++;
+              }
+
+              if (len > t.width()) {
+                FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
+                          pix);
+                runY += len / t.width();
+                len = len % t.width();
+              }
+            }
+
+            if (len != 0) {
+              FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
+            }
+#else
+            while (len-- > 0) *ptr++ = pix;
+#endif
+
+          }
+        } else {
+
+          // palette RLE
+
+          PIXEL_T* ptr = buf;
+          PIXEL_T* end = ptr + t.area();
+          while (ptr < end) {
+            int index = zis->readU8();
+            int len = 1;
+            if (index & 128) {
+              int b;
+              do {
+                b = zis->readU8();
+                len += b;
+              } while (b == 255);
+
+              assert(len <= end - ptr);
+            }
+
+            index &= 127;
+
+            PIXEL_T pix = palette[index];
+
+#ifdef FAVOUR_FILL_RECT
+            int i = ptr - buf;
+            ptr += len;
+
+            int runX = i % t.width();
+            int runY = i / t.width();
+
+            if (runX + len > t.width()) {
+              if (runX != 0) {
+                FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
+                          pix);
+                len -= t.width()-runX;
+                runX = 0;
+                runY++;
+              }
+
+              if (len > t.width()) {
+                FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
+                          pix);
+                runY += len / t.width();
+                len = len % t.width();
+              }
+            }
+
+            if (len != 0) {
+              FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
+            }
+#else
+            while (len-- > 0) *ptr++ = pix;
+#endif
+          }
+        }
+      }
+
+#ifndef FAVOUR_FILL_RECT
+      //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
+      //t.width(),t.height(),t.tl.x,t.tl.y);
+      IMAGE_RECT(t,buf);
+#endif
+    }
+  }
+
+  zis->reset();
+}
+
+#undef ZRLE_DECODE
+#undef READ_PIXEL
+#undef PIXEL_T
+}
diff --git a/common/rfb/zrleEncode.h b/common/rfb/zrleEncode.h
new file mode 100644
index 0000000..9b7263b
--- /dev/null
+++ b/common/rfb/zrleEncode.h
@@ -0,0 +1,328 @@
+/* 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.
+ */
+
+//
+// zrleEncode.h - zrle encoding function.
+//
+// This file is #included after having set the following macros:
+// BPP                - 8, 16 or 32
+// EXTRA_ARGS         - optional extra arguments
+// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
+//
+// Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+// bigger than the largest tile of pixel data, since the ZRLE encoding
+// algorithm writes to the position one past the end of the pixel data.
+//
+
+#include <rdr/OutStream.h>
+#include <rdr/ZlibOutStream.h>
+#include <assert.h>
+
+namespace rfb {
+
+// CONCAT2E concatenates its arguments, expanding them if they are macros
+
+#ifndef CONCAT2E
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,CPIXEL)
+#define ZRLE_ENCODE CONCAT2E(zrleEncode,CPIXEL)
+#define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,CPIXEL)
+#define BPPOUT 24
+#else
+#define PIXEL_T rdr::CONCAT2E(U,BPP)
+#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
+#define ZRLE_ENCODE CONCAT2E(zrleEncode,BPP)
+#define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,BPP)
+#define BPPOUT BPP
+#endif
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+static const int bitsPerPackedPixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+// The PaletteHelper class helps us build up the palette from pixel data by
+// storing a reverse index using a simple hash-table
+
+class PaletteHelper {
+public:
+  enum { MAX_SIZE = 127 };
+
+  PaletteHelper()
+  {
+    memset(index, 255, sizeof(index));
+    size = 0;
+  }
+
+  inline int hash(rdr::U32 pix)
+  {
+    return (pix ^ (pix >> 17)) & 4095;
+  }
+
+  inline void insert(rdr::U32 pix)
+  {
+    if (size < MAX_SIZE) {
+      int i = hash(pix);
+      while (index[i] != 255 && key[i] != pix)
+        i++;
+      if (index[i] != 255) return;
+
+      index[i] = size;
+      key[i] = pix;
+      palette[size] = pix;
+    }
+    size++;
+  }
+
+  inline int lookup(rdr::U32 pix)
+  {
+    assert(size <= MAX_SIZE);
+    int i = hash(pix);
+    while (index[i] != 255 && key[i] != pix)
+      i++;
+    if (index[i] != 255) return index[i];
+    return -1;
+  }
+
+  rdr::U32 palette[MAX_SIZE];
+  rdr::U8 index[4096+MAX_SIZE];
+  rdr::U32 key[4096+MAX_SIZE];
+  int size;
+};
+#endif
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os);
+
+bool ZRLE_ENCODE (const Rect& r, rdr::OutStream* os,
+                  rdr::ZlibOutStream* zos, void* buf, int maxLen, Rect* actual
+#ifdef EXTRA_ARGS
+                  , EXTRA_ARGS
+#endif
+                  )
+{
+  zos->setUnderlying(os);
+  // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block
+  int worstCaseLine = r.width() * 64 * (BPPOUT/8) + 1 + r.width() / 64;
+  // Zlib overhead is at worst 6 bytes plus 5 bytes per 32Kbyte block.
+  worstCaseLine += 11 + 5 * (worstCaseLine >> 15);
+  Rect t;
+
+  for (t.tl.y = r.tl.y; t.tl.y < 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)
+        throw Exception("ZRLE: not enough space for first line?");
+      actual->tl = r.tl;
+      actual->br.x = r.br.x;
+      actual->br.y = t.tl.y;
+      return false;
+    }
+
+    for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
+
+      GET_IMAGE_INTO_BUF(t,buf);
+
+      ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos);
+    }
+
+    zos->flush();
+  }
+  return true;
+}
+
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os)
+{
+  // First find the palette and the number of runs
+
+  PaletteHelper ph;
+
+  int runs = 0;
+  int singlePixels = 0;
+
+  PIXEL_T* ptr = data;
+  PIXEL_T* end = ptr + h * w;
+  *end = ~*(end-1); // one past the end is different so the while loop ends
+
+  while (ptr < end) {
+    PIXEL_T pix = *ptr;
+    if (*++ptr != pix) {
+      singlePixels++;
+    } else {
+      while (*++ptr == pix) ;
+      runs++;
+    }
+    ph.insert(pix);
+  }
+
+  //fprintf(stderr,"runs %d, single pixels %d, paletteSize %d\n",
+  //        runs, singlePixels, ph.size);
+
+  // Solid tile is a special case
+
+  if (ph.size == 1) {
+    os->writeU8(1);
+    os->WRITE_PIXEL(ph.palette[0]);
+    return;
+  }
+
+  // Try to work out whether to use RLE and/or a palette.  We do this by
+  // estimating the number of bytes which will be generated and picking the
+  // method which results in the fewest bytes.  Of course this may not result
+  // in the fewest bytes after compression...
+
+  bool useRle = false;
+  bool usePalette = false;
+
+  int estimatedBytes = w * h * (BPPOUT/8); // start assuming raw
+
+  int plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
+
+  if (plainRleBytes < estimatedBytes) {
+    useRle = true;
+    estimatedBytes = plainRleBytes;
+  }
+
+  if (ph.size < 128) {
+    int paletteRleBytes = (BPPOUT/8) * ph.size + 2 * runs + singlePixels;
+
+    if (paletteRleBytes < estimatedBytes) {
+      useRle = true;
+      usePalette = true;
+      estimatedBytes = paletteRleBytes;
+    }
+
+    if (ph.size < 17) {
+      int packedBytes = ((BPPOUT/8) * ph.size +
+                         w * h * bitsPerPackedPixel[ph.size-1] / 8);
+
+      if (packedBytes < estimatedBytes) {
+        useRle = false;
+        usePalette = true;
+        estimatedBytes = packedBytes;
+      }
+    }
+  }
+
+  if (!usePalette) ph.size = 0;
+
+  os->writeU8((useRle ? 128 : 0) | ph.size);
+
+  for (int i = 0; i < ph.size; i++) {
+    os->WRITE_PIXEL(ph.palette[i]);
+  }
+
+  if (useRle) {
+
+    PIXEL_T* ptr = data;
+    PIXEL_T* end = ptr + w * h;
+    PIXEL_T* runStart;
+    PIXEL_T pix;
+    while (ptr < end) {
+      runStart = ptr;
+      pix = *ptr++;
+      while (*ptr == pix && ptr < end)
+        ptr++;
+      int len = ptr - runStart;
+      if (len <= 2 && usePalette) {
+        int index = ph.lookup(pix);
+        if (len == 2)
+          os->writeU8(index);
+        os->writeU8(index);
+        continue;
+      }
+      if (usePalette) {
+        int index = ph.lookup(pix);
+        os->writeU8(index | 128);
+      } else {
+        os->WRITE_PIXEL(pix);
+      }
+      len -= 1;
+      while (len >= 255) {
+        os->writeU8(255);
+        len -= 255;
+      }
+      os->writeU8(len);
+    }
+
+  } else {
+
+    // no RLE
+
+    if (usePalette) {
+
+      // packed pixels
+
+      assert (ph.size < 17);
+
+      int bppp = bitsPerPackedPixel[ph.size-1];
+
+      PIXEL_T* ptr = data;
+
+      for (int i = 0; i < h; i++) {
+        rdr::U8 nbits = 0;
+        rdr::U8 byte = 0;
+
+        PIXEL_T* eol = ptr + w;
+
+        while (ptr < eol) {
+          PIXEL_T pix = *ptr++;
+          rdr::U8 index = ph.lookup(pix);
+          byte = (byte << bppp) | index;
+          nbits += bppp;
+          if (nbits >= 8) {
+            os->writeU8(byte);
+            nbits = 0;
+          }
+        }
+        if (nbits > 0) {
+          byte <<= 8 - nbits;
+          os->writeU8(byte);
+        }
+      }
+    } else {
+
+      // raw
+
+#ifdef CPIXEL
+      for (PIXEL_T* ptr = data; ptr < data+w*h; ptr++) {
+        os->WRITE_PIXEL(*ptr);
+      }
+#else
+      os->writeBytes(data, w*h*(BPP/8));
+#endif
+    }
+  }
+}
+
+#undef PIXEL_T
+#undef WRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef BPPOUT
+}