From 0fc57f2054f9e1b7d2efbe202fdaa4b8e39556f3 Mon Sep 17 00:00:00 2001
From: dscho <dscho>
Date: Sun, 27 Jul 2003 21:51:57 +0000
Subject: first alpha version of libvncclient

---
 libvncclient/Makefile    |   17 +
 libvncclient/corre.c     |   70 +++
 libvncclient/cursor.c    |  175 ++++++++
 libvncclient/hextile.c   |  120 ++++++
 libvncclient/listen.c    |   94 +++++
 libvncclient/rfbproto.c  | 1052 ++++++++++++++++++++++++++++++++++++++++++++++
 libvncclient/rre.c       |   68 +++
 libvncclient/sockets.c   |  424 +++++++++++++++++++
 libvncclient/tight.c     |  606 ++++++++++++++++++++++++++
 libvncclient/vncviewer.c |  240 +++++++++++
 libvncclient/zlib.c      |  158 +++++++
 rfb/rfbclient.h          |  186 ++++++++
 vncauth.c                |    2 +-
 13 files changed, 3211 insertions(+), 1 deletion(-)
 create mode 100644 libvncclient/Makefile
 create mode 100644 libvncclient/corre.c
 create mode 100644 libvncclient/cursor.c
 create mode 100644 libvncclient/hextile.c
 create mode 100644 libvncclient/listen.c
 create mode 100644 libvncclient/rfbproto.c
 create mode 100644 libvncclient/rre.c
 create mode 100644 libvncclient/sockets.c
 create mode 100644 libvncclient/tight.c
 create mode 100644 libvncclient/vncviewer.c
 create mode 100644 libvncclient/zlib.c
 create mode 100644 rfb/rfbclient.h

diff --git a/libvncclient/Makefile b/libvncclient/Makefile
new file mode 100644
index 0000000..026b5b2
--- /dev/null
+++ b/libvncclient/Makefile
@@ -0,0 +1,17 @@
+CFLAGS=-g -I.. -I. -Wall
+LDLIBS=-lz -ljpeg
+
+OBJS=cursor.o listen.o rfbproto.o sockets.o vncviewer.o ../libvncserver.a
+
+all: libvncclient.a
+
+rfbproto.o: rfbproto.c corre.c hextile.c rre.c tight.c zlib.c
+
+$(OBJS): ../rfb/rfbclient.h
+
+libvncclient.a: $(OBJS)
+	$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+
+clean:
+	rm *.o *.a
+
diff --git a/libvncclient/corre.c b/libvncclient/corre.c
new file mode 100644
index 0000000..d6d3d0d
--- /dev/null
+++ b/libvncclient/corre.c
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * corre.c - handle CoRRE encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles a CoRRE
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
+#define CARDBPP CONCAT3E(uint,BPP,_t)
+
+static Bool
+HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
+{
+    rfbRREHeader hdr;
+    int i;
+    CARDBPP pix;
+    uint8_t *ptr;
+    int x, y, w, h;
+
+    if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
+	return FALSE;
+
+    hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
+
+    if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
+	return FALSE;
+
+    FillRectangle(client, rx, ry, rw, rh, pix);
+
+    if (!ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8))))
+	return FALSE;
+
+    ptr = (uint8_t *)client->buffer;
+
+    for (i = 0; i < hdr.nSubrects; i++) {
+	pix = *(CARDBPP *)ptr;
+	ptr += BPP/8;
+	x = *ptr++;
+	y = *ptr++;
+	w = *ptr++;
+	h = *ptr++;
+
+	FillRectangle(client, rx+x, ry+y, w, h, pix);
+    }
+
+    return TRUE;
+}
+
+#undef CARDBPP
diff --git a/libvncclient/cursor.c b/libvncclient/cursor.c
new file mode 100644
index 0000000..f6a7816
--- /dev/null
+++ b/libvncclient/cursor.c
@@ -0,0 +1,175 @@
+/*
+ *  Copyright (C) 2001,2002 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.
+ */
+
+/*
+ * cursor.c - code to support cursor shape updates (XCursor and
+ * RichCursor preudo-encodings).
+ */
+
+#include <rfb/rfbclient.h>
+
+
+#define OPER_SAVE     0
+#define OPER_RESTORE  1
+
+#define RGB24_TO_PIXEL(bpp,r,g,b)                                       \
+   ((((uint##bpp##_t)(r) & 0xFF) * client->format.redMax + 127) / 255             \
+    << client->format.redShift |                                              \
+    (((uint##bpp##_t)(g) & 0xFF) * client->format.greenMax + 127) / 255           \
+    << client->format.greenShift |                                            \
+    (((uint##bpp##_t)(b) & 0xFF) * client->format.blueMax + 127) / 255            \
+    << client->format.blueShift)
+
+
+/*********************************************************************
+ * HandleCursorShape(). Support for XCursor and RichCursor shape
+ * updates. We emulate cursor operating on the frame buffer (that is
+ * why we call it "software cursor").
+ ********************************************************************/
+
+Bool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc)
+{
+  int bytesPerPixel;
+  size_t bytesPerRow, bytesMaskData;
+  rfbXCursorColors rgb;
+  uint32_t colors[2];
+  char *buf;
+  uint8_t *ptr;
+  int x, y, b;
+
+  bytesPerPixel = client->format.bitsPerPixel / 8;
+  bytesPerRow = (width + 7) / 8;
+  bytesMaskData = bytesPerRow * height;
+
+  if (width * height == 0)
+    return TRUE;
+
+  /* Allocate memory for pixel data and temporary mask data. */
+  if(client->rcSource)
+    free(client->rcSource);
+
+  client->rcSource = malloc(width * height * bytesPerPixel);
+  if (client->rcSource == NULL)
+    return FALSE;
+
+  buf = malloc(bytesMaskData);
+  if (buf == NULL) {
+    free(client->rcSource);
+    client->rcSource = NULL;
+    return FALSE;
+  }
+
+  /* Read and decode cursor pixel data, depending on the encoding type. */
+
+  if (enc == rfbEncodingXCursor) {
+    /* Read and convert background and foreground colors. */
+    if (!ReadFromRFBServer(client, (char *)&rgb, sz_rfbXCursorColors)) {
+      free(client->rcSource);
+      client->rcSource = NULL;
+      free(buf);
+      return FALSE;
+    }
+    colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
+    colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
+
+    /* Read 1bpp pixel data into a temporary buffer. */
+    if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
+      free(client->rcSource);
+      client->rcSource = NULL;
+      free(buf);
+      return FALSE;
+    }
+
+    /* Convert 1bpp data to byte-wide color indices. */
+    ptr = client->rcSource;
+    for (y = 0; y < height; y++) {
+      for (x = 0; x < width / 8; x++) {
+	for (b = 7; b >= 0; b--) {
+	  *ptr = buf[y * bytesPerRow + x] >> b & 1;
+	  ptr += bytesPerPixel;
+	}
+      }
+      for (b = 7; b > 7 - width % 8; b--) {
+	*ptr = buf[y * bytesPerRow + x] >> b & 1;
+	ptr += bytesPerPixel;
+      }
+    }
+
+    /* Convert indices into the actual pixel values. */
+    switch (bytesPerPixel) {
+    case 1:
+      for (x = 0; x < width * height; x++)
+	client->rcSource[x] = (uint8_t)colors[client->rcSource[x]];
+      break;
+    case 2:
+      for (x = 0; x < width * height; x++)
+	((uint16_t *)client->rcSource)[x] = (uint16_t)colors[client->rcSource[x * 2]];
+      break;
+    case 4:
+      for (x = 0; x < width * height; x++)
+	((uint32_t *)client->rcSource)[x] = colors[client->rcSource[x * 4]];
+      break;
+    }
+
+  } else {			/* enc == rfbEncodingRichCursor */
+
+    if (!ReadFromRFBServer(client, (char *)client->rcSource, width * height * bytesPerPixel)) {
+      free(client->rcSource);
+      client->rcSource = NULL;
+      free(buf);
+      return FALSE;
+    }
+
+  }
+
+  /* Read and decode mask data. */
+
+  if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
+    free(client->rcSource);
+    client->rcSource = NULL;
+    free(buf);
+    return FALSE;
+  }
+
+  client->rcMask = malloc(width * height);
+  if (client->rcMask == NULL) {
+    free(client->rcSource);
+    client->rcSource = NULL;
+    free(buf);
+    return FALSE;
+  }
+
+  ptr = client->rcMask;
+  for (y = 0; y < height; y++) {
+    for (x = 0; x < width / 8; x++) {
+      for (b = 7; b >= 0; b--) {
+	*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
+      }
+    }
+    for (b = 7; b > 7 - width % 8; b--) {
+      *ptr++ = buf[y * bytesPerRow + x] >> b & 1;
+    }
+  }
+
+  free(buf);
+
+  return TRUE;
+}
+
+
diff --git a/libvncclient/hextile.c b/libvncclient/hextile.c
new file mode 100644
index 0000000..e09fbc9
--- /dev/null
+++ b/libvncclient/hextile.c
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.c - handle hextile encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles a hextile
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
+#define CARDBPP CONCAT3E(uint,BPP,_t)
+#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
+
+static Bool
+HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
+{
+  CARDBPP bg, fg;
+  int i;
+  uint8_t *ptr;
+  int x, y, w, h;
+  int sx, sy, sw, sh;
+  uint8_t subencoding;
+  uint8_t nSubrects;
+
+  for (y = ry; y < ry+rh; y += 16) {
+    for (x = rx; x < rx+rw; x += 16) {
+      w = h = 16;
+      if (rx+rw - x < 16)
+	w = rx+rw - x;
+      if (ry+rh - y < 16)
+	h = ry+rh - y;
+
+      if (!ReadFromRFBServer(client, (char *)&subencoding, 1))
+	return FALSE;
+
+      if (subencoding & rfbHextileRaw) {
+	if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8)))
+	  return FALSE;
+
+	CopyRectangle(client, client->buffer, x, y, w, h);
+
+	continue;
+      }
+
+      if (subencoding & rfbHextileBackgroundSpecified)
+	if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg)))
+	  return FALSE;
+
+      FillRectangle(client, x, y, w, h, fg);
+
+      if (subencoding & rfbHextileForegroundSpecified)
+	if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg)))
+	  return FALSE;
+
+      if (!(subencoding & rfbHextileAnySubrects)) {
+	continue;
+      }
+
+      if (!ReadFromRFBServer(client, (char *)&nSubrects, 1))
+	return FALSE;
+
+      ptr = (uint8_t*)client->buffer;
+
+      if (subencoding & rfbHextileSubrectsColoured) {
+	if (!ReadFromRFBServer(client, client->buffer, nSubrects * (2 + (BPP / 8))))
+	  return FALSE;
+
+	for (i = 0; i < nSubrects; i++) {
+	  GET_PIXEL(fg, ptr);
+	  sx = rfbHextileExtractX(*ptr);
+	  sy = rfbHextileExtractY(*ptr);
+	  ptr++;
+	  sw = rfbHextileExtractW(*ptr);
+	  sh = rfbHextileExtractH(*ptr);
+	  ptr++;
+
+	  FillRectangle(client, x+sx, y+sy, sw, sh, fg);
+	}
+
+      } else {
+	if (!ReadFromRFBServer(client, client->buffer, nSubrects * 2))
+	  return FALSE;
+
+	for (i = 0; i < nSubrects; i++) {
+	  sx = rfbHextileExtractX(*ptr);
+	  sy = rfbHextileExtractY(*ptr);
+	  ptr++;
+	  sw = rfbHextileExtractW(*ptr);
+	  sh = rfbHextileExtractH(*ptr);
+	  ptr++;
+
+	  FillRectangle(client, x+sx, y+sy, sw, sh, fg);
+	}
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+#undef CARDBPP
diff --git a/libvncclient/listen.c b/libvncclient/listen.c
new file mode 100644
index 0000000..c11aef7
--- /dev/null
+++ b/libvncclient/listen.c
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * listen.c - listen for incoming connections
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <rfb/rfbclient.h>
+
+/*
+ * listenForIncomingConnections() - listen for incoming connections from
+ * servers, and fork a new process to deal with each connection.
+ */
+
+void
+listenForIncomingConnections(rfbClient* client)
+{
+  int listenSocket;
+  fd_set fds;
+
+  client->listenSpecified = TRUE;
+
+  listenSocket = ListenAtTcpPort(client->listenPort);
+
+  if ((listenSocket < 0)) exit(1);
+
+  fprintf(stderr,"%s -listen: Listening on port %d\n",
+	  client->programName,client->listenPort);
+  fprintf(stderr,"%s -listen: Command line errors are not reported until "
+	  "a connection comes in.\n", client->programName);
+
+  while (TRUE) {
+
+    /* reap any zombies */
+    int status, pid;
+    while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
+
+    /* TODO: callback for discard any events (like X11 events) */
+
+    FD_ZERO(&fds); 
+
+    FD_SET(listenSocket, &fds);
+
+    select(FD_SETSIZE, &fds, NULL, NULL, NULL);
+
+    if (FD_ISSET(listenSocket, &fds)) {
+      client->sock = AcceptTcpConnection(listenSocket);
+      if (client->sock < 0) exit(1);
+      if (!SetNonBlocking(client->sock)) exit(1);
+
+      /* Now fork off a new process to deal with it... */
+
+      switch (fork()) {
+
+      case -1: 
+	perror("fork"); 
+	exit(1);
+
+      case 0:
+	/* child - return to caller */
+	close(listenSocket);
+	return;
+
+      default:
+	/* parent - go round and listen again */
+	close(client->sock); 
+	break;
+      }
+    }
+  }
+}
+
+
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
new file mode 100644
index 0000000..e654fcc
--- /dev/null
+++ b/libvncclient/rfbproto.c
@@ -0,0 +1,1052 @@
+/*
+ *  Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * rfbproto.c - functions to deal with client side of RFB protocol.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <rfb/rfbclient.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+#ifdef HAVE_LIBJPEG
+#include <jpeglib.h>
+#endif
+
+void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) {
+  int i,j;
+
+#define FILL_RECT(BPP) \
+    for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \
+      for(i=x;i<x+w;i++) \
+	((uint##BPP##_t*)client->frameBuffer)[j+i]=colour;
+
+  switch(client->format.bitsPerPixel) {
+  case  8: FILL_RECT(8);  break;
+  case 16: FILL_RECT(16); break;
+  case 32: FILL_RECT(32); break;
+  default:
+    fprintf(stderr,"Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+  }
+}
+
+void CopyRectangle(rfbClient* client, uint8_t* buffer, int x, int y, int w, int h) {
+  int i,j;
+
+#define COPY_RECT(BPP) \
+  { \
+    uint##BPP##_t* _buffer=(uint##BPP##_t*)buffer; \
+    for(j=y*client->width;j<(y+h)*client->width;j+=client->width) { \
+      for(i=x;i<x+w;i++,_buffer++) \
+	((uint##BPP##_t*)client->frameBuffer)[j+i]=*_buffer; \
+    } \
+  }
+
+  switch(client->format.bitsPerPixel) {
+  case  8: COPY_RECT(8);  break;
+  case 16: COPY_RECT(16); break;
+  case 32: COPY_RECT(32); break;
+  default:
+    fprintf(stderr,"Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+  }
+}
+
+/* TODO: test */
+void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
+  int i,j;
+
+#define COPY_RECT_FROM_RECT(BPP) \
+  { \
+    uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \
+    for(j=dest_y*client->width;j<(dest_y+h)*client->width;j+=client->width) { \
+      for(i=dest_x;i<dest_x+w;i++) \
+	((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
+    } \
+  }
+
+  switch(client->format.bitsPerPixel) {
+  case  8: COPY_RECT_FROM_RECT(8);  break;
+  case 16: COPY_RECT_FROM_RECT(16); break;
+  case 32: COPY_RECT_FROM_RECT(32); break;
+  default:
+    fprintf(stderr,"Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
+  }
+}
+
+static Bool HandleRRE8(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleRRE16(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleRRE32(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleCoRRE8(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleCoRRE16(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleCoRRE32(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleHextile8(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleHextile16(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleHextile32(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleZlib8(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleZlib16(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleZlib32(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleTight8(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleTight16(rfbClient* client, int rx, int ry, int rw, int rh);
+static Bool HandleTight32(rfbClient* client, int rx, int ry, int rw, int rh);
+
+static long ReadCompactLen (rfbClient* client);
+
+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 JpegSetSrcManager(j_decompress_ptr cinfo, uint8_t *compressedData,
+                              int compressedLen);
+
+/* The zlib encoding requires expansion/decompression/deflation of the
+   compressed data in the "buffer" above into another, result buffer.
+   However, the size of the result buffer can be determined precisely
+   based on the bitsPerPixel, height and width of the rectangle.  We
+   allocate this buffer one time to be the full size of the buffer. */
+
+static int raw_buffer_size = -1;
+static char *raw_buffer;
+
+static z_stream decompStream;
+static Bool decompStreamInited = FALSE;
+
+
+/*
+ * Variables for the ``tight'' encoding implementation.
+ */
+
+/* Separate buffer for compressed data. */
+#define ZLIB_BUFFER_SIZE 512
+static char zlib_buffer[ZLIB_BUFFER_SIZE];
+
+/* Four independent compression streams for zlib library. */
+static z_stream zlibStream[4];
+static Bool zlibStreamActive[4] = {
+  FALSE, FALSE, FALSE, FALSE
+};
+
+/* Filter stuff. Should be initialized by filter initialization code. */
+static Bool cutZeros;
+static int rectWidth, rectColors;
+static char tightPalette[256*4];
+static uint8_t tightPrevRow[2048*3*sizeof(uint16_t)];
+
+/* JPEG decoder state. */
+static Bool jpegError;
+
+
+/*
+ * ConnectToRFBServer.
+ */
+
+Bool
+ConnectToRFBServer(rfbClient* client,const char *hostname, int port)
+{
+  unsigned int host;
+
+  if (!StringToIPAddr(hostname, &host)) {
+    fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
+    return FALSE;
+  }
+
+  client->sock = ConnectToTcpAddr(host, port);
+
+  if (client->sock < 0) {
+    fprintf(stderr,"Unable to connect to VNC server\n");
+    return FALSE;
+  }
+
+  return SetNonBlocking(client->sock);
+}
+
+static void rfbEncryptBytes(unsigned char *bytes, char *passwd);
+
+/*
+ * InitialiseRFBConnection.
+ */
+
+Bool
+InitialiseRFBConnection(rfbClient* client)
+{
+  rfbProtocolVersionMsg pv;
+  int major,minor;
+  uint32_t authScheme, reasonLen, authResult;
+  char *reason;
+  uint8_t challenge[CHALLENGESIZE];
+  char *passwd;
+  int i;
+  rfbClientInitMsg ci;
+
+  /* if the connection is immediately closed, don't report anything, so
+       that pmw's monitor can make test connections */
+
+  if (client->listenSpecified)
+    errorMessageOnReadFailure = FALSE;
+
+  if (!ReadFromRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE;
+
+  errorMessageOnReadFailure = TRUE;
+
+  pv[sz_rfbProtocolVersionMsg] = 0;
+
+  if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+    fprintf(stderr,"Not a valid VNC server\n");
+    return FALSE;
+  }
+
+  fprintf(stderr,"VNC server supports protocol version %d.%d (viewer %d.%d)\n",
+	  major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+  major = rfbProtocolMajorVersion;
+  minor = rfbProtocolMinorVersion;
+
+  sprintf(pv,rfbProtocolVersionFormat,major,minor);
+
+  if (!WriteExact(client, pv, sz_rfbProtocolVersionMsg)) return FALSE;
+
+  if (!ReadFromRFBServer(client, (char *)&authScheme, 4)) return FALSE;
+
+  authScheme = Swap32IfLE(authScheme);
+
+  switch (authScheme) {
+
+  case rfbConnFailed:
+    if (!ReadFromRFBServer(client, (char *)&reasonLen, 4)) return FALSE;
+    reasonLen = Swap32IfLE(reasonLen);
+
+    reason = malloc(reasonLen);
+
+    if (!ReadFromRFBServer(client, reason, reasonLen)) return FALSE;
+
+    fprintf(stderr,"VNC connection failed: %.*s\n",(int)reasonLen, reason);
+    return FALSE;
+
+  case rfbNoAuth:
+    fprintf(stderr,"No authentication needed\n");
+    break;
+
+  case rfbVncAuth:
+    if (!ReadFromRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE;
+
+    if (client->GetPassword)
+      passwd = client->GetPassword(client);
+
+    if ((!passwd) || (strlen(passwd) == 0)) {
+      fprintf(stderr,"Reading password failed\n");
+      return FALSE;
+    }
+    if (strlen(passwd) > 8) {
+      passwd[8] = '\0';
+    }
+
+    rfbEncryptBytes(challenge, passwd);
+
+	/* Lose the password from memory */
+    for (i = strlen(passwd); i >= 0; i--) {
+      passwd[i] = '\0';
+    }
+
+    if (!WriteExact(client, (char *)challenge, CHALLENGESIZE)) return FALSE;
+
+    if (!ReadFromRFBServer(client, (char *)&authResult, 4)) return FALSE;
+
+    authResult = Swap32IfLE(authResult);
+
+    switch (authResult) {
+    case rfbVncAuthOK:
+      fprintf(stderr,"VNC authentication succeeded\n");
+      break;
+    case rfbVncAuthFailed:
+      fprintf(stderr,"VNC authentication failed\n");
+      return FALSE;
+    case rfbVncAuthTooMany:
+      fprintf(stderr,"VNC authentication failed - too many tries\n");
+      return FALSE;
+    default:
+      fprintf(stderr,"Unknown VNC authentication result: %d\n",
+	      (int)authResult);
+      return FALSE;
+    }
+    break;
+
+  default:
+    fprintf(stderr,"Unknown authentication scheme from VNC server: %d\n",
+	    (int)authScheme);
+    return FALSE;
+  }
+
+  ci.shared = (client->appData.shareDesktop ? 1 : 0);
+
+  if (!WriteExact(client,  (char *)&ci, sz_rfbClientInitMsg)) return FALSE;
+
+  if (!ReadFromRFBServer(client, (char *)&client->si, sz_rfbServerInitMsg)) return FALSE;
+
+  client->si.framebufferWidth = Swap16IfLE(client->si.framebufferWidth);
+  client->si.framebufferHeight = Swap16IfLE(client->si.framebufferHeight);
+  client->si.format.redMax = Swap16IfLE(client->si.format.redMax);
+  client->si.format.greenMax = Swap16IfLE(client->si.format.greenMax);
+  client->si.format.blueMax = Swap16IfLE(client->si.format.blueMax);
+  client->si.nameLength = Swap32IfLE(client->si.nameLength);
+
+  client->desktopName = malloc(client->si.nameLength + 1);
+  if (!client->desktopName) {
+    fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
+            (unsigned long)client->si.nameLength);
+    return FALSE;
+  }
+
+  if (!ReadFromRFBServer(client, client->desktopName, client->si.nameLength)) return FALSE;
+
+  client->desktopName[client->si.nameLength] = 0;
+
+  fprintf(stderr,"Desktop name \"%s\"\n",client->desktopName);
+
+  fprintf(stderr,"Connected to VNC server, using protocol version %d.%d\n",
+	  rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+  fprintf(stderr,"VNC server default format:\n");
+  PrintPixelFormat(&client->si.format);
+
+  return TRUE;
+}
+
+
+/*
+ * SetFormatAndEncodings.
+ */
+
+Bool
+SetFormatAndEncodings(rfbClient* client)
+{
+  rfbSetPixelFormatMsg spf;
+  char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
+  rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
+  uint32_t *encs = (uint32_t *)(&buf[sz_rfbSetEncodingsMsg]);
+  int len = 0;
+  Bool requestCompressLevel = FALSE;
+  Bool requestQualityLevel = FALSE;
+  Bool requestLastRectEncoding = FALSE;
+
+  spf.type = rfbSetPixelFormat;
+  spf.format = client->format;
+  spf.format.redMax = Swap16IfLE(spf.format.redMax);
+  spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
+  spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
+
+  if (!WriteExact(client, (char *)&spf, sz_rfbSetPixelFormatMsg))
+    return FALSE;
+
+  se->type = rfbSetEncodings;
+  se->nEncodings = 0;
+
+  if (client->appData.encodingsString) {
+    const char *encStr = client->appData.encodingsString;
+    int encStrLen;
+    do {
+      const char *nextEncStr = strchr(encStr, ' ');
+      if (nextEncStr) {
+	encStrLen = nextEncStr - encStr;
+	nextEncStr++;
+      } else {
+	encStrLen = strlen(encStr);
+      }
+
+      if (strncasecmp(encStr,"raw",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+      } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+      } else if (strncasecmp(encStr,"tight",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+	requestLastRectEncoding = TRUE;
+	if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9)
+	  requestCompressLevel = TRUE;
+	if (client->appData.enableJPEG)
+	  requestQualityLevel = TRUE;
+      } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+      } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+	if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9)
+	  requestCompressLevel = TRUE;
+      } else if (strncasecmp(encStr,"corre",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
+      } else if (strncasecmp(encStr,"rre",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
+      } else {
+	fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr);
+      }
+
+      encStr = nextEncStr;
+    } while (encStr && se->nEncodings < MAX_ENCODINGS);
+
+    if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) {
+      encs[se->nEncodings++] = Swap32IfLE(client->appData.compressLevel +
+					  rfbEncodingCompressLevel0);
+    }
+
+    if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) {
+      if (client->appData.qualityLevel < 0 || client->appData.qualityLevel > 9)
+        client->appData.qualityLevel = 5;
+      encs[se->nEncodings++] = Swap32IfLE(client->appData.qualityLevel +
+					  rfbEncodingQualityLevel0);
+    }
+
+    if (client->appData.useRemoteCursor) {
+      if (se->nEncodings < MAX_ENCODINGS)
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
+      if (se->nEncodings < MAX_ENCODINGS)
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+      if (se->nEncodings < MAX_ENCODINGS)
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
+    }
+
+    if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+    }
+  }
+  else {
+    if (SameMachine(client->sock)) {
+      /* TODO:
+      if (!tunnelSpecified) {
+      */
+	fprintf(stderr,"Same machine: preferring raw encoding\n");
+	/* TODO: */
+	//encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+      /*
+      } else {
+	fprintf(stderr,"Tunneling active: preferring tight encoding\n");
+      }
+      */
+    }
+
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
+
+    if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9) {
+      encs[se->nEncodings++] = Swap32IfLE(client->appData.compressLevel +
+					  rfbEncodingCompressLevel0);
+    } else /* if (!tunnelSpecified) */ {
+      /* If -tunnel option was provided, we assume that server machine is
+	 not in the local network so we use default compression level for
+	 tight encoding instead of fast compression. Thus we are
+	 requesting level 1 compression only if tunneling is not used. */
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1);
+    }
+
+    if (client->appData.enableJPEG) {
+      if (client->appData.qualityLevel < 0 || client->appData.qualityLevel > 9)
+	client->appData.qualityLevel = 5;
+      encs[se->nEncodings++] = Swap32IfLE(client->appData.qualityLevel +
+					  rfbEncodingQualityLevel0);
+    }
+
+    if (client->appData.useRemoteCursor) {
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
+    }
+
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+  }
+
+  len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
+
+  se->nEncodings = Swap16IfLE(se->nEncodings);
+
+  if (!WriteExact(client, buf, len)) return FALSE;
+
+  return TRUE;
+}
+
+
+/*
+ * SendIncrementalFramebufferUpdateRequest.
+ */
+
+Bool
+SendIncrementalFramebufferUpdateRequest(rfbClient* client)
+{
+  return SendFramebufferUpdateRequest(client, 0, 0, client->si.framebufferWidth,
+				      client->si.framebufferHeight, TRUE);
+}
+
+
+/*
+ * SendFramebufferUpdateRequest.
+ */
+
+Bool
+SendFramebufferUpdateRequest(rfbClient* client, int x, int y, int w, int h, Bool incremental)
+{
+  rfbFramebufferUpdateRequestMsg fur;
+
+  fur.type = rfbFramebufferUpdateRequest;
+  fur.incremental = incremental ? 1 : 0;
+  fur.x = Swap16IfLE(x);
+  fur.y = Swap16IfLE(y);
+  fur.w = Swap16IfLE(w);
+  fur.h = Swap16IfLE(h);
+
+  if (!WriteExact(client, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/*
+ * SendPointerEvent.
+ */
+
+Bool
+SendPointerEvent(rfbClient* client,int x, int y, int buttonMask)
+{
+  rfbPointerEventMsg pe;
+
+  pe.type = rfbPointerEvent;
+  pe.buttonMask = buttonMask;
+  if (x < 0) x = 0;
+  if (y < 0) y = 0;
+
+  pe.x = Swap16IfLE(x);
+  pe.y = Swap16IfLE(y);
+  return WriteExact(client, (char *)&pe, sz_rfbPointerEventMsg);
+}
+
+
+/*
+ * SendKeyEvent.
+ */
+
+Bool
+SendKeyEvent(rfbClient* client, uint32_t key, Bool down)
+{
+  rfbKeyEventMsg ke;
+
+  ke.type = rfbKeyEvent;
+  ke.down = down ? 1 : 0;
+  ke.key = Swap32IfLE(key);
+  return WriteExact(client, (char *)&ke, sz_rfbKeyEventMsg);
+}
+
+
+/*
+ * SendClientCutText.
+ */
+
+Bool
+SendClientCutText(rfbClient* client, char *str, int len)
+{
+  rfbClientCutTextMsg cct;
+
+  if (client->serverCutText)
+    free(client->serverCutText);
+  client->serverCutText = NULL;
+
+  cct.type = rfbClientCutText;
+  cct.length = Swap32IfLE(len);
+  return  (WriteExact(client, (char *)&cct, sz_rfbClientCutTextMsg) &&
+	   WriteExact(client, str, len));
+}
+
+
+
+/*
+ * HandleRFBServerMessage.
+ */
+
+Bool
+HandleRFBServerMessage(rfbClient* client)
+{
+  rfbServerToClientMsg msg;
+
+  if (!ReadFromRFBServer(client, (char *)&msg, 1))
+    return FALSE;
+
+  switch (msg.type) {
+
+  case rfbSetColourMapEntries:
+  {
+    /* TODO:
+    int i;
+    uint16_t rgb[3];
+    XColor xc;
+
+    if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
+			   sz_rfbSetColourMapEntriesMsg - 1))
+      return FALSE;
+
+    msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
+    msg.scme.nColours = Swap16IfLE(msg.scme.nColours);
+
+    for (i = 0; i < msg.scme.nColours; i++) {
+      if (!ReadFromRFBServer(client, (char *)rgb, 6))
+	return FALSE;
+      xc.pixel = msg.scme.firstColour + i;
+      xc.red = Swap16IfLE(rgb[0]);
+      xc.green = Swap16IfLE(rgb[1]);
+      xc.blue = Swap16IfLE(rgb[2]);
+      xc.flags = DoRed|DoGreen|DoBlue;
+      XStoreColor(dpy, cmap, &xc);
+    }
+    */
+
+    break;
+  }
+
+  case rfbFramebufferUpdate:
+  {
+    rfbFramebufferUpdateRectHeader rect;
+    int linesToRead;
+    int bytesPerLine;
+    int i;
+
+    if (!ReadFromRFBServer(client, ((char *)&msg.fu) + 1,
+			   sz_rfbFramebufferUpdateMsg - 1))
+      return FALSE;
+
+    msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
+
+    for (i = 0; i < msg.fu.nRects; i++) {
+      if (!ReadFromRFBServer(client, (char *)&rect, sz_rfbFramebufferUpdateRectHeader))
+	return FALSE;
+
+      rect.encoding = Swap32IfLE(rect.encoding);
+      if (rect.encoding == rfbEncodingLastRect)
+	break;
+
+      rect.r.x = Swap16IfLE(rect.r.x);
+      rect.r.y = Swap16IfLE(rect.r.y);
+      rect.r.w = Swap16IfLE(rect.r.w);
+      rect.r.h = Swap16IfLE(rect.r.h);
+
+      if (rect.encoding == rfbEncodingXCursor ||
+	  rect.encoding == rfbEncodingRichCursor) {
+	if (!HandleCursorShape(client,
+			       rect.r.x, rect.r.y, rect.r.w, rect.r.h,
+			       rect.encoding)) {
+	  return FALSE;
+	}
+	continue;
+      }
+
+      if (rect.encoding == rfbEncodingPointerPos) {
+	if (!client->HandleCursorPos(client,rect.r.x, rect.r.y)) {
+	  return FALSE;
+	}
+	continue;
+      }
+
+      if ((rect.r.x + rect.r.w > client->si.framebufferWidth) ||
+	  (rect.r.y + rect.r.h > client->si.framebufferHeight))
+	{
+	  fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n",
+		  rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+	  return FALSE;
+	}
+
+      if (rect.r.h * rect.r.w == 0) {
+	fprintf(stderr,"Zero size rect - ignoring\n");
+	continue;
+      }
+
+      /* If RichCursor encoding is used, we should prevent collisions
+	 between framebuffer updates and cursor drawing operations. */
+      client->SoftCursorLockArea(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+
+      switch (rect.encoding) {
+
+      case rfbEncodingRaw:
+
+	bytesPerLine = rect.r.w * client->format.bitsPerPixel / 8;
+	linesToRead = BUFFER_SIZE / bytesPerLine;
+
+	while (rect.r.h > 0) {
+	  if (linesToRead > rect.r.h)
+	    linesToRead = rect.r.h;
+
+	  if (!ReadFromRFBServer(client, client->buffer,bytesPerLine * linesToRead))
+	    return FALSE;
+
+	  CopyRectangle(client, client->buffer,
+			   rect.r.x, rect.r.y, rect.r.w,linesToRead);
+
+	  rect.r.h -= linesToRead;
+	  rect.r.y += linesToRead;
+
+	}
+	break;
+
+      case rfbEncodingCopyRect:
+      {
+	rfbCopyRect cr;
+
+	if (!ReadFromRFBServer(client, (char *)&cr, sz_rfbCopyRect))
+	  return FALSE;
+
+	cr.srcX = Swap16IfLE(cr.srcX);
+	cr.srcY = Swap16IfLE(cr.srcY);
+
+	/* If RichCursor encoding is used, we should extend our
+	   "cursor lock area" (previously set to destination
+	   rectangle) to the source rectangle as well. */
+	client->SoftCursorLockArea(client,
+				   cr.srcX, cr.srcY, rect.r.w, rect.r.h);
+
+	CopyRectangleFromRectangle(client,
+				   cr.srcX, cr.srcY, rect.r.w, rect.r.h,
+				   rect.r.x, rect.r.y);
+
+	break;
+      }
+
+      case rfbEncodingRRE:
+      {
+	switch (client->format.bitsPerPixel) {
+	case 8:
+	  if (!HandleRRE8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 16:
+	  if (!HandleRRE16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 32:
+	  if (!HandleRRE32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	}
+	break;
+      }
+
+      case rfbEncodingCoRRE:
+      {
+	switch (client->format.bitsPerPixel) {
+	case 8:
+	  if (!HandleCoRRE8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 16:
+	  if (!HandleCoRRE16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 32:
+	  if (!HandleCoRRE32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	}
+	break;
+      }
+
+      case rfbEncodingHextile:
+      {
+	switch (client->format.bitsPerPixel) {
+	case 8:
+	  if (!HandleHextile8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 16:
+	  if (!HandleHextile16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 32:
+	  if (!HandleHextile32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	}
+	break;
+      }
+
+      case rfbEncodingZlib:
+      {
+	switch (client->format.bitsPerPixel) {
+	case 8:
+	  if (!HandleZlib8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 16:
+	  if (!HandleZlib16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 32:
+	  if (!HandleZlib32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	}
+	break;
+     }
+
+      case rfbEncodingTight:
+      {
+	switch (client->format.bitsPerPixel) {
+	case 8:
+	  if (!HandleTight8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 16:
+	  if (!HandleTight16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	case 32:
+	  if (!HandleTight32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+	    return FALSE;
+	  break;
+	}
+	break;
+      }
+
+      default:
+	fprintf(stderr,"Unknown rect encoding %d\n",
+		(int)rect.encoding);
+	return FALSE;
+      }
+
+      /* Now we may discard "soft cursor locks". */
+      client->SoftCursorUnlockScreen(client);
+
+      client->FramebufferUpdateReceived(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+    }
+
+#ifdef MITSHM
+    /* if using shared memory PutImage, make sure that the X server has
+       updated its framebuffer before we reuse the shared memory.  This is
+       mainly to avoid copyrect using invalid screen contents - not sure
+       if we'd need it otherwise. */
+
+    if (client->appData.useShm)
+      XSync(dpy, FALSE);
+#endif
+
+    if (!SendIncrementalFramebufferUpdateRequest(client))
+      return FALSE;
+
+    break;
+  }
+
+  case rfbBell:
+  {
+    client->Bell(client);
+
+    break;
+  }
+
+  case rfbServerCutText:
+  {
+    if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
+			   sz_rfbServerCutTextMsg - 1))
+      return FALSE;
+
+    msg.sct.length = Swap32IfLE(msg.sct.length);
+
+    if (client->serverCutText)
+      free(client->serverCutText);
+
+    client->serverCutText = malloc(msg.sct.length+1);
+
+    if (!ReadFromRFBServer(client, client->serverCutText, msg.sct.length))
+      return FALSE;
+
+    client->serverCutText[msg.sct.length] = 0;
+
+    client->newServerCutText = TRUE;
+
+    break;
+  }
+
+  default:
+    fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++)
+
+#define GET_PIXEL16(pix, ptr) (((uint8_t*)&(pix))[0] = *(ptr)++, \
+			       ((uint8_t*)&(pix))[1] = *(ptr)++)
+
+#define GET_PIXEL32(pix, ptr) (((uint8_t*)&(pix))[0] = *(ptr)++, \
+			       ((uint8_t*)&(pix))[1] = *(ptr)++, \
+			       ((uint8_t*)&(pix))[2] = *(ptr)++, \
+			       ((uint8_t*)&(pix))[3] = *(ptr)++)
+
+/* CONCAT2 concatenates its two arguments.  CONCAT2E does the same but also
+   expands its arguments if they are macros */
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT3(a,b,c) a##b##c
+#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
+
+#define BPP 8
+#include "rre.c"
+#include "corre.c"
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+#define BPP 16
+#include "rre.c"
+#include "corre.c"
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+#define BPP 32
+#include "rre.c"
+#include "corre.c"
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+
+
+/*
+ * PrintPixelFormat.
+ */
+
+void
+PrintPixelFormat(format)
+    rfbPixelFormat *format;
+{
+  if (format->bitsPerPixel == 1) {
+    fprintf(stderr,"  Single bit per pixel.\n");
+    fprintf(stderr,
+	    "  %s significant bit in each byte is leftmost on the screen.\n",
+	    (format->bigEndian ? "Most" : "Least"));
+  } else {
+    fprintf(stderr,"  %d bits per pixel.\n",format->bitsPerPixel);
+    if (format->bitsPerPixel != 8) {
+      fprintf(stderr,"  %s significant byte first in each pixel.\n",
+	      (format->bigEndian ? "Most" : "Least"));
+    }
+    if (format->trueColour) {
+      fprintf(stderr,"  TRUE colour: max red %d green %d blue %d",
+	      format->redMax, format->greenMax, format->blueMax);
+      fprintf(stderr,", shift red %d green %d blue %d\n",
+	      format->redShift, format->greenShift, format->blueShift);
+    } else {
+      fprintf(stderr,"  Colour map (not true colour).\n");
+    }
+  }
+}
+
+static long
+ReadCompactLen (rfbClient* client)
+{
+  long len;
+  uint8_t b;
+
+  if (!ReadFromRFBServer(client, (char *)&b, 1))
+    return -1;
+  len = (int)b & 0x7F;
+  if (b & 0x80) {
+    if (!ReadFromRFBServer(client, (char *)&b, 1))
+      return -1;
+    len |= ((int)b & 0x7F) << 7;
+    if (b & 0x80) {
+      if (!ReadFromRFBServer(client, (char *)&b, 1))
+	return -1;
+      len |= ((int)b & 0xFF) << 14;
+    }
+  }
+  return len;
+}
+
+/*
+ * JPEG source manager functions for JPEG decompression in Tight decoder.
+ */
+
+static struct jpeg_source_mgr jpegSrcManager;
+static JOCTET *jpegBufferPtr;
+static size_t jpegBufferLen;
+
+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 || 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, uint8_t *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;
+}
+
+/* avoid name clashes with LibVNCServer */
+
+#define vncEncryptBytes rfbEncryptBytes
+#define vncEncryptAndStorePasswd rfbEncryptAndStorePasswdUnused
+#define vncDecryptPasswdFromFile rfbDecryptPasswdFromFileUnused
+#define vncRandomBytes rfbRandomBytesUnused
+
+#include "../vncauth.c"
+#include "../d3des.c"
diff --git a/libvncclient/rre.c b/libvncclient/rre.c
new file mode 100644
index 0000000..fba3767
--- /dev/null
+++ b/libvncclient/rre.c
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.c - handle RRE encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles an RRE
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
+#define CARDBPP CONCAT3E(uint,BPP,_t)
+
+static Bool
+HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
+{
+  rfbRREHeader hdr;
+  int i;
+  CARDBPP pix;
+  rfbRectangle subrect;
+
+  if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
+    return FALSE;
+
+  hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
+
+  if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
+    return FALSE;
+
+  FillRectangle(client, rx, ry, rw, rh, pix);
+
+  for (i = 0; i < hdr.nSubrects; i++) {
+    if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
+      return FALSE;
+
+    if (!ReadFromRFBServer(client, (char *)&subrect, sz_rfbRectangle))
+      return FALSE;
+
+    subrect.x = Swap16IfLE(subrect.x);
+    subrect.y = Swap16IfLE(subrect.y);
+    subrect.w = Swap16IfLE(subrect.w);
+    subrect.h = Swap16IfLE(subrect.h);
+
+    FillRectangle(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
+  }
+
+  return TRUE;
+}
+
+#undef CARDBPP
diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c
new file mode 100644
index 0000000..5e6cd69
--- /dev/null
+++ b/libvncclient/sockets.c
@@ -0,0 +1,424 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * sockets.c - functions to deal with sockets.
+ */
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <rfb/rfbclient.h>
+
+void PrintInHex(char *buf, int len);
+
+Bool errorMessageOnReadFailure = TRUE;
+
+#define BUF_SIZE 8192
+static char buf[BUF_SIZE];
+static char *bufoutptr = buf;
+static int buffered = 0;
+
+/*
+ * ReadFromRFBServer is called whenever we want to read some data from the RFB
+ * server.  It is non-trivial for two reasons:
+ *
+ * 1. For efficiency it performs some intelligent buffering, avoiding invoking
+ *    the read() system call too often.  For small chunks of data, it simply
+ *    copies the data out of an internal buffer.  For large amounts of data it
+ *    reads directly into the buffer provided by the caller.
+ *
+ * 2. Whenever read() would block, it invokes the Xt event dispatching
+ *    mechanism to process X events.  In fact, this is the only place these
+ *    events are processed, as there is no XtAppMainLoop in the program.
+ */
+
+Bool
+ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
+{
+  if (n <= buffered) {
+    memcpy(out, bufoutptr, n);
+    bufoutptr += n;
+    buffered -= n;
+    return TRUE;
+  }
+
+  memcpy(out, bufoutptr, buffered);
+
+  out += buffered;
+  n -= buffered;
+
+  bufoutptr = buf;
+  buffered = 0;
+
+  if (n <= BUF_SIZE) {
+
+    while (buffered < n) {
+      int i = read(client->sock, buf + buffered, BUF_SIZE - buffered);
+      if (i <= 0) {
+	if (i < 0) {
+	  if (errno == EWOULDBLOCK || errno == EAGAIN) {
+	    /* TODO:
+	       ProcessXtEvents();
+	    */
+	    i = 0;
+	  } else {
+	    perror("read");
+	    return FALSE;
+	  }
+	} else {
+	  if (errorMessageOnReadFailure) {
+	    fprintf(stderr,"VNC server closed connection\n");
+	  }
+	  return FALSE;
+	}
+      }
+      buffered += i;
+    }
+
+    memcpy(out, bufoutptr, n);
+    bufoutptr += n;
+    buffered -= n;
+    return TRUE;
+
+  } else {
+
+    while (n > 0) {
+      int i = read(client->sock, out, n);
+      if (i <= 0) {
+	if (i < 0) {
+	  if (errno == EWOULDBLOCK || errno == EAGAIN) {
+	    /* TODO:
+	       ProcessXtEvents();
+	    */
+	    i = 0;
+	  } else {
+	    perror("read");
+	    return FALSE;
+	  }
+	} else {
+	  if (errorMessageOnReadFailure) {
+	    fprintf(stderr,"VNC server closed connection\n");
+	  }
+	  return FALSE;
+	}
+      }
+      out += i;
+      n -= i;
+    }
+
+    return TRUE;
+  }
+}
+
+
+/*
+ * Write an exact number of bytes, and don't return until you've sent them.
+ */
+
+Bool
+WriteExact(rfbClient* client, char *buf, int n)
+{
+  fd_set fds;
+  int i = 0;
+  int j;
+
+  while (i < n) {
+    j = write(client->sock, buf + i, (n - i));
+    if (j <= 0) {
+      if (j < 0) {
+	if (errno == EWOULDBLOCK || errno == EAGAIN) {
+	  FD_ZERO(&fds);
+	  FD_SET(client->sock,&fds);
+
+	  if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) {
+	    perror("select");
+	    return FALSE;
+	  }
+	  j = 0;
+	} else {
+	  perror("write");
+	  return FALSE;
+	}
+      } else {
+	fprintf(stderr,"write failed\n");
+	return FALSE;
+      }
+    }
+    i += j;
+  }
+  return TRUE;
+}
+
+
+/*
+ * ConnectToTcpAddr connects to the given TCP port.
+ */
+
+int
+ConnectToTcpAddr(unsigned int host, int port)
+{
+  int sock;
+  struct sockaddr_in addr;
+  int one = 1;
+
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(port);
+  addr.sin_addr.s_addr = host;
+
+  sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    perror("ConnectToTcpAddr: socket");
+    return -1;
+  }
+
+  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("ConnectToTcpAddr: connect");
+    close(sock);
+    return -1;
+  }
+
+  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		 (char *)&one, sizeof(one)) < 0) {
+    perror("ConnectToTcpAddr: setsockopt");
+    close(sock);
+    return -1;
+  }
+
+  return sock;
+}
+
+
+
+/*
+ * FindFreeTcpPort tries to find unused TCP port in the range
+ * (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure.
+ */
+
+int
+FindFreeTcpPort(void)
+{
+  int sock, port;
+  struct sockaddr_in addr;
+
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    perror(": FindFreeTcpPort: socket");
+    return 0;
+  }
+
+  for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
+    addr.sin_port = htons((unsigned short)port);
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+      close(sock);
+      return port;
+    }
+  }
+
+  close(sock);
+  return 0;
+}
+
+
+/*
+ * ListenAtTcpPort starts listening at the given TCP port.
+ */
+
+int
+ListenAtTcpPort(int port)
+{
+  int sock;
+  struct sockaddr_in addr;
+  int one = 1;
+
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons(port);
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    perror("ListenAtTcpPort: socket");
+    return -1;
+  }
+
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		 (const char *)&one, sizeof(one)) < 0) {
+    perror("ListenAtTcpPort: setsockopt");
+    close(sock);
+    return -1;
+  }
+
+  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    perror("ListenAtTcpPort: bind");
+    close(sock);
+    return -1;
+  }
+
+  if (listen(sock, 5) < 0) {
+    perror("ListenAtTcpPort: listen");
+    close(sock);
+    return -1;
+  }
+
+  return sock;
+}
+
+
+/*
+ * AcceptTcpConnection accepts a TCP connection.
+ */
+
+int
+AcceptTcpConnection(int listenSock)
+{
+  int sock;
+  struct sockaddr_in addr;
+  int addrlen = sizeof(addr);
+  int one = 1;
+
+  sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
+  if (sock < 0) {
+    perror("AcceptTcpConnection: accept");
+    return -1;
+  }
+
+  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		 (char *)&one, sizeof(one)) < 0) {
+    perror("AcceptTcpConnection: setsockopt");
+    close(sock);
+    return -1;
+  }
+
+  return sock;
+}
+
+
+/*
+ * SetNonBlocking sets a socket into non-blocking mode.
+ */
+
+Bool
+SetNonBlocking(int sock)
+{
+  if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+    perror("AcceptTcpConnection: fcntl");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/*
+ * StringToIPAddr - convert a host string to an IP address.
+ */
+
+Bool
+StringToIPAddr(const char *str, unsigned int *addr)
+{
+  struct hostent *hp;
+
+  if (strcmp(str,"") == 0) {
+    *addr = 0; /* local */
+    return TRUE;
+  }
+
+  *addr = inet_addr(str);
+
+  if (*addr != -1)
+    return TRUE;
+
+  hp = gethostbyname(str);
+
+  if (hp) {
+    *addr = *(unsigned int *)hp->h_addr;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+/*
+ * Test if the other end of a socket is on the same machine.
+ */
+
+Bool
+SameMachine(int sock)
+{
+  struct sockaddr_in peeraddr, myaddr;
+  int addrlen = sizeof(struct sockaddr_in);
+
+  getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
+  getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
+
+  return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
+}
+
+
+/*
+ * Print out the contents of a packet for debugging.
+ */
+
+void
+PrintInHex(char *buf, int len)
+{
+  int i, j;
+  char c, str[17];
+
+  str[16] = 0;
+
+  fprintf(stderr,"ReadExact: ");
+
+  for (i = 0; i < len; i++)
+    {
+      if ((i % 16 == 0) && (i != 0)) {
+	fprintf(stderr,"           ");
+      }
+      c = buf[i];
+      str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
+      fprintf(stderr,"%02x ",(unsigned char)c);
+      if ((i % 4) == 3)
+	fprintf(stderr," ");
+      if ((i % 16) == 15)
+	{
+	  fprintf(stderr,"%s\n",str);
+	}
+    }
+  if ((i % 16) != 0)
+    {
+      for (j = i % 16; j < 16; j++)
+	{
+	  fprintf(stderr,"   ");
+	  if ((j % 4) == 3) fprintf(stderr," ");
+	}
+      str[i % 16] = 0;
+      fprintf(stderr,"%s\n",str);
+    }
+
+  fflush(stderr);
+}
diff --git a/libvncclient/tight.c b/libvncclient/tight.c
new file mode 100644
index 0000000..c858392
--- /dev/null
+++ b/libvncclient/tight.c
@@ -0,0 +1,606 @@
+/*
+ *  Copyright (C) 2000, 2001 Const 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.
+ */
+
+/*
+ * tight.c - handle ``tight'' encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple
+ * times by rfbproto.c, each time with a different definition of the
+ * macro BPP. For each value of BPP, this file defines a function
+ * which handles a tight-encoded rectangle with BPP bits per pixel.
+ *
+ */
+
+#define TIGHT_MIN_TO_COMPRESS 12
+
+#define CARDBPP CONCAT3E(uint,BPP,_t)
+#define filterPtrBPP CONCAT2E(filterPtr,BPP)
+
+#define HandleTightBPP CONCAT2E(HandleTight,BPP)
+#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
+#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
+#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
+#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
+#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
+#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
+
+#if BPP != 8
+#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
+#endif
+
+#ifndef RGB_TO_PIXEL
+
+#define RGB_TO_PIXEL(bpp,r,g,b)						\
+  (((CARD##bpp)(r) & client->format.redMax) << client->format.redShift |		\
+   ((CARD##bpp)(g) & client->format.greenMax) << client->format.greenShift |	\
+   ((CARD##bpp)(b) & client->format.blueMax) << client->format.blueShift)
+
+#define RGB24_TO_PIXEL(bpp,r,g,b)                                       \
+   ((((CARD##bpp)(r) & 0xFF) * client->format.redMax + 127) / 255             \
+    << client->format.redShift |                                              \
+    (((CARD##bpp)(g) & 0xFF) * client->format.greenMax + 127) / 255           \
+    << client->format.greenShift |                                            \
+    (((CARD##bpp)(b) & 0xFF) * client->format.blueMax + 127) / 255            \
+    << client->format.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b)						\
+  (((uint32_t)(r) & 0xFF) << client->format.redShift |				\
+   ((uint32_t)(g) & 0xFF) << client->format.greenShift |			\
+   ((uint32_t)(b) & 0xFF) << client->format.blueShift)
+
+#endif
+
+/* Type declarations */
+
+typedef void (*filterPtrBPP)(rfbClient* client, int, CARDBPP *);
+
+/* Prototypes */
+
+static int InitFilterCopyBPP (rfbClient* client, int rw, int rh);
+static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh);
+static int InitFilterGradientBPP (rfbClient* client, int rw, int rh);
+static void FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
+static void FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
+static void FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
+
+#if BPP != 8
+static Bool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h);
+#endif
+
+/* Definitions */
+
+static Bool
+HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
+{
+  CARDBPP fill_colour;
+  uint8_t comp_ctl;
+  uint8_t filter_id;
+  filterPtrBPP filterFn;
+  z_streamp zs;
+  char *buffer2;
+  int err, stream_id, compressedLen, bitsPixel;
+  int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
+
+  if (!ReadFromRFBServer(client, (char *)&comp_ctl, 1))
+    return FALSE;
+
+  /* Flush zlib streams if we are told by the server to do so. */
+  for (stream_id = 0; stream_id < 4; stream_id++) {
+    if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
+      if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
+	  zlibStream[stream_id].msg != NULL)
+	fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
+      zlibStreamActive[stream_id] = FALSE;
+    }
+    comp_ctl >>= 1;
+  }
+
+  /* Handle solid rectangles. */
+  if (comp_ctl == rfbTightFill) {
+#if BPP == 32
+    if (client->format.depth == 24 && client->format.redMax == 0xFF &&
+	client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
+      if (!ReadFromRFBServer(client, client->buffer, 3))
+	return FALSE;
+      fill_colour = RGB24_TO_PIXEL32(client->buffer[0], client->buffer[1], client->buffer[2]);
+    } else {
+      if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
+	return FALSE;
+    }
+#else
+    if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
+	return FALSE;
+#endif
+
+    FillRectangle(client, rx, ry, rw, rh, fill_colour);
+
+    return TRUE;
+  }
+
+#if BPP == 8
+  if (comp_ctl == rfbTightJpeg) {
+    fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
+    return FALSE;
+  }
+#else
+  if (comp_ctl == rfbTightJpeg) {
+    return DecompressJpegRectBPP(client, rx, ry, rw, rh);
+  }
+#endif
+
+  /* Quit on unsupported subencoding value. */
+  if (comp_ctl > rfbTightMaxSubencoding) {
+    fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
+    return FALSE;
+  }
+
+  /*
+   * Here primary compression mode handling begins.
+   * Data was processed with optional filter + zlib compression.
+   */
+
+  /* First, we should identify a filter to use. */
+  if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+    if (!ReadFromRFBServer(client, (char*)&filter_id, 1))
+      return FALSE;
+
+    switch (filter_id) {
+    case rfbTightFilterCopy:
+      filterFn = FilterCopyBPP;
+      bitsPixel = InitFilterCopyBPP(client, rw, rh);
+      break;
+    case rfbTightFilterPalette:
+      filterFn = FilterPaletteBPP;
+      bitsPixel = InitFilterPaletteBPP(client, rw, rh);
+      break;
+    case rfbTightFilterGradient:
+      filterFn = FilterGradientBPP;
+      bitsPixel = InitFilterGradientBPP(client, rw, rh);
+      break;
+    default:
+      fprintf(stderr, "Tight encoding: unknown filter code received.\n");
+      return FALSE;
+    }
+  } else {
+    filterFn = FilterCopyBPP;
+    bitsPixel = InitFilterCopyBPP(client, rw, rh);
+  }
+  if (bitsPixel == 0) {
+    fprintf(stderr, "Tight encoding: error receiving palette.\n");
+    return FALSE;
+  }
+
+  /* Determine if the data should be decompressed or just copied. */
+  rowSize = (rw * bitsPixel + 7) / 8;
+  if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
+    if (!ReadFromRFBServer(client, (char*)client->buffer, rh * rowSize))
+      return FALSE;
+
+    buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4];
+    filterFn(client, rh, (CARDBPP *)buffer2);
+
+    CopyRectangle(client, buffer2, rx, ry, rw, rh);
+
+    return TRUE;
+  }
+
+  /* Read the length (1..3 bytes) of compressed data following. */
+  compressedLen = (int)ReadCompactLen(client);
+  if (compressedLen <= 0) {
+    fprintf(stderr, "Incorrect data received from the server.\n");
+    return FALSE;
+  }
+
+  /* Now let's initialize compression stream if needed. */
+  stream_id = comp_ctl & 0x03;
+  zs = &zlibStream[stream_id];
+  if (!zlibStreamActive[stream_id]) {
+    zs->zalloc = Z_NULL;
+    zs->zfree = Z_NULL;
+    zs->opaque = Z_NULL;
+    err = inflateInit(zs);
+    if (err != Z_OK) {
+      if (zs->msg != NULL)
+	fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
+      return FALSE;
+    }
+    zlibStreamActive[stream_id] = TRUE;
+  }
+
+  /* Read, decode and draw actual pixel data in a loop. */
+
+  bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
+  buffer2 = &client->buffer[bufferSize];
+  if (rowSize > bufferSize) {
+    /* Should be impossible when BUFFER_SIZE >= 16384 */
+    fprintf(stderr, "Internal error: incorrect buffer size.\n");
+    return FALSE;
+  }
+
+  rowsProcessed = 0;
+  extraBytes = 0;
+
+  while (compressedLen > 0) {
+    if (compressedLen > ZLIB_BUFFER_SIZE)
+      portionLen = ZLIB_BUFFER_SIZE;
+    else
+      portionLen = compressedLen;
+
+    if (!ReadFromRFBServer(client, (char*)zlib_buffer, portionLen))
+      return FALSE;
+
+    compressedLen -= portionLen;
+
+    zs->next_in = (Bytef *)zlib_buffer;
+    zs->avail_in = portionLen;
+
+    do {
+      zs->next_out = (Bytef *)&client->buffer[extraBytes];
+      zs->avail_out = bufferSize - extraBytes;
+
+      err = inflate(zs, Z_SYNC_FLUSH);
+      if (err == Z_BUF_ERROR)   /* Input exhausted -- no problem. */
+	break;
+      if (err != Z_OK && err != Z_STREAM_END) {
+	if (zs->msg != NULL) {
+	  fprintf(stderr, "Inflate error: %s.\n", zs->msg);
+	} else {
+	  fprintf(stderr, "Inflate error: %d.\n", err);
+	}
+	return FALSE;
+      }
+
+      numRows = (bufferSize - zs->avail_out) / rowSize;
+
+      filterFn(client, numRows, (CARDBPP *)buffer2);
+
+      extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
+      if (extraBytes > 0)
+	memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes);
+
+      CopyRectangle(client, buffer2, rx, ry+rowsProcessed, rw, numRows);
+
+      rowsProcessed += numRows;
+    }
+    while (zs->avail_out == 0);
+  }
+
+  if (rowsProcessed != rh) {
+    fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ *
+ * Filter stuff.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool cutZeros;
+     static int rectWidth, rectColors;
+     static uint8_t tightPalette[256*4];
+     static uint8_t tightPrevRow[2048*3*sizeof(CARD16)];
+*/
+
+static int
+InitFilterCopyBPP (rfbClient* client, int rw, int rh)
+{
+  rectWidth = rw;
+
+#if BPP == 32
+  if (client->format.depth == 24 && client->format.redMax == 0xFF &&
+      client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
+    cutZeros = TRUE;
+    return 24;
+  } else {
+    cutZeros = FALSE;
+  }
+#endif
+
+  return BPP;
+}
+
+static void
+FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *dst)
+{
+
+#if BPP == 32
+  int x, y;
+
+  if (cutZeros) {
+    for (y = 0; y < numRows; y++) {
+      for (x = 0; x < rectWidth; x++) {
+	dst[y*rectWidth+x] =
+	  RGB24_TO_PIXEL32(client->buffer[(y*rectWidth+x)*3],
+			   client->buffer[(y*rectWidth+x)*3+1],
+			   client->buffer[(y*rectWidth+x)*3+2]);
+      }
+    }
+    return;
+  }
+#endif
+
+  memcpy (dst, client->buffer, numRows * rectWidth * (BPP / 8));
+}
+
+static int
+InitFilterGradientBPP (rfbClient* client, int rw, int rh)
+{
+  int bits;
+
+  bits = InitFilterCopyBPP(client, rw, rh);
+  if (cutZeros)
+    memset(tightPrevRow, 0, rw * 3);
+  else
+    memset(tightPrevRow, 0, rw * 3 * sizeof(uint16_t));
+
+  return bits;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24 (rfbClient* client, int numRows, uint32_t *dst)
+{
+  int x, y, c;
+  uint8_t thisRow[2048*3];
+  uint8_t pix[3];
+  int est[3];
+
+  for (y = 0; y < numRows; y++) {
+
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = tightPrevRow[c] + client->buffer[y*rectWidth*3+c];
+      thisRow[c] = pix[c];
+    }
+    dst[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] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
+		 (int)tightPrevRow[(x-1)*3+c];
+	if (est[c] > 0xFF) {
+	  est[c] = 0xFF;
+	} else if (est[c] < 0x00) {
+	  est[c] = 0x00;
+	}
+	pix[c] = (uint8_t)est[c] + client->buffer[(y*rectWidth+x)*3+c];
+	thisRow[x*3+c] = pix[c];
+      }
+      dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(tightPrevRow, thisRow, rectWidth * 3);
+  }
+}
+
+#endif
+
+static void
+FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *dst)
+{
+  int x, y, c;
+  CARDBPP *src = (CARDBPP *)client->buffer;
+  uint16_t *thatRow = (uint16_t *)tightPrevRow;
+  uint16_t thisRow[2048*3];
+  uint16_t pix[3];
+  uint16_t max[3];
+  int shift[3];
+  int est[3];
+
+#if BPP == 32
+  if (cutZeros) {
+    FilterGradient24(client, numRows, dst);
+    return;
+  }
+#endif
+
+  max[0] = client->format.redMax;
+  max[1] = client->format.greenMax;
+  max[2] = client->format.blueMax;
+
+  shift[0] = client->format.redShift;
+  shift[1] = client->format.greenShift;
+  shift[2] = client->format.blueShift;
+
+  for (y = 0; y < numRows; y++) {
+
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = (uint16_t)(((src[y*rectWidth] >> shift[c]) + thatRow[c]) & max[c]);
+      thisRow[c] = pix[c];
+    }
+    dst[y*rectWidth] = RGB_TO_PIXEL(BPP, 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] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
+	if (est[c] > (int)max[c]) {
+	  est[c] = (int)max[c];
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = (uint16_t)(((src[y*rectWidth+x] >> shift[c]) + est[c]) & max[c]);
+	thisRow[x*3+c] = pix[c];
+      }
+      dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+    }
+    memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(uint16_t));
+  }
+}
+
+static int
+InitFilterPaletteBPP (rfbClient* client, int rw, int rh)
+{
+  uint8_t numColors;
+#if BPP == 32
+  int i;
+  CARDBPP *palette = (CARDBPP *)tightPalette;
+#endif
+
+  rectWidth = rw;
+
+  if (!ReadFromRFBServer(client, (char*)&numColors, 1))
+    return 0;
+
+  rectColors = (int)numColors;
+  if (++rectColors < 2)
+    return 0;
+
+#if BPP == 32
+  if (client->format.depth == 24 && client->format.redMax == 0xFF &&
+      client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
+    if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * 3))
+      return 0;
+    for (i = rectColors - 1; i >= 0; i--) {
+      palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+				    tightPalette[i*3+1],
+				    tightPalette[i*3+2]);
+    }
+    return (rectColors == 2) ? 1 : 8;
+  }
+#endif
+
+  if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * (BPP / 8)))
+    return 0;
+
+  return (rectColors == 2) ? 1 : 8;
+}
+
+static void
+FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *dst)
+{
+  int x, y, b, w;
+  uint8_t *src = (uint8_t *)client->buffer;
+  CARDBPP *palette = (CARDBPP *)tightPalette;
+
+  if (rectColors == 2) {
+    w = (rectWidth + 7) / 8;
+    for (y = 0; y < numRows; y++) {
+      for (x = 0; x < rectWidth / 8; x++) {
+	for (b = 7; b >= 0; b--)
+	  dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+      }
+      for (b = 7; b >= 8 - rectWidth % 8; b--) {
+	dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+      }
+    }
+  } else {
+    for (y = 0; y < numRows; y++)
+      for (x = 0; x < rectWidth; x++)
+	dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
+  }
+}
+
+#if BPP != 8
+
+/*----------------------------------------------------------------------------
+ *
+ * JPEG decompression.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool jpegError;
+     static struct jpeg_source_mgr jpegSrcManager;
+     static JOCTET *jpegBufferPtr;
+     static size_t *jpegBufferLen;
+*/
+
+static Bool
+DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  int compressedLen;
+  uint8_t *compressedData;
+  CARDBPP *pixelPtr;
+  JSAMPROW rowPointer[1];
+  int dx, dy;
+
+  compressedLen = (int)ReadCompactLen(client);
+  if (compressedLen <= 0) {
+    fprintf(stderr, "Incorrect data received from the server.\n");
+    return FALSE;
+  }
+
+  compressedData = malloc(compressedLen);
+  if (compressedData == NULL) {
+    fprintf(stderr, "Memory allocation error.\n");
+    return FALSE;
+  }
+
+  if (!ReadFromRFBServer(client, (char*)compressedData, compressedLen)) {
+    free(compressedData);
+    return FALSE;
+  }
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo);
+
+  JpegSetSrcManager(&cinfo, compressedData, compressedLen);
+
+  jpeg_read_header(&cinfo, TRUE);
+  cinfo.out_color_space = JCS_RGB;
+
+  jpeg_start_decompress(&cinfo);
+  if (cinfo.output_width != w || cinfo.output_height != h ||
+      cinfo.output_components != 3) {
+    fprintf(stderr, "Tight Encoding: Wrong JPEG data received.\n");
+    jpeg_destroy_decompress(&cinfo);
+    free(compressedData);
+    return FALSE;
+  }
+
+  rowPointer[0] = (JSAMPROW)client->buffer;
+  dy = 0;
+  while (cinfo.output_scanline < cinfo.output_height) {
+    jpeg_read_scanlines(&cinfo, rowPointer, 1);
+    if (jpegError) {
+      break;
+    }
+    pixelPtr = (CARDBPP *)&client->buffer[BUFFER_SIZE / 2];
+    for (dx = 0; dx < w; dx++) {
+      *pixelPtr++ =
+	RGB24_TO_PIXEL(BPP, client->buffer[dx*3], client->buffer[dx*3+1], client->buffer[dx*3+2]);
+    }
+    CopyRectangle(client, &client->buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
+    dy++;
+  }
+
+  if (!jpegError)
+    jpeg_finish_decompress(&cinfo);
+
+  jpeg_destroy_decompress(&cinfo);
+  free(compressedData);
+
+  return !jpegError;
+}
+
+#endif
+
diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c
new file mode 100644
index 0000000..3c9c13c
--- /dev/null
+++ b/libvncclient/vncviewer.c
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * vncviewer.c - the Xt-based VNC viewer.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <rfb/rfbclient.h>
+
+static void Dummy(rfbClient* client) {
+}
+static Bool DummyPoint(rfbClient* client, int x, int y) {
+  return TRUE;
+}
+static void DummyRect(rfbClient* client, int x, int y, int w, int h) {
+}
+static char* NoPassword(rfbClient* client) {
+  return "";
+}
+static Bool MallocFrameBuffer(rfbClient* client) {
+  if(client->frameBuffer)
+    free(client->frameBuffer);
+  client->frameBuffer=malloc(client->width*client->height*client->format.bitsPerPixel/8);
+  return client->frameBuffer?TRUE:FALSE;
+}
+
+rfbClient* rfbGetClient(int* argc,char** argv,
+			int bitsPerSample,int samplesPerPixel,
+			int bytesPerPixel) {
+  rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1);
+  client->programName = argv[0];
+  client->endianTest = 1;
+
+  client->format.bitsPerPixel = bytesPerPixel*8;
+  client->format.depth = bitsPerSample*samplesPerPixel;
+  client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
+  client->format.trueColour = TRUE;
+
+  if (client->format.bitsPerPixel == 8) {
+    client->format.redMax = 7;
+    client->format.greenMax = 7;
+    client->format.blueMax = 3;
+    client->format.redShift = 0;
+    client->format.greenShift = 3;
+    client->format.blueShift = 6;
+  } else {
+    client->format.redMax = (1 << bitsPerSample) - 1;
+    client->format.greenMax = (1 << bitsPerSample) - 1;
+    client->format.blueMax = (1 << bitsPerSample) - 1;
+    if(!client->format.bigEndian) {
+      client->format.redShift = 0;
+      client->format.greenShift = bitsPerSample;
+      client->format.blueShift = bitsPerSample * 2;
+    } else {
+      if(client->format.bitsPerPixel==8*3) {
+	client->format.redShift = bitsPerSample*2;
+	client->format.greenShift = bitsPerSample*1;
+	client->format.blueShift = 0;
+      } else {
+	client->format.redShift = bitsPerSample*3;
+	client->format.greenShift = bitsPerSample*2;
+	client->format.blueShift = bitsPerSample;
+      }
+    }
+  }
+
+  client->HandleCursorPos = DummyPoint;
+  client->SoftCursorLockArea = DummyRect;
+  client->SoftCursorUnlockScreen = Dummy;
+  client->FramebufferUpdateReceived = DummyRect;
+  client->GetPassword = NoPassword;
+  client->MallocFrameBuffer = MallocFrameBuffer;
+  client->Bell = Dummy;
+
+  return client;
+}
+
+void PrintRect(rfbClient* client, int x, int y, int w, int h) {
+  fprintf(stderr,"Received an update for %d,%d,%d,%d.\n",x,y,w,h);
+}
+
+void SaveFramebufferAsPGM(rfbClient* client, int x, int y, int w, int h) {
+  static time_t t=0,t1;
+  FILE* f;
+  int i,j;
+  int bpp=client->format.bitsPerPixel/8;
+  int row_stride=client->width*bpp;
+
+  /* save one picture only if the last is older than 2 seconds */
+  t1=time(0);
+  if(t1-t>2)
+    t=t1;
+  else
+    return;
+
+  /* assert bpp=4 */
+  if(bpp!=4) {
+    fprintf(stderr,"bpp = %d (!=4)\n",bpp);
+    return;
+  }
+
+  f=fopen("/tmp/framebuffer.ppm","wb");
+
+  fprintf(f,"P6\n# %s\n%d %d\n255\n",client->desktopName,client->width,client->height);
+  for(j=0;j<client->height*row_stride;j+=row_stride)
+    for(i=0;i<client->width*bpp;i+=bpp) {
+      if(client->format.bigEndian) {
+	fputc(client->frameBuffer[j+i+bpp-1],f);
+	fputc(client->frameBuffer[j+i+bpp-2],f);
+	fputc(client->frameBuffer[j+i+bpp-3],f);
+      } else {
+	fputc(client->frameBuffer[j+i+bpp+0],f);
+	fputc(client->frameBuffer[j+i+bpp+1],f);
+	fputc(client->frameBuffer[j+i+bpp+2],f);
+      }
+    }
+  fclose(f);
+}
+
+void
+vncEncryptBytes(unsigned char *bytes, char *passwd);
+
+int
+main(int argc, char **argv)
+{
+  int i;
+  rfbClient* client = rfbGetClient(&argc,argv,8,3,4);
+  const char* vncServerHost="";
+  int vncServerPort=5900;
+
+  char buf1[]="pass",buf2[]="pass";
+  vncEncryptBytes(buf1,buf2);
+
+  client->FramebufferUpdateReceived = PrintRect;
+  client->FramebufferUpdateReceived = SaveFramebufferAsPGM;
+
+  /* The -listen option is used to make us a daemon process which listens for
+     incoming connections from servers, rather than actively connecting to a
+     given server. The -tunnel and -via options are useful to create
+     connections tunneled via SSH port forwarding. We must test for the
+     -listen option before invoking any Xt functions - this is because we use
+     forking, and Xt doesn't seem to cope with forking very well. For -listen
+     option, when a successful incoming connection has been accepted,
+     listenForIncomingConnections() returns, setting the listenSpecified
+     flag. */
+
+  for (i = 1; i < argc; i++) {
+    if (strcmp(argv[i], "-listen") == 0) {
+      listenForIncomingConnections(client);
+      break;
+    } else {
+      char* colon=strchr(argv[i],':');
+
+      vncServerHost=argv[i];
+      if(colon) {
+	*colon=0;
+	vncServerPort=atoi(colon+1);
+      } else
+	vncServerPort=0;
+      vncServerPort+=5900;
+    }
+
+    /* TODO:
+    if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) {
+      if (!createTunnel(&argc, argv, i))
+	exit(1);
+      break;
+    }
+    */
+  }
+
+  /* Call the main Xt initialisation function.  It parses command-line options,
+     generating appropriate resource specs, and makes a connection to the X
+     display. */
+
+  /* TODO: cmdline args
+  toplevel = XtVaAppInitialize(&appContext, "Vncviewer",
+			       cmdLineOptions, numCmdLineOptions,
+			       &argc, argv, fallback_resources,
+			       XtNborderWidth, 0, NULL);
+
+  dpy = XtDisplay(toplevel);
+  */
+
+  /* Interpret resource specs and process any remaining command-line arguments
+     (i.e. the VNC server name).  If the server name isn't specified on the
+     command line, getArgsAndResources() will pop up a dialog box and wait
+     for one to be entered. */
+
+  /*
+  GetArgsAndResources(argc, argv);
+  */
+
+  /* Unless we accepted an incoming connection, make a TCP connection to the
+     given VNC server */
+
+  if (!client->listenSpecified) {
+    if (!ConnectToRFBServer(client,vncServerHost, vncServerPort)) exit(1);
+  }
+
+  /* Initialise the VNC connection, including reading the password */
+
+  if (!InitialiseRFBConnection(client)) exit(1);
+
+  SetFormatAndEncodings(client);
+
+  client->width=client->si.framebufferWidth;
+  client->height=client->si.framebufferHeight;
+  client->MallocFrameBuffer(client);
+  SendFramebufferUpdateRequest(client,0,0,client->width,client->height,FALSE);
+
+  /* Now enter the main loop, processing VNC messages.  X events will
+     automatically be processed whenever the VNC connection is idle. */
+
+  while (1) {
+    if (!HandleRFBServerMessage(client))
+      break;
+  }
+
+  return 0;
+}
diff --git a/libvncclient/zlib.c b/libvncclient/zlib.c
new file mode 100644
index 0000000..1fa67b5
--- /dev/null
+++ b/libvncclient/zlib.c
@@ -0,0 +1,158 @@
+/*
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * zlib.c - handle zlib encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles an zlib
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
+#define CARDBPP CONCAT2E(uint,BPP,_t)
+
+static Bool
+HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh)
+{
+  rfbZlibHeader hdr;
+  int remaining;
+  int inflateResult;
+  int toRead;
+
+  /* First make sure we have a large enough raw buffer to hold the
+   * decompressed data.  In practice, with a fixed BPP, fixed frame
+   * buffer size and the first update containing the entire frame
+   * buffer, this buffer allocation should only happen once, on the
+   * first update.
+   */
+  if ( raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
+
+    if ( raw_buffer != NULL ) {
+
+      free( raw_buffer );
+
+    }
+
+    raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
+    raw_buffer = (char*) malloc( raw_buffer_size );
+
+  }
+
+  if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
+    return FALSE;
+
+  remaining = Swap32IfLE(hdr.nBytes);
+
+  /* Need to initialize the decompressor state. */
+  decompStream.next_in   = ( Bytef * )client->buffer;
+  decompStream.avail_in  = 0;
+  decompStream.next_out  = ( Bytef * )raw_buffer;
+  decompStream.avail_out = raw_buffer_size;
+  decompStream.data_type = Z_BINARY;
+
+  /* Initialize the decompression stream structures on the first invocation. */
+  if ( decompStreamInited == FALSE ) {
+
+    inflateResult = inflateInit( &decompStream );
+
+    if ( inflateResult != Z_OK ) {
+      fprintf(stderr,
+              "inflateInit returned error: %d, msg: %s\n",
+              inflateResult,
+              decompStream.msg);
+      return FALSE;
+    }
+
+    decompStreamInited = TRUE;
+
+  }
+
+  inflateResult = Z_OK;
+
+  /* Process buffer full of data until no more to process, or
+   * some type of inflater error, or Z_STREAM_END.
+   */
+  while (( remaining > 0 ) &&
+         ( inflateResult == Z_OK )) {
+  
+    if ( remaining > BUFFER_SIZE ) {
+      toRead = BUFFER_SIZE;
+    }
+    else {
+      toRead = remaining;
+    }
+
+    /* Fill the buffer, obtaining data from the server. */
+    if (!ReadFromRFBServer(client, client->buffer,toRead))
+      return FALSE;
+
+    decompStream.next_in  = ( Bytef * )client->buffer;
+    decompStream.avail_in = toRead;
+
+    /* Need to uncompress buffer full. */
+    inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
+
+    /* We never supply a dictionary for compression. */
+    if ( inflateResult == Z_NEED_DICT ) {
+      fprintf(stderr,"zlib inflate needs a dictionary!\n");
+      return FALSE;
+    }
+    if ( inflateResult < 0 ) {
+      fprintf(stderr,
+              "zlib inflate returned error: %d, msg: %s\n",
+              inflateResult,
+              decompStream.msg);
+      return FALSE;
+    }
+
+    /* Result buffer allocated to be at least large enough.  We should
+     * never run out of space!
+     */
+    if (( decompStream.avail_in > 0 ) &&
+        ( decompStream.avail_out <= 0 )) {
+      fprintf(stderr,"zlib inflate ran out of space!\n");
+      return FALSE;
+    }
+
+    remaining -= toRead;
+
+  } /* while ( remaining > 0 ) */
+
+  if ( inflateResult == Z_OK ) {
+
+    /* Put the uncompressed contents of the update on the screen. */
+    CopyRectangle(client, raw_buffer, rx, ry, rw, rh);
+  }
+  else {
+
+    fprintf(stderr,
+            "zlib inflate returned error: %d, msg: %s\n",
+            inflateResult,
+            decompStream.msg);
+    return FALSE;
+
+  }
+
+  return TRUE;
+}
+
+#undef CARDBPP
diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h
new file mode 100644
index 0000000..c4f0418
--- /dev/null
+++ b/rfb/rfbclient.h
@@ -0,0 +1,186 @@
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  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.
+ */
+
+/*
+ * vncviewer.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <rfb/rfbproto.h>
+#include <rfb/keysym.h>
+
+#define Swap16IfLE(s) \
+    (*(char *)&client->endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s))
+
+#define Swap32IfLE(l) \
+    (*(char *)&client->endianTest ? ((((l) & 0xff000000) >> 24) | \
+			     (((l) & 0x00ff0000) >> 8)  | \
+			     (((l) & 0x0000ff00) << 8)  | \
+			     (((l) & 0x000000ff) << 24))  : (l))
+
+#define FLASH_PORT_OFFSET 5400
+#define LISTEN_PORT_OFFSET 5500
+#define TUNNEL_PORT_OFFSET 5500
+#define SERVER_PORT_OFFSET 5900
+
+#define DEFAULT_SSH_CMD "/usr/bin/ssh"
+#define DEFAULT_TUNNEL_CMD  \
+  (DEFAULT_SSH_CMD " -f -L %L:localhost:%R %H sleep 20")
+#define DEFAULT_VIA_CMD     \
+  (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20")
+
+
+typedef struct {
+  Bool shareDesktop;
+  Bool viewOnly;
+  Bool fullScreen;
+  Bool grabKeyboard;
+  Bool raiseOnBeep;
+
+  const char* encodingsString;
+
+  Bool useBGR233;
+  int nColours;
+  Bool useSharedColours;
+  Bool forceOwnCmap;
+  Bool forceTrueColour;
+  int requestedDepth;
+
+  Bool useShm;
+
+  int wmDecorationWidth;
+  int wmDecorationHeight;
+
+  Bool debug;
+
+  int popupButtonCount;
+
+  int bumpScrollTime;
+  int bumpScrollPixels;
+
+  int compressLevel;
+  int qualityLevel;
+  Bool enableJPEG;
+  Bool useRemoteCursor;
+} AppData;
+
+
+struct _rfbClient;
+
+typedef Bool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y);
+typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h);
+typedef void (*SoftCursorUnlockScreenProc)(struct _rfbClient* client);
+typedef void (*FramebufferUpdateReceivedProc)(struct _rfbClient* client, int x, int y, int w, int h);
+typedef char* (*GetPasswordProc)(struct _rfbClient* client);
+typedef Bool (*MallocFrameBufferProc)(struct _rfbClient* client);
+typedef void (*BellProc)(struct _rfbClient* client);
+
+typedef struct _rfbClient {
+	uint8_t* frameBuffer;
+	int width, height;
+
+	int endianTest;
+
+	AppData appData;
+
+	const char* programName;
+	const char* serverHost;
+	int serverPort;
+	Bool listenSpecified;
+	int listenPort, flashPort;
+
+	/* Note that the CoRRE encoding uses this buffer and assumes it is big enough
+	   to hold 255 * 255 * 32 bits -> 260100 bytes.  640*480 = 307200 bytes.
+	   Hextile also assumes it is big enough to hold 16 * 16 * 32 bits.
+	   Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */
+
+#define BUFFER_SIZE (640*480)
+	char buffer[BUFFER_SIZE];
+
+	/* rfbproto.c */
+
+	int sock;
+	Bool canUseCoRRE;
+	Bool canUseHextile;
+	char *desktopName;
+	rfbPixelFormat format;
+	rfbServerInitMsg si;
+	char *serverCutText;
+	Bool newServerCutText;
+
+	/* cursor.c */
+	uint8_t *rcSource, *rcMask;
+
+	/* hooks */
+	HandleCursorPosProc HandleCursorPos;
+	SoftCursorLockAreaProc SoftCursorLockArea;
+	SoftCursorUnlockScreenProc SoftCursorUnlockScreen;
+	FramebufferUpdateReceivedProc FramebufferUpdateReceived;
+	GetPasswordProc GetPassword;
+	MallocFrameBufferProc MallocFrameBuffer;
+	BellProc Bell;
+} rfbClient;
+
+/* cursor.c */
+
+// TODO: make callback
+
+extern Bool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc);
+
+/* listen.c */
+
+extern void listenForIncomingConnections(rfbClient* viewer);
+
+/* rfbproto.c */
+
+extern Bool ConnectToRFBServer(rfbClient* client,const char *hostname, int port);
+extern Bool InitialiseRFBConnection(rfbClient* client);
+extern Bool SetFormatAndEncodings(rfbClient* client);
+extern Bool SendIncrementalFramebufferUpdateRequest(rfbClient* client);
+extern Bool SendFramebufferUpdateRequest(rfbClient* client,
+					 int x, int y, int w, int h,
+					 Bool incremental);
+extern Bool SendPointerEvent(rfbClient* client,int x, int y, int buttonMask);
+extern Bool SendKeyEvent(rfbClient* client,uint32_t key, Bool down);
+extern Bool SendClientCutText(rfbClient* client,char *str, int len);
+extern Bool HandleRFBServerMessage(rfbClient* client);
+
+extern void PrintPixelFormat(rfbPixelFormat *format);
+
+/* sockets.c */
+
+extern Bool errorMessageOnReadFailure;
+
+extern Bool ReadFromRFBServer(rfbClient* client, char *out, unsigned int n);
+extern Bool WriteExact(rfbClient* client, char *buf, int n);
+extern int FindFreeTcpPort(void);
+extern int ListenAtTcpPort(int port);
+extern int ConnectToTcpAddr(unsigned int host, int port);
+extern int AcceptTcpConnection(int listenSock);
+extern Bool SetNonBlocking(int sock);
+
+extern Bool StringToIPAddr(const char *str, unsigned int *addr);
+extern Bool SameMachine(int sock);
+
diff --git a/vncauth.c b/vncauth.c
index cc88fcf..f701b84 100644
--- a/vncauth.c
+++ b/vncauth.c
@@ -51,7 +51,7 @@
  * as plaintext.
  */
 
-unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
+static unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
 
 
 /*
-- 
cgit v1.2.3

