[PATCH 03/25] Rename gvnc.[h,c] -> vncconnection.[h,c]



---
 autogen.sh          |    6 +-
 configure.ac        |    2 +-
 src/Makefile.am     |    2 +-
 src/gvnc.c          | 3964 ---------------------------------------------------
 src/gvnc.h          |  217 ---
 src/vncconnection.c | 3964 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/vncconnection.h |  217 +++
 src/vncdisplay.c    |    2 +-
 8 files changed, 4187 insertions(+), 4187 deletions(-)
 delete mode 100644 src/gvnc.c
 delete mode 100644 src/gvnc.h
 create mode 100644 src/vncconnection.c
 create mode 100644 src/vncconnection.h

diff --git a/autogen.sh b/autogen.sh
index 371b98b..1d2a117 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -39,8 +39,8 @@ if test "$DIE" -eq 1; then
 fi
 
 if test -z "$*"; then
-	echo "I am going to run ./configure with --enable-warnings - if you "
-        echo "wish to pass any extra arguments to it, please specify them on "
+	echo "I am going to run ./configure with --enable-compile-warnings=maximum"
+        echo "If you wish to pass any extra arguments to it, please specify them on "
         echo "the $0 command line."
 fi
 
@@ -55,7 +55,7 @@ rm -f COPYING
 
 cd $THEDIR
 
-$srcdir/configure --enable-warnings "$@" && {
+$srcdir/configure --enable-compile-warnings=maximum "$@" && {
     echo
     echo "Now type 'make' to compile gtk-vnc."
 }
diff --git a/configure.ac b/configure.ac
index 2131706..3bcf5a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 dnl Process this file with autoconf to produce a configure script.
 
 AC_INIT([gtk-vnc], [0.3.10])
-AC_CONFIG_SRCDIR([src/gvnc.c])
+AC_CONFIG_SRCDIR([src/vncconnection.c])
 dnl Causes problems with RHEL-5 vintage intltool
 dnl AC_CONFIG_AUX_DIR([build-aux])
 AM_CONFIG_HEADER([config.h])
diff --git a/src/Makefile.am b/src/Makefile.am
index cae7406..1a81ac1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,7 @@ libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
 	coroutine.h \
 	d3des.h d3des.c \
 	dh.h dh.c \
-	gvnc.h gvnc.c \
+	vncconnection.h vncconnection.c \
 	vncdisplay.h vncdisplay.c \
         vncmarshal.h vncmarshal.c \
 	x_keymap.h x_keymap.c vnc_keycodes.h \
diff --git a/src/gvnc.c b/src/gvnc.c
deleted file mode 100644
index 307bbfe..0000000
--- a/src/gvnc.c
+++ /dev/null
@@ -1,3964 +0,0 @@
-/*
- * GTK VNC Widget
- *
- * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.0 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#include <config.h>
-
-#include "gvnc.h"
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "coroutine.h"
-#include "d3des.h"
-
-#include "x_keymap.h"
-
-#include "utils.h"
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#if HAVE_SASL
-#include <sasl/sasl.h>
-#endif
-
-#include <zlib.h>
-
-#include <gdk/gdkkeysyms.h>
-
-#include "getaddrinfo.h"
-#include "dh.h"
-
-/* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
-   even if its emulated getaddrinfo() for us . */
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0
-#endif
-
-
-struct wait_queue
-{
-	gboolean waiting;
-	struct coroutine *context;
-};
-
-
-typedef void gvnc_blt_func(struct gvnc *, guint8 *, int, int, int, int, int);
-
-typedef void gvnc_fill_func(struct gvnc *, guint8 *, int, int, int, int);
-
-typedef void gvnc_set_pixel_at_func(struct gvnc *, int, int, guint8 *);
-
-typedef void gvnc_hextile_func(struct gvnc *gvnc, guint8 flags,
-			       guint16 x, guint16 y,
-			       guint16 width, guint16 height,
-			       guint8 *fg, guint8 *bg);
-
-typedef void gvnc_rich_cursor_blt_func(struct gvnc *, guint8 *, guint8 *,
-				       guint8 *, int, guint16, guint16);
-
-typedef void gvnc_rgb24_blt_func(struct gvnc *, int, int, int, int,
-				 guint8 *, int);
-
-typedef void gvnc_tight_compute_predicted_func(struct gvnc *, guint8 *,
-					       guint8 *, guint8 *,
-					       guint8 *);
-
-typedef void gvnc_tight_sum_pixel_func(struct gvnc *, guint8 *, guint8 *);
-
-/*
- * A special GSource impl which allows us to wait on a certain
- * condition to be satisfied. This is effectively a boolean test
- * run on each iteration of the main loop. So whenever a file has
- * new I/O, or a timer occurs, etc we'll do the check. This is
- * pretty efficient compared to a normal GLib Idle func which has
- * to busy wait on a timeout, since our condition is only checked
- * when some other source's state changes
- */
-typedef gboolean (*g_condition_wait_func)(gpointer);
-
-struct g_condition_wait_source
-{
-        GSource src;
-        struct coroutine *co;
-	g_condition_wait_func func;
-	gpointer data;
-};
-
-struct gvnc
-{
-	GIOChannel *channel;
-	int fd;
-	char *host;
-	char *port;
-	struct gvnc_pixel_format fmt;
-	gboolean has_error;
-	int width;
-	int height;
-	char *name;
-
-	int major;
-	int minor;
-	gnutls_session_t tls_session;
-
-	/* Auth related params */
-	unsigned int auth_type;
-	unsigned int auth_subtype;
-	char *cred_username;
-	char *cred_password;
-	char *cred_x509_cacert;
-	char *cred_x509_cacrl;
-	char *cred_x509_cert;
-	char *cred_x509_key;
-	gboolean want_cred_username;
-	gboolean want_cred_password;
-	gboolean want_cred_x509;
-
-#if HAVE_SASL
-	sasl_conn_t *saslconn;      /* SASL context */
-	const char *saslDecoded;
-	unsigned int saslDecodedLength;
-	unsigned int saslDecodedOffset;
-#endif
-
-	char read_buffer[4096];
-	size_t read_offset;
-	size_t read_size;
-
-	char write_buffer[4096];
-	size_t write_offset;
-
-	gboolean perfect_match;
-	struct gvnc_framebuffer local;
-
-	int rm, gm, bm;
-	int rrs, grs, brs;
-	int rls, gls, bls;
-
-	gvnc_blt_func *blt;
-	gvnc_fill_func *fill;
-	gvnc_set_pixel_at_func *set_pixel_at;
-	gvnc_hextile_func *hextile;
-	gvnc_rich_cursor_blt_func *rich_cursor_blt;
-	gvnc_rgb24_blt_func *rgb24_blt;
-	gvnc_tight_compute_predicted_func *tight_compute_predicted;
-	gvnc_tight_sum_pixel_func *tight_sum_pixel;
-
-	struct gvnc_ops ops;
-	gpointer ops_data;
-
-	int absolute;
-
-	int wait_interruptable;
-	struct wait_queue wait;
-
-	char *xmit_buffer;
-	int xmit_buffer_capacity;
-	int xmit_buffer_size;
-
-	z_stream *strm;
-	z_stream streams[5];
-
-	size_t uncompressed_length;
-	guint8 uncompressed_buffer[4096];
-
-	size_t compressed_length;
-	guint8 *compressed_buffer;
-
-	guint8 zrle_pi;
-	int zrle_pi_bits;
-
-	gboolean has_ext_key_event;
-	const guint8 const *keycode_map;
-};
-
-#define nibhi(a) (((a) >> 4) & 0x0F)
-#define niblo(a) ((a) & 0x0F)
-
-/* Main loop helper functions */
-static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
-				 GIOCondition cond,
-				 gpointer data)
-{
-	struct coroutine *to = data;
-	coroutine_yieldto(to, &cond);
-	return FALSE;
-}
-
-static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
-{
-	GIOCondition *ret;
-
-	g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, coroutine_self());
-	ret = coroutine_yield(NULL);
-	return *ret;
-}
-
-
-static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
-					    GIOChannel *channel,
-					    GIOCondition cond)
-{
-	GIOCondition *ret;
-	gint id;
-
-	wait->context = coroutine_self();
-	id = g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, wait->context);
-
-	wait->waiting = TRUE;
-	ret = coroutine_yield(NULL);
-	wait->waiting = FALSE;
-
-	if (ret == NULL) {
-		g_source_remove(id);
-		return 0;
-	} else
-		return *ret;
-}
-
-static void g_io_wakeup(struct wait_queue *wait)
-{
-	if (wait->waiting)
-		coroutine_yieldto(wait->context, NULL);
-}
-
-
-/*
- * Call immediately before the main loop does an iteration. Returns
- * true if the condition we're checking is ready for dispatch
- */
-static gboolean g_condition_wait_prepare(GSource *src,
-					 int *timeout) {
-        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
-        *timeout = -1;
-        return vsrc->func(vsrc->data);
-}
-
-/*
- * Call immediately after the main loop does an iteration. Returns
- * true if the condition we're checking is ready for dispatch
- */
-static gboolean g_condition_wait_check(GSource *src)
-{
-        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
-        return vsrc->func(vsrc->data);
-}
-
-static gboolean g_condition_wait_dispatch(GSource *src G_GNUC_UNUSED,
-					  GSourceFunc cb,
-					  gpointer data) {
-        return cb(data);
-}
-
-GSourceFuncs waitFuncs = {
-        .prepare = g_condition_wait_prepare,
-        .check = g_condition_wait_check,
-        .dispatch = g_condition_wait_dispatch,
-  };
-
-static gboolean g_condition_wait_helper(gpointer data)
-{
-        struct coroutine *co = (struct coroutine *)data;
-        coroutine_yieldto(co, NULL);
-        return FALSE;
-}
-
-static gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
-{
-	GSource *src;
-	struct g_condition_wait_source *vsrc;
-
-	/* Short-circuit check in case we've got it ahead of time */
-	if (func(data)) {
-		return TRUE;
-	}
-
-	/*
-	 * Don't have it, so yield to the main loop, checking the condition
-	 * on each iteration of the main loop
-	 */
-	src = g_source_new(&waitFuncs, sizeof(struct g_condition_wait_source));
-	vsrc = (struct g_condition_wait_source *)src;
-
-	vsrc->func = func;
-	vsrc->data = data;
-	vsrc->co = coroutine_self();
-
-	g_source_attach(src, NULL);
-	g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
-	coroutine_yield(NULL);
-	return TRUE;
-}
-
-static gboolean gvnc_use_compression(struct gvnc *gvnc)
-{
-	return gvnc->compressed_buffer != NULL;
-}
-
-static int gvnc_zread(struct gvnc *gvnc, void *buffer, size_t size)
-{
-	char *ptr = buffer;
-	size_t offset = 0;
-
-	while (offset < size) {
-		/* if data is available in the uncompressed buffer, then
-		 * copy */
-		if (gvnc->uncompressed_length) {
-			size_t len = MIN(gvnc->uncompressed_length,
-					 size - offset);
-
-			memcpy(ptr + offset,
-			       gvnc->uncompressed_buffer,
-			       len);
-
-			gvnc->uncompressed_length -= len;
-			if (gvnc->uncompressed_length)
-				memmove(gvnc->uncompressed_buffer,
-					gvnc->uncompressed_buffer + len,
-					gvnc->uncompressed_length);
-			offset += len;
-		} else {
-			int err;
-
-			gvnc->strm->next_in = gvnc->compressed_buffer;
-			gvnc->strm->avail_in = gvnc->compressed_length;
-			gvnc->strm->next_out = gvnc->uncompressed_buffer;
-			gvnc->strm->avail_out = sizeof(gvnc->uncompressed_buffer);
-
-			/* inflate as much as possible */
-			err = inflate(gvnc->strm, Z_SYNC_FLUSH);
-			if (err != Z_OK) {
-				errno = EIO;
-				return -1;
-			}
-
-			gvnc->uncompressed_length = (guint8 *)gvnc->strm->next_out - gvnc->uncompressed_buffer;
-			gvnc->compressed_length -= (guint8 *)gvnc->strm->next_in - gvnc->compressed_buffer;
-			gvnc->compressed_buffer = gvnc->strm->next_in;
-		}
-	}
-
-	return offset;
-}
-
-/* IO functions */
-
-
-/*
- * Read at least 1 more byte of data straight off the wire
- * into the requested buffer.
- */
-static int gvnc_read_wire(struct gvnc *gvnc, void *data, size_t len)
-{
-	int ret;
-
- reread:
-	if (gvnc->tls_session) {
-		ret = gnutls_read(gvnc->tls_session, data, len);
-		if (ret < 0) {
-			if (ret == GNUTLS_E_AGAIN)
-				errno = EAGAIN;
-			else
-				errno = EIO;
-			ret = -1;
-		}
-	} else
-		ret = recv (gvnc->fd, data, len, 0);
-
-	if (ret == -1) {
-		switch (errno) {
-		case EWOULDBLOCK:
-			if (gvnc->wait_interruptable) {
-				if (!g_io_wait_interruptable(&gvnc->wait,
-							     gvnc->channel, G_IO_IN)) {
-					GVNC_DEBUG("Read blocking interrupted %d", gvnc->has_error);
-					return -EAGAIN;
-				}
-			} else
-				g_io_wait(gvnc->channel, G_IO_IN);
-		case EINTR:
-			goto reread;
-
-		default:
-			GVNC_DEBUG("Closing the connection: gvnc_read() - errno=%d", errno);
-			gvnc->has_error = TRUE;
-			return -errno;
-		}
-	}
-	if (ret == 0) {
-		GVNC_DEBUG("Closing the connection: gvnc_read() - ret=0");
-		gvnc->has_error = TRUE;
-		return -EPIPE;
-	}
-	//GVNC_DEBUG("Read wire %p %d -> %d", data, len, ret);
-
-	return ret;
-}
-
-
-#if HAVE_SASL
-/*
- * Read at least 1 more byte of data out of the SASL decrypted
- * data buffer, into the internal read buffer
- */
-static int gvnc_read_sasl(struct gvnc *gvnc)
-{
-	size_t want;
-	//GVNC_DEBUG("Read SASL %p size %d offset %d", gvnc->saslDecoded,
-	//	   gvnc->saslDecodedLength, gvnc->saslDecodedOffset);
-	if (gvnc->saslDecoded == NULL) {
-		char encoded[8192];
-		int encodedLen = sizeof(encoded);
-		int err, ret;
-
-		ret = gvnc_read_wire(gvnc, encoded, encodedLen);
-		if (ret < 0) {
-			return ret;
-		}
-
-		err = sasl_decode(gvnc->saslconn, encoded, ret,
-				  &gvnc->saslDecoded, &gvnc->saslDecodedLength);
-		if (err != SASL_OK) {
-			GVNC_DEBUG("Failed to decode SASL data %s",
-				   sasl_errstring(err, NULL, NULL));
-			gvnc->has_error = TRUE;
-			return -EINVAL;
-		}
-		gvnc->saslDecodedOffset = 0;
-	}
-
-	want = gvnc->saslDecodedLength - gvnc->saslDecodedOffset;
-	if (want > sizeof(gvnc->read_buffer))
-		want = sizeof(gvnc->read_buffer);
-
-	memcpy(gvnc->read_buffer,
-	       gvnc->saslDecoded + gvnc->saslDecodedOffset,
-	       want);
-	gvnc->saslDecodedOffset += want;
-	if (gvnc->saslDecodedOffset == gvnc->saslDecodedLength) {
-		gvnc->saslDecodedLength = gvnc->saslDecodedOffset = 0;
-		gvnc->saslDecoded = NULL;
-	}
-	//GVNC_DEBUG("Done read write %d - %d", want, gvnc->has_error);
-	return want;
-}
-#endif
-
-
-/*
- * Read at least 1 more byte of data straight off the wire
- * into the internal read buffer
- */
-static int gvnc_read_plain(struct gvnc *gvnc)
-{
-	//GVNC_DEBUG("Read plain %d", sizeof(gvnc->read_buffer));
-	return gvnc_read_wire(gvnc, gvnc->read_buffer, sizeof(gvnc->read_buffer));
-}
-
-/*
- * Read at least 1 more byte of data into the internal read_buffer
- */
-static int gvnc_read_buf(struct gvnc *gvnc)
-{
-	//GVNC_DEBUG("Start read %d", gvnc->has_error);
-#if HAVE_SASL
-	if (gvnc->saslconn)
-		return gvnc_read_sasl(gvnc);
-	else
-#endif
-		return gvnc_read_plain(gvnc);
-}
-
-/*
- * Fill the 'data' buffer up with exactly 'len' bytes worth of data
- */
-static int gvnc_read(struct gvnc *gvnc, void *data, size_t len)
-{
-	char *ptr = data;
-	size_t offset = 0;
-
-	if (gvnc->has_error) return -EINVAL;
-
-	while (offset < len) {
-		size_t tmp;
-
-		/* compressed data is buffered independently of the read buffer
-		 * so we must by-pass it */
-		if (gvnc_use_compression(gvnc)) {
-			int ret = gvnc_zread(gvnc, ptr + offset, len);
-			if (ret == -1) {
-				GVNC_DEBUG("Closing the connection: gvnc_read() - gvnc_zread() failed");
-				gvnc->has_error = TRUE;
-				return -errno;
-			}
-			offset += ret;
-			continue;
-		} else if (gvnc->read_offset == gvnc->read_size) {
-			int ret = gvnc_read_buf(gvnc);
-
-			if (ret < 0)
-				return ret;
-			gvnc->read_offset = 0;
-			gvnc->read_size = ret;
-		}
-
-		tmp = MIN(gvnc->read_size - gvnc->read_offset, len - offset);
-
-		memcpy(ptr + offset, gvnc->read_buffer + gvnc->read_offset, tmp);
-
-		gvnc->read_offset += tmp;
-		offset += tmp;
-	}
-
-	return 0;
-}
-
-/*
- * Write all 'data' of length 'datalen' bytes out to
- * the wire
- */
-static void gvnc_flush_wire(struct gvnc *gvnc,
-			    const void *data,
-			    size_t datalen)
-{
-	const char *ptr = data;
-	size_t offset = 0;
-	//GVNC_DEBUG("Flush write %p %d", data, datalen);
-	while (offset < datalen) {
-		int ret;
-
-		if (gvnc->tls_session) {
-			ret = gnutls_write(gvnc->tls_session,
-					   ptr+offset,
-					   datalen-offset);
-			if (ret < 0) {
-				if (ret == GNUTLS_E_AGAIN)
-					errno = EAGAIN;
-				else
-					errno = EIO;
-				ret = -1;
-			}
-		} else
-			ret = send (gvnc->fd,
-				    ptr+offset,
-				    datalen-offset, 0);
-		if (ret == -1) {
-			switch (errno) {
-			case EWOULDBLOCK:
-				g_io_wait(gvnc->channel, G_IO_OUT);
-			case EINTR:
-				continue;
-			default:
-				GVNC_DEBUG("Closing the connection: gvnc_flush %d", errno);
-				gvnc->has_error = TRUE;
-				return;
-			}
-		}
-		if (ret == 0) {
-			GVNC_DEBUG("Closing the connection: gvnc_flush");
-			gvnc->has_error = TRUE;
-			return;
-		}
-		offset += ret;
-	}
-}
-
-
-#if HAVE_SASL
-/*
- * Encode all buffered data, write all encrypted data out
- * to the wire
- */
-static void gvnc_flush_sasl(struct gvnc *gvnc)
-{
-	const char *output;
-	unsigned int outputlen;
-	int err;
-
-	err = sasl_encode(gvnc->saslconn,
-			  gvnc->write_buffer,
-			  gvnc->write_offset,
-			  &output, &outputlen);
-	if (err != SASL_OK) {
-		GVNC_DEBUG("Failed to encode SASL data %s",
-			   sasl_errstring(err, NULL, NULL));
-		gvnc->has_error = TRUE;
-		return;
-	}
-	//GVNC_DEBUG("Flush SASL %d: %p %d", gvnc->write_offset, output, outputlen);
-	gvnc_flush_wire(gvnc, output, outputlen);
-}
-#endif
-
-/*
- * Write all buffered data straight out to the wire
- */
-static void gvnc_flush_plain(struct gvnc *gvnc)
-{
-	//GVNC_DEBUG("Flush plain %d", gvnc->write_offset);
-	gvnc_flush_wire(gvnc,
-			gvnc->write_buffer,
-			gvnc->write_offset);
-}
-
-
-/*
- * Write all buffered data out to the wire
- */
-static void gvnc_flush(struct gvnc *gvnc)
-{
-	//GVNC_DEBUG("STart write %d", gvnc->has_error);
-#if HAVE_SASL
-	if (gvnc->saslconn)
-		gvnc_flush_sasl(gvnc);
-	else
-#endif
-		gvnc_flush_plain(gvnc);
-	gvnc->write_offset = 0;
-}
-
-static void gvnc_write(struct gvnc *gvnc, const void *data, size_t len)
-{
-	const char *ptr = data;
-	size_t offset = 0;
-
-	while (offset < len) {
-		ssize_t tmp;
-
-		if (gvnc->write_offset == sizeof(gvnc->write_buffer)) {
-			gvnc_flush(gvnc);
-		}
-
-		tmp = MIN(sizeof(gvnc->write_buffer), len - offset);
-
-		memcpy(gvnc->write_buffer+gvnc->write_offset, ptr + offset, tmp);
-
-		gvnc->write_offset += tmp;
-		offset += tmp;
-	}
-}
-
-
-static ssize_t gvnc_tls_push(gnutls_transport_ptr_t transport,
-			      const void *data,
-			      size_t len) {
-	struct gvnc *gvnc = (struct gvnc *)transport;
-	int ret;
-
- retry:
-	ret = write(gvnc->fd, data, len);
-	if (ret < 0) {
-		if (errno == EINTR)
-			goto retry;
-		return -1;
-	}
-	return ret;
-}
-
-
-static ssize_t gvnc_tls_pull(gnutls_transport_ptr_t transport,
-			     void *data,
-			     size_t len) {
-	struct gvnc *gvnc = (struct gvnc *)transport;
-	int ret;
-
- retry:
-	ret = read(gvnc->fd, data, len);
-	if (ret < 0) {
-		if (errno == EINTR)
-			goto retry;
-		return -1;
-	}
-	return ret;
-}
-
-static size_t gvnc_pixel_size(struct gvnc *gvnc)
-{
-	return gvnc->fmt.bits_per_pixel / 8;
-}
-
-static void gvnc_read_pixel(struct gvnc *gvnc, guint8 *pixel)
-{
-	gvnc_read(gvnc, pixel, gvnc_pixel_size(gvnc));
-}
-
-static guint8 gvnc_read_u8(struct gvnc *gvnc)
-{
-	guint8 value = 0;
-	gvnc_read(gvnc, &value, sizeof(value));
-	return value;
-}
-
-static int gvnc_read_u8_interruptable(struct gvnc *gvnc, guint8 *value)
-{
-	int ret;
-
-	gvnc->wait_interruptable = 1;
-	ret = gvnc_read(gvnc, value, sizeof(*value));
-	gvnc->wait_interruptable = 0;
-
-	return ret;
-}
-
-static guint16 gvnc_read_u16(struct gvnc *gvnc)
-{
-	guint16 value = 0;
-	gvnc_read(gvnc, &value, sizeof(value));
-	return ntohs(value);
-}
-
-static guint32 gvnc_read_u32(struct gvnc *gvnc)
-{
-	guint32 value = 0;
-	gvnc_read(gvnc, &value, sizeof(value));
-	return ntohl(value);
-}
-
-static gint32 gvnc_read_s32(struct gvnc *gvnc)
-{
-	gint32 value = 0;
-	gvnc_read(gvnc, &value, sizeof(value));
-	return ntohl(value);
-}
-
-static void gvnc_write_u8(struct gvnc *gvnc, guint8 value)
-{
-	gvnc_write(gvnc, &value, sizeof(value));
-}
-
-static void gvnc_write_u16(struct gvnc *gvnc, guint16 value)
-{
-	value = htons(value);
-	gvnc_write(gvnc, &value, sizeof(value));
-}
-
-static void gvnc_write_u32(struct gvnc *gvnc, guint32 value)
-{
-	value = htonl(value);
-	gvnc_write(gvnc, &value, sizeof(value));
-}
-
-static void gvnc_write_s32(struct gvnc *gvnc, gint32 value)
-{
-	value = htonl(value);
-	gvnc_write(gvnc, &value, sizeof(value));
-}
-
-#define DH_BITS 1024
-static gnutls_dh_params_t dh_params;
-
-#if 0
-static void gvnc_debug_gnutls_log(int level, const char* str) {
-	GVNC_DEBUG("%d %s", level, str);
-}
-#endif
-
-static gboolean gvnc_tls_initialize(void)
-{
-	static int tlsinitialized = 0;
-
-	if (tlsinitialized)
-		return TRUE;
-
-	if (gnutls_global_init () < 0)
-		return FALSE;
-
-	if (gnutls_dh_params_init (&dh_params) < 0)
-		return FALSE;
-	if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
-		return FALSE;
-
-#if 0
-	if (debug_enabled) {
-		gnutls_global_set_log_level(10);
-		gnutls_global_set_log_function(gvnc_debug_gnutls_log);
-	}
-#endif
-
-	tlsinitialized = TRUE;
-
-	return TRUE;
-}
-
-static gnutls_anon_client_credentials gvnc_tls_initialize_anon_cred(void)
-{
-	gnutls_anon_client_credentials anon_cred;
-	int ret;
-
-	if ((ret = gnutls_anon_allocate_client_credentials(&anon_cred)) < 0) {
-		GVNC_DEBUG("Cannot allocate credentials %s", gnutls_strerror(ret));
-		return NULL;
-	}
-
-	return anon_cred;
-}
-
-static gnutls_certificate_credentials_t gvnc_tls_initialize_cert_cred(struct gvnc *vnc)
-{
-	gnutls_certificate_credentials_t x509_cred;
-	int ret;
-
-	if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
-		GVNC_DEBUG("Cannot allocate credentials %s", gnutls_strerror(ret));
-		return NULL;
-	}
-	if (vnc->cred_x509_cacert) {
-		if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
-								  vnc->cred_x509_cacert,
-								  GNUTLS_X509_FMT_PEM)) < 0) {
-			GVNC_DEBUG("Cannot load CA certificate %s", gnutls_strerror(ret));
-			return NULL;
-		}
-	} else {
-		GVNC_DEBUG("No CA certificate provided");
-		return NULL;
-	}
-
-	if (vnc->cred_x509_cert && vnc->cred_x509_key) {
-		if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
-								 vnc->cred_x509_cert,
-								 vnc->cred_x509_key,
-								 GNUTLS_X509_FMT_PEM)) < 0) {
-			GVNC_DEBUG("Cannot load certificate & key %s", gnutls_strerror(ret));
-			return NULL;
-		}
-	} else {
-		GVNC_DEBUG("No client cert or key provided");
-	}
-
-	if (vnc->cred_x509_cacrl) {
-		if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
-								vnc->cred_x509_cacrl,
-								GNUTLS_X509_FMT_PEM)) < 0) {
-			GVNC_DEBUG("Cannot load CRL %s", gnutls_strerror(ret));
-			return NULL;
-		}
-	} else {
-		GVNC_DEBUG("No CA revocation list provided");
-	}
-
-	gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
-	return x509_cred;
-}
-
-static int gvnc_validate_certificate(struct gvnc *vnc)
-{
-	int ret;
-	unsigned int status;
-	const gnutls_datum_t *certs;
-	unsigned int nCerts, i;
-	time_t now;
-
-	GVNC_DEBUG("Validating");
-	if ((ret = gnutls_certificate_verify_peers2 (vnc->tls_session, &status)) < 0) {
-		GVNC_DEBUG("Verify failed %s", gnutls_strerror(ret));
-		return FALSE;
-	}
-
-	if ((now = time(NULL)) == ((time_t)-1)) {
-		return FALSE;
-	}
-
-	if (status != 0) {
-		if (status & GNUTLS_CERT_INVALID)
-			GVNC_DEBUG ("The certificate is not trusted.");
-
-		if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-			GVNC_DEBUG ("The certificate hasn't got a known issuer.");
-
-		if (status & GNUTLS_CERT_REVOKED)
-			GVNC_DEBUG ("The certificate has been revoked.");
-
-		if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-			GVNC_DEBUG ("The certificate uses an insecure algorithm");
-
-		return FALSE;
-	} else {
-		GVNC_DEBUG("Certificate is valid.");
-	}
-
-	if (gnutls_certificate_type_get(vnc->tls_session) != GNUTLS_CRT_X509)
-		return FALSE;
-
-	if (!(certs = gnutls_certificate_get_peers(vnc->tls_session, &nCerts)))
-		return FALSE;
-
-	for (i = 0 ; i < nCerts ; i++) {
-		gnutls_x509_crt_t cert;
-		GVNC_DEBUG ("Checking chain %d", i);
-		if (gnutls_x509_crt_init (&cert) < 0)
-			return FALSE;
-
-		if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
-			gnutls_x509_crt_deinit (cert);
-			return FALSE;
-		}
-
-		if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-			GVNC_DEBUG("The certificate has expired");
-			gnutls_x509_crt_deinit (cert);
-			return FALSE;
-		}
-
-		if (gnutls_x509_crt_get_activation_time (cert) > now) {
-			GVNC_DEBUG("The certificate is not yet activated");
-			gnutls_x509_crt_deinit (cert);
-			return FALSE;
-		}
-
-		if (gnutls_x509_crt_get_activation_time (cert) > now) {
-			GVNC_DEBUG("The certificate is not yet activated");
-			gnutls_x509_crt_deinit (cert);
-			return FALSE;
-		}
-
-		if (i == 0) {
-			if (!vnc->host) {
-				GVNC_DEBUG ("No hostname provided for certificate verification");
-				gnutls_x509_crt_deinit (cert);
-				return FALSE;
-			}
-			if (!gnutls_x509_crt_check_hostname (cert, vnc->host)) {
-				GVNC_DEBUG ("The certificate's owner does not match hostname '%s'",
-					    vnc->host);
-				gnutls_x509_crt_deinit (cert);
-				return FALSE;
-			}
-		}
-	}
-
-	return TRUE;
-}
-
-
-static void gvnc_read_pixel_format(struct gvnc *gvnc, struct gvnc_pixel_format *fmt)
-{
-	guint8 pad[3];
-
-	fmt->bits_per_pixel  = gvnc_read_u8(gvnc);
-	fmt->depth           = gvnc_read_u8(gvnc);
-	fmt->byte_order      = gvnc_read_u8(gvnc) ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
-	fmt->true_color_flag = gvnc_read_u8(gvnc);
-
-	fmt->red_max         = gvnc_read_u16(gvnc);
-	fmt->green_max       = gvnc_read_u16(gvnc);
-	fmt->blue_max        = gvnc_read_u16(gvnc);
-
-	fmt->red_shift       = gvnc_read_u8(gvnc);
-	fmt->green_shift     = gvnc_read_u8(gvnc);
-	fmt->blue_shift      = gvnc_read_u8(gvnc);
-
-	gvnc_read(gvnc, pad, 3);
-
-	GVNC_DEBUG("Pixel format BPP: %d,  Depth: %d, Byte order: %d, True color: %d\n"
-		   "             Mask  red: %3d, green: %3d, blue: %3d\n"
-		   "             Shift red: %3d, green: %3d, blue: %3d",
-		   fmt->bits_per_pixel, fmt->depth, fmt->byte_order, fmt->true_color_flag,
-		   fmt->red_max, fmt->green_max, fmt->blue_max,
-		   fmt->red_shift, fmt->green_shift, fmt->blue_shift);
-}
-
-/* initialize function */
-
-gboolean gvnc_has_error(struct gvnc *gvnc)
-{
-	return gvnc->has_error;
-}
-
-gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
-			       const struct gvnc_pixel_format *fmt)
-{
-	guint8 pad[3] = {0};
-
-	gvnc_write_u8(gvnc, 0);
-	gvnc_write(gvnc, pad, 3);
-
-	gvnc_write_u8(gvnc, fmt->bits_per_pixel);
-	gvnc_write_u8(gvnc, fmt->depth);
-	gvnc_write_u8(gvnc, fmt->byte_order == G_BIG_ENDIAN ? 1 : 0);
-	gvnc_write_u8(gvnc, fmt->true_color_flag);
-
-	gvnc_write_u16(gvnc, fmt->red_max);
-	gvnc_write_u16(gvnc, fmt->green_max);
-	gvnc_write_u16(gvnc, fmt->blue_max);
-
-	gvnc_write_u8(gvnc, fmt->red_shift);
-	gvnc_write_u8(gvnc, fmt->green_shift);
-	gvnc_write_u8(gvnc, fmt->blue_shift);
-
-	gvnc_write(gvnc, pad, 3);
-	gvnc_flush(gvnc);
-
-	if (&gvnc->fmt != fmt)
-		memcpy(&gvnc->fmt, fmt, sizeof(*fmt));
-
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, gint32 *encoding)
-{
-	guint8 pad[1] = {0};
-	int i, skip_zrle=0;
-
-	/*
-	 * RealVNC server is broken for ZRLE in some pixel formats.
-	 * Specifically if you have a format with either R, G or B
-	 * components with a max value > 255, it still uses a CPIXEL
-	 * of 3 bytes, even though the colour requirs 4 bytes. It
-	 * thus messes up the colours of the server in a way we can't
-	 * recover from on the client. Most VNC clients don't see this
-	 * problem since they send a 'set pixel format' message instead
-	 * of running with the server's default format.
-	 *
-	 * So we kill off ZRLE encoding for problematic pixel formats
-	 */
-	for (i = 0; i < n_encoding; i++)
-		if (gvnc->fmt.depth == 32 &&
-		    (gvnc->fmt.red_max > 255 ||
-		     gvnc->fmt.blue_max > 255 ||
-		     gvnc->fmt.green_max > 255) &&
-		    encoding[i] == GVNC_ENCODING_ZRLE) {
-			GVNC_DEBUG("Dropping ZRLE encoding for broken pixel format");
-			skip_zrle++;
-		}
-
-	gvnc->has_ext_key_event = FALSE;
-	gvnc_write_u8(gvnc, 2);
-	gvnc_write(gvnc, pad, 1);
-	gvnc_write_u16(gvnc, n_encoding - skip_zrle);
-	for (i = 0; i < n_encoding; i++) {
-		if (skip_zrle && encoding[i] == GVNC_ENCODING_ZRLE)
-			continue;
-		gvnc_write_s32(gvnc, encoding[i]);
-	}
-	gvnc_flush(gvnc);
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
-					 guint8 incremental,
-					 guint16 x, guint16 y,
-					 guint16 width, guint16 height)
-{
-	gvnc_write_u8(gvnc, 3);
-	gvnc_write_u8(gvnc, incremental);
-	gvnc_write_u16(gvnc, x);
-	gvnc_write_u16(gvnc, y);
-	gvnc_write_u16(gvnc, width);
-	gvnc_write_u16(gvnc, height);
-	gvnc_flush(gvnc);
-	return !gvnc_has_error(gvnc);
-}
-
-static void gvnc_buffered_write(struct gvnc *gvnc, const void *data, size_t size)
-{
-	size_t left;
-
-	left = gvnc->xmit_buffer_capacity - gvnc->xmit_buffer_size;
-	if (left < size) {
-		gvnc->xmit_buffer_capacity += size + 4095;
-		gvnc->xmit_buffer_capacity &= ~4095;
-
-		gvnc->xmit_buffer = g_realloc(gvnc->xmit_buffer, gvnc->xmit_buffer_capacity);
-	}
-
-	memcpy(&gvnc->xmit_buffer[gvnc->xmit_buffer_size],
-	       data, size);
-
-	gvnc->xmit_buffer_size += size;
-}
-
-static void gvnc_buffered_write_u8(struct gvnc *gvnc, guint8 value)
-{
-	gvnc_buffered_write(gvnc, &value, 1);
-}
-
-static void gvnc_buffered_write_u16(struct gvnc *gvnc, guint16 value)
-{
-	value = htons(value);
-	gvnc_buffered_write(gvnc, &value, 2);
-}
-
-static void gvnc_buffered_write_u32(struct gvnc *gvnc, guint32 value)
-{
-	value = htonl(value);
-	gvnc_buffered_write(gvnc, &value, 4);
-}
-
-static void gvnc_buffered_flush(struct gvnc *gvnc)
-{
-	g_io_wakeup(&gvnc->wait);
-}
-
-gboolean gvnc_key_event(struct gvnc *gvnc, guint8 down_flag,
-			guint32 key, guint16 scancode)
-{
-	guint8 pad[2] = {0};
-
-	GVNC_DEBUG("Key event %d %d %d %d", key, scancode, down_flag, gvnc->has_ext_key_event);
-	if (gvnc->has_ext_key_event) {
-		scancode = x_keycode_to_pc_keycode(gvnc->keycode_map, scancode);
-
-		gvnc_buffered_write_u8(gvnc, 255);
-		gvnc_buffered_write_u8(gvnc, 0);
-		gvnc_buffered_write_u16(gvnc, down_flag);
-		gvnc_buffered_write_u32(gvnc, key);
-		gvnc_buffered_write_u32(gvnc, scancode);
-	} else {
-		gvnc_buffered_write_u8(gvnc, 4);
-		gvnc_buffered_write_u8(gvnc, down_flag);
-		gvnc_buffered_write(gvnc, pad, 2);
-		gvnc_buffered_write_u32(gvnc, key);
-	}
-
-	gvnc_buffered_flush(gvnc);
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_pointer_event(struct gvnc *gvnc, guint8 button_mask,
-			    guint16 x, guint16 y)
-{
-	gvnc_buffered_write_u8(gvnc, 5);
-	gvnc_buffered_write_u8(gvnc, button_mask);
-	gvnc_buffered_write_u16(gvnc, x);
-	gvnc_buffered_write_u16(gvnc, y);
-	gvnc_buffered_flush(gvnc);
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_client_cut_text(struct gvnc *gvnc,
-			      const void *data, size_t length)
-{
-	guint8 pad[3] = {0};
-
-	gvnc_buffered_write_u8(gvnc, 6);
-	gvnc_buffered_write(gvnc, pad, 3);
-	gvnc_buffered_write_u32(gvnc, length);
-	gvnc_buffered_write(gvnc, data, length);
-	gvnc_buffered_flush(gvnc);
-	return !gvnc_has_error(gvnc);
-}
-
-static inline guint8 *gvnc_get_local(struct gvnc *gvnc, int x, int y)
-{
-	return gvnc->local.data +
-		(y * gvnc->local.linesize) +
-		(x * gvnc->local.bpp);
-}
-
-static guint8 gvnc_swap_img_8(struct gvnc *gvnc G_GNUC_UNUSED, guint8 pixel)
-{
-	return pixel;
-}
-
-static guint8 gvnc_swap_rfb_8(struct gvnc *gvnc G_GNUC_UNUSED, guint8 pixel)
-{
-	return pixel;
-}
-
-/* local host native format -> X server image format */
-static guint16 gvnc_swap_img_16(struct gvnc *gvnc, guint16 pixel)
-{
-	if (G_BYTE_ORDER != gvnc->local.byte_order)
-		return  (((pixel >> 8) & 0xFF) << 0) |
-			(((pixel >> 0) & 0xFF) << 8);
-	else
-		return pixel;
-}
-
-/* VNC server RFB  format ->  local host native format */
-static guint16 gvnc_swap_rfb_16(struct gvnc *gvnc, guint16 pixel)
-{
-	if (gvnc->fmt.byte_order != G_BYTE_ORDER)
-		return  (((pixel >> 8) & 0xFF) << 0) |
-			(((pixel >> 0) & 0xFF) << 8);
-	else
-		return pixel;
-}
-
-/* local host native format -> X server image format */
-static guint32 gvnc_swap_img_32(struct gvnc *gvnc, guint32 pixel)
-{
-	if (G_BYTE_ORDER != gvnc->local.byte_order)
-		return  (((pixel >> 24) & 0xFF) <<  0) |
-			(((pixel >> 16) & 0xFF) <<  8) |
-			(((pixel >>  8) & 0xFF) << 16) |
-			(((pixel >>  0) & 0xFF) << 24);
-	else
-		return pixel;
-}
-
-/* VNC server RFB  format ->  local host native format */
-static guint32 gvnc_swap_rfb_32(struct gvnc *gvnc, guint32 pixel)
-{
-	if (gvnc->fmt.byte_order != G_BYTE_ORDER)
-		return  (((pixel >> 24) & 0xFF) <<  0) |
-			(((pixel >> 16) & 0xFF) <<  8) |
-			(((pixel >>  8) & 0xFF) << 16) |
-			(((pixel >>  0) & 0xFF) << 24);
-	else
-		return pixel;
-}
-
-#define SPLICE_I(a, b) a ## b
-#define SPLICE(a, b) SPLICE_I(a, b)
-
-#define SRC 8
-#include "blt1.h"
-#undef SRC
-
-#define SRC 16
-#include "blt1.h"
-#undef SRC
-
-#define SRC 32
-#include "blt1.h"
-#undef SRC
-
-static gvnc_blt_func *gvnc_blt_table[3][3] = {
-	{  gvnc_blt_8x8,  gvnc_blt_8x16,  gvnc_blt_8x32 },
-	{ gvnc_blt_16x8, gvnc_blt_16x16, gvnc_blt_16x32 },
-	{ gvnc_blt_32x8, gvnc_blt_32x16, gvnc_blt_32x32 },
-};
-
-static gvnc_hextile_func *gvnc_hextile_table[3][3] = {
-	{ (gvnc_hextile_func *)gvnc_hextile_8x8,
-	  (gvnc_hextile_func *)gvnc_hextile_8x16,
-	  (gvnc_hextile_func *)gvnc_hextile_8x32 },
-	{ (gvnc_hextile_func *)gvnc_hextile_16x8,
-	  (gvnc_hextile_func *)gvnc_hextile_16x16,
-	  (gvnc_hextile_func *)gvnc_hextile_16x32 },
-	{ (gvnc_hextile_func *)gvnc_hextile_32x8,
-	  (gvnc_hextile_func *)gvnc_hextile_32x16,
-	  (gvnc_hextile_func *)gvnc_hextile_32x32 },
-};
-
-static gvnc_set_pixel_at_func *gvnc_set_pixel_at_table[3][3] = {
-	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x8,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x16,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x32 },
-	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x8,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x16,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x32 },
-	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x8,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x16,
-	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x32 },
-};
-
-static gvnc_fill_func *gvnc_fill_table[3][3] = {
-	{ (gvnc_fill_func *)gvnc_fill_8x8,
-	  (gvnc_fill_func *)gvnc_fill_8x16,
-	  (gvnc_fill_func *)gvnc_fill_8x32 },
-	{ (gvnc_fill_func *)gvnc_fill_16x8,
-	  (gvnc_fill_func *)gvnc_fill_16x16,
-	  (gvnc_fill_func *)gvnc_fill_16x32 },
-	{ (gvnc_fill_func *)gvnc_fill_32x8,
-	  (gvnc_fill_func *)gvnc_fill_32x16,
-	  (gvnc_fill_func *)gvnc_fill_32x32 },
-};
-
-static gvnc_rich_cursor_blt_func *gvnc_rich_cursor_blt_table[3] = {
-	gvnc_rich_cursor_blt_8x32,
-	gvnc_rich_cursor_blt_16x32,
-	gvnc_rich_cursor_blt_32x32,
-};
-
-static gvnc_rgb24_blt_func *gvnc_rgb24_blt_table[3] = {
-	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x8,
-	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x16,
-	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x32,
-};
-
-static gvnc_tight_compute_predicted_func *gvnc_tight_compute_predicted_table[3] = {
-	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_8x8,
-	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_16x16,
-	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_32x32,
-};
-
-static gvnc_tight_sum_pixel_func *gvnc_tight_sum_pixel_table[3] = {
-	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_8x8,
-	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_16x16,
-	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_32x32,
-};
-
-/* a fast blit for the perfect match scenario */
-static void gvnc_blt_fast(struct gvnc *gvnc, guint8 *src, int pitch,
-			  int x, int y, int width, int height)
-{
-	guint8 *dst = gvnc_get_local(gvnc, x, y);
-	int i;
-	for (i = 0; i < height; i++) {
-		memcpy(dst, src, width * gvnc->local.bpp);
-		dst += gvnc->local.linesize;
-		src += pitch;
-	}
-}
-
-static void gvnc_blt(struct gvnc *gvnc, guint8 *src, int pitch,
-		     int x, int y, int width, int height)
-{
-	gvnc->blt(gvnc, src, pitch, x, y, width, height);
-}
-
-static void gvnc_raw_update(struct gvnc *gvnc,
-			    guint16 x, guint16 y,
-			    guint16 width, guint16 height)
-{
-	guint8 *dst;
-	int i;
-
-	/* optimize for perfect match between server/client
-	   FWIW, in the local case, we ought to be doing a write
-	   directly from the source framebuffer and a read directly
-	   into the client framebuffer
-	 */
-	if (gvnc->perfect_match) {
-		dst = gvnc_get_local(gvnc, x, y);
-		for (i = 0; i < height; i++) {
-			gvnc_read(gvnc, dst, width * gvnc->local.bpp);
-			dst += gvnc->local.linesize;
-		}
-		return;
-	}
-
-	dst = g_malloc(width * (gvnc->fmt.bits_per_pixel / 8));
-	for (i = 0; i < height; i++) {
-		gvnc_read(gvnc, dst, width * (gvnc->fmt.bits_per_pixel / 8));
-		gvnc_blt(gvnc, dst, 0, x, y + i, width, 1);
-	}
-	g_free(dst);
-}
-
-static void gvnc_copyrect_update(struct gvnc *gvnc,
-				 guint16 dst_x, guint16 dst_y,
-				 guint16 width, guint16 height)
-{
-	int src_x, src_y;
-	guint8 *dst, *src;
-	int pitch = gvnc->local.linesize;
-	int i;
-
-	src_x = gvnc_read_u16(gvnc);
-	src_y = gvnc_read_u16(gvnc);
-
-	if (src_y < dst_y) {
-		pitch = -pitch;
-		src_y += (height - 1);
-		dst_y += (height - 1);
-	}
-
-	dst = gvnc_get_local(gvnc, dst_x, dst_y);
-	src = gvnc_get_local(gvnc, src_x, src_y);
-	for (i = 0; i < height; i++) {
-		memmove(dst, src, width * gvnc->local.bpp);
-		dst += pitch;
-		src += pitch;
-	}
-}
-
-static void gvnc_hextile_update(struct gvnc *gvnc,
-				guint16 x, guint16 y,
-				guint16 width, guint16 height)
-{
-	guint8 fg[4];
-	guint8 bg[4];
-
-	int j;
-	for (j = 0; j < height; j += 16) {
-		int i;
-		for (i = 0; i < width; i += 16) {
-			guint8 flags;
-			int w = MIN(16, width - i);
-			int h = MIN(16, height - j);
-
-			flags = gvnc_read_u8(gvnc);
-			gvnc->hextile(gvnc, flags, x + i, y + j, w, h, fg, bg);
-		}
-	}
-}
-
-static void gvnc_fill(struct gvnc *gvnc, guint8 *color,
-		      guint16 x, guint16 y, guint16 width, guint16 height)
-{
-	gvnc->fill(gvnc, color, x, y, width, height);
-}
-
-static void gvnc_set_pixel_at(struct gvnc *gvnc, int x, int y, guint8 *pixel)
-{
-	gvnc->set_pixel_at(gvnc, x, y, pixel);
-}
-
-static void gvnc_rre_update(struct gvnc *gvnc,
-			    guint16 x, guint16 y,
-			    guint16 width, guint16 height)
-{
-	guint8 bg[4];
-	guint32 num;
-	guint32 i;
-
-	num = gvnc_read_u32(gvnc);
-	gvnc_read_pixel(gvnc, bg);
-	gvnc_fill(gvnc, bg, x, y, width, height);
-
-	for (i = 0; i < num; i++) {
-		guint8 fg[4];
-		guint16 sub_x, sub_y, sub_w, sub_h;
-
-		gvnc_read_pixel(gvnc, fg);
-		sub_x = gvnc_read_u16(gvnc);
-		sub_y = gvnc_read_u16(gvnc);
-		sub_w = gvnc_read_u16(gvnc);
-		sub_h = gvnc_read_u16(gvnc);
-
-		gvnc_fill(gvnc, fg,
-			  x + sub_x, y + sub_y, sub_w, sub_h);
-	}
-}
-
-/* CPIXELs are optimized slightly.  32-bit pixel values are packed into 24-bit
- * values. */
-static void gvnc_read_cpixel(struct gvnc *gvnc, guint8 *pixel)
-{
-	int bpp = gvnc_pixel_size(gvnc);
-
-	memset(pixel, 0, bpp);
-
-	if (bpp == 4 && gvnc->fmt.true_color_flag) {
-		int fitsInMSB = ((gvnc->fmt.red_shift > 7) &&
-				 (gvnc->fmt.green_shift > 7) &&
-				 (gvnc->fmt.blue_shift > 7));
-		int fitsInLSB = (((gvnc->fmt.red_max << gvnc->fmt.red_shift) < (1 << 24)) &&
-				 ((gvnc->fmt.green_max << gvnc->fmt.green_shift) < (1 << 24)) &&
-				 ((gvnc->fmt.blue_max << gvnc->fmt.blue_shift) < (1 << 24)));
-
-		/*
-		 * We need to analyse the shifts to see if they fit in 3 bytes,
-		 * rather than looking at the declared  'depth' for the format
-		 * because despite what the RFB spec says, this is what RealVNC
-		 * server actually does in practice.
-		 */
-		if (fitsInMSB || fitsInLSB) {
-			bpp = 3;
-			if (gvnc->fmt.depth == 24 &&
-			    gvnc->fmt.byte_order == G_BIG_ENDIAN)
-				pixel++;
-		}
-	}
-
-	gvnc_read(gvnc, pixel, bpp);
-}
-
-static void gvnc_zrle_update_tile_blit(struct gvnc *gvnc,
-				       guint16 x, guint16 y,
-				       guint16 width, guint16 height)
-{
-	guint8 blit_data[4 * 64 * 64];
-	int i, bpp;
-
-	bpp = gvnc_pixel_size(gvnc);
-
-	for (i = 0; i < width * height; i++)
-		gvnc_read_cpixel(gvnc, blit_data + (i * bpp));
-
-	gvnc_blt(gvnc, blit_data, width * bpp, x, y, width, height);
-}
-
-static guint8 gvnc_read_zrle_pi(struct gvnc *gvnc, int palette_size)
-{
-	guint8 pi = 0;
-
-	if (gvnc->zrle_pi_bits == 0) {
-		gvnc->zrle_pi = gvnc_read_u8(gvnc);
-		gvnc->zrle_pi_bits = 8;
-	}
-	if ( palette_size == 2) {
-		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 1)) & 1;
-		gvnc->zrle_pi_bits -= 1;
-	} else if ((palette_size == 3) || (palette_size == 4)) {
-		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 2)) & 3;
-		gvnc->zrle_pi_bits -= 2;
-	} else if ((palette_size >=5) && (palette_size <=16)){
-		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 4)) & 15;
-		gvnc->zrle_pi_bits -= 4;
-	}
-
-	return pi;
-}
-
-static void gvnc_zrle_update_tile_palette(struct gvnc *gvnc,
-					  guint8 palette_size,
-					  guint16 x, guint16 y,
-					  guint16 width, guint16 height)
-{
-	guint8 palette[128][4];
-	int i, j;
-
-	for (i = 0; i < palette_size; i++)
-		gvnc_read_cpixel(gvnc, palette[i]);
-
-	for (j = 0; j < height; j++) {
-		/* discard any padding bits */
-		gvnc->zrle_pi_bits = 0;
-
-		for (i = 0; i < width; i++) {
-			int ind = gvnc_read_zrle_pi(gvnc, palette_size);
-
-			gvnc_set_pixel_at(gvnc, x + i, y + j,
-					  palette[ind & 0x7F]);
-		}
-	}
-}
-
-static int gvnc_read_zrle_rl(struct gvnc *gvnc)
-{
-	int rl = 1;
-	guint8 b;
-
-	do {
-		b = gvnc_read_u8(gvnc);
-		rl += b;
-	} while (!gvnc_has_error(gvnc) && b == 255);
-
-	return rl;
-}
-
-static void gvnc_zrle_update_tile_rle(struct gvnc *gvnc,
-				      guint16 x, guint16 y,
-				      guint16 width, guint16 height)
-{
-	int i, j, rl = 0;
-	guint8 pixel[4];
-
-	for (j = 0; j < height; j++) {
-		for (i = 0; i < width; i++) {
-			if (rl == 0) {
-				gvnc_read_cpixel(gvnc, pixel);
-				rl = gvnc_read_zrle_rl(gvnc);
-			}
-			gvnc_set_pixel_at(gvnc, x + i, y + j, pixel);
-			rl -= 1;
-		}
-	}
-}
-
-static void gvnc_zrle_update_tile_prle(struct gvnc *gvnc,
-				       guint8 palette_size,
-				       guint16 x, guint16 y,
-				       guint16 width, guint16 height)
-{
-	int i, j, rl = 0;
-	guint8 palette[128][4];
-	guint8 pi = 0;
-
-	for (i = 0; i < palette_size; i++)
-		gvnc_read_cpixel(gvnc, palette[i]);
-
-	for (j = 0; j < height; j++) {
-		for (i = 0; i < width; i++) {
-			if (rl == 0) {
-				pi = gvnc_read_u8(gvnc);
-				if (pi & 0x80) {
-					rl = gvnc_read_zrle_rl(gvnc);
-					pi &= 0x7F;
-				} else
-					rl = 1;
-			}
-
-			gvnc_set_pixel_at(gvnc, x + i, y + j, palette[pi]);
-			rl -= 1;
-		}
-	}
-}
-
-static void gvnc_zrle_update_tile(struct gvnc *gvnc, guint16 x, guint16 y,
-				  guint16 width, guint16 height)
-{
-	guint8 subencoding = gvnc_read_u8(gvnc);
-	guint8 pixel[4];
-
-	if (subencoding == 0 ) {
-		/* Raw pixel data */
-		gvnc_zrle_update_tile_blit(gvnc, x, y, width, height);
-	} else if (subencoding == 1) {
-		/* Solid tile of a single color */
-		gvnc_read_cpixel(gvnc, pixel);
-		gvnc_fill(gvnc, pixel, x, y, width, height);
-	} else if ((subencoding >= 2) && (subencoding <= 16)) {
-		/* Packed palette types */
-		gvnc_zrle_update_tile_palette(gvnc, subencoding,
-					      x, y, width, height);
-	} else if ((subencoding >= 17) && (subencoding <= 127)) {
-		/* FIXME raise error? */
-	} else if (subencoding == 128) {
-		/* Plain RLE */
-		gvnc_zrle_update_tile_rle(gvnc, x, y, width, height);
-	} else if (subencoding == 129) {
-
-	} else if (subencoding >= 130) {
-		/* Palette RLE */
-		gvnc_zrle_update_tile_prle(gvnc, subencoding - 128,
-					   x, y, width, height);
-	}
-}
-
-static void gvnc_zrle_update(struct gvnc *gvnc,
-			     guint16 x, guint16 y,
-			     guint16 width, guint16 height)
-
-{
-	guint32 length;
-	guint32 offset;
-	guint16 i, j;
-	guint8 *zlib_data;
-
-	length = gvnc_read_u32(gvnc);
-	zlib_data = g_malloc(length);
-	gvnc_read(gvnc, zlib_data, length);
-
-	/* setup subsequent calls to gvnc_read*() to use the compressed data */
-	gvnc->uncompressed_length = 0;
-	gvnc->compressed_length = length;
-	gvnc->compressed_buffer = zlib_data;
-	gvnc->strm = &gvnc->streams[0];
-
-	offset = 0;
-	for (j = 0; j < height; j += 64) {
-		for (i = 0; i < width; i += 64) {
-			guint16 w, h;
-
-			w = MIN(width - i, 64);
-			h = MIN(height - j, 64);
-			gvnc_zrle_update_tile(gvnc, x + i, y + j, w, h);
-		}
-	}
-
-	gvnc->strm = NULL;
-	gvnc->uncompressed_length = 0;
-	gvnc->compressed_length = 0;
-	gvnc->compressed_buffer = NULL;
-
-	g_free(zlib_data);
-}
-
-static void gvnc_rgb24_blt(struct gvnc *gvnc, int x, int y,
-			   int width, int height, guint8 *data, int pitch)
-{
-	gvnc->rgb24_blt(gvnc, x, y, width, height, data, pitch);
-}
-
-static guint32 gvnc_read_cint(struct gvnc *gvnc)
-{
-	guint32 value = 0;
-	guint8 val;
-
-	val = gvnc_read_u8(gvnc);
-	value = (val & 0x7F);
-	if (!(val & 0x80))
-		return value;
-
-	val = gvnc_read_u8(gvnc);
-	value |= (val & 0x7F) << 7;
-
-	if (!(val & 0x80))
-		return value;
-
-	value |= gvnc_read_u8(gvnc) << 14;
-
-	return value;
-}
-
-static int gvnc_tpixel_size(struct gvnc *gvnc)
-{
-	if (gvnc->fmt.depth == 24)
-		return 3;
-	return gvnc->fmt.bits_per_pixel / 8;
-}
-
-static void gvnc_read_tpixel(struct gvnc *gvnc, guint8 *pixel)
-{
-	if (gvnc->fmt.depth == 24) {
-		guint32 val;
-		gvnc_read(gvnc, pixel, 3);
-		val = (pixel[0] << gvnc->fmt.red_shift)
-			| (pixel[1] << gvnc->fmt.green_shift)
-			| (pixel[2] << gvnc->fmt.blue_shift);
-
-		if (gvnc->fmt.byte_order != G_BYTE_ORDER)
-			val =   (((val >>  0) & 0xFF) << 24) |
-				(((val >>  8) & 0xFF) << 16) |
-				(((val >> 16) & 0xFF) << 8) |
-				(((val >> 24) & 0xFF) << 0);
-
-		memcpy(pixel, &val, 4);
-	} else
-		gvnc_read_pixel(gvnc, pixel);
-}
-
-static void gvnc_tight_update_copy(struct gvnc *gvnc,
-				   guint16 x, guint16 y,
-				   guint16 width, guint16 height)
-{
-	guint8 pixel[4];
-	int i, j;
-
-	for (j = 0; j < height; j++) {
-		for (i = 0; i < width; i++) {
-			gvnc_read_tpixel(gvnc, pixel);
-			gvnc_set_pixel_at(gvnc, x + i, y + j, pixel);
-		}
-	}
-}
-
-static int gvnc_tight_get_pi(struct gvnc *gvnc, guint8 *ra,
-			     int i, guint8 palette_size)
-{
-	if (palette_size == 2) {
-		if ((i % 8) == 0)
-			*ra = gvnc_read_u8(gvnc);
-		return (*ra >> (7 - (i % 8))) & 1;
-	}
-
-	return gvnc_read_u8(gvnc);
-}
-
-static void gvnc_tight_update_palette(struct gvnc *gvnc,
-				      int palette_size, guint8 *palette,
-				      guint16 x, guint16 y,
-				      guint16 width, guint16 height)
-{
-	int i, j;
-
-	for (j = 0; j < height; j++) {
-		guint8 ra = 0;
-
-		for (i = 0; i < width; i++) {
-			guint8 ind;
-
-			ind = gvnc_tight_get_pi(gvnc, &ra, i, palette_size);
-			gvnc_set_pixel_at(gvnc, x + i, y + j,
-					  &palette[ind * 4]);
-		}
-	}
-}
-
-static void gvnc_tight_compute_predicted(struct gvnc *gvnc, guint8 *ppixel,
-					  guint8 *lp, guint8 *cp,
-					  guint8 *llp)
-{
-	gvnc->tight_compute_predicted(gvnc, ppixel, lp, cp, llp);
-}
-
-static void gvnc_tight_sum_pixel(struct gvnc *gvnc,
-				 guint8 *lhs, guint8 *rhs)
-{
-	gvnc->tight_sum_pixel(gvnc, lhs, rhs);
-}
-
-static void gvnc_tight_update_gradient(struct gvnc *gvnc,
-				       guint16 x, guint16 y,
-				       guint16 width, guint16 height)
-{
-	int i, j;
-	guint8 zero_pixel[4];
-	guint8 *last_row, *row;
-	int bpp;
-
-	bpp = gvnc_pixel_size(gvnc);
-	last_row = g_malloc(width * bpp);
-	row = g_malloc(width * bpp);
-
-	memset(last_row, 0, width * bpp);
-	memset(zero_pixel, 0, 4);
-
-	for (j = 0; j < height; j++) {
-		guint8 *tmp_row;
-		guint8 *llp, *lp;
-
-		/* use zero pixels for the edge cases */
-		llp = zero_pixel;
-		lp = zero_pixel;
-
-		for (i = 0; i < width; i++) {
-			guint8 predicted_pixel[4];
-
-			/* compute predicted pixel value */
-			gvnc_tight_compute_predicted(gvnc, predicted_pixel,
-						     lp, last_row + i * bpp,
-						     llp);
-
-			/* read the difference pixel from the wire */
-			gvnc_read_tpixel(gvnc, row + i * bpp);
-
-			/* sum the predicted pixel and the difference to get
-			 * the original pixel value */
-			gvnc_tight_sum_pixel(gvnc, row + i * bpp,
-					     predicted_pixel);
-
-			llp = last_row + i * bpp;
-			lp = row + i * bpp;
-		}
-
-		/* write out row of pixel data */
-		gvnc_blt(gvnc, row, width * bpp, x, y + j, width, 1);
-
-		/* swap last row and current row */
-		tmp_row = last_row;
-		last_row = row;
-		row = tmp_row;
-	}
-
-	g_free(row);
-	g_free(last_row);
-}
-
-static void jpeg_draw(void *opaque, int x, int y, int w, int h,
-		      guint8 *data, int stride)
-{
-	struct gvnc *gvnc = opaque;
-
-	gvnc_rgb24_blt(gvnc, x, y, w, h, data, stride);
-}
-
-static void gvnc_tight_update_jpeg(struct gvnc *gvnc, guint16 x, guint16 y,
-				   guint16 width, guint16 height,
-				   guint8 *data, size_t length)
-{
-	if (gvnc->ops.render_jpeg == NULL)
-		return;
-
-	gvnc->ops.render_jpeg(gvnc->ops_data, jpeg_draw, gvnc,
-			      x, y, width, height, data, length);
-}
-
-static void gvnc_tight_update(struct gvnc *gvnc,
-			      guint16 x, guint16 y,
-			      guint16 width, guint16 height)
-{
-	guint8 ccontrol;
-	guint8 pixel[4];
-	int i;
-
-	ccontrol = gvnc_read_u8(gvnc);
-
-	for (i = 0; i < 4; i++) {
-		if (ccontrol & (1 << i)) {
-			inflateEnd(&gvnc->streams[i + 1]);
-			inflateInit(&gvnc->streams[i + 1]);
-		}
-	}
-
-	ccontrol >>= 4;
-	ccontrol &= 0x0F;
-
-	if (ccontrol <= 7) {
-		/* basic */
-		guint8 filter_id = 0;
-		guint32 data_size, zlib_length;
-		guint8 *zlib_data = NULL;
-		guint8 palette[256][4];
-		int palette_size = 0;
-
-		if (ccontrol & 0x04)
-			filter_id = gvnc_read_u8(gvnc);
-
-		gvnc->strm = &gvnc->streams[(ccontrol & 0x03) + 1];
-
-		if (filter_id == 1) {
-			palette_size = gvnc_read_u8(gvnc);
-			palette_size += 1;
-			for (i = 0; i < palette_size; i++)
-				gvnc_read_tpixel(gvnc, palette[i]);
-		}
-
-		if (filter_id == 1) {
-			if (palette_size == 2)
-				data_size = ((width + 7) / 8) * height;
-			else
-				data_size = width * height;
-		} else
-			data_size = width * height * gvnc_tpixel_size(gvnc);
-
-		if (data_size >= 12) {
-			zlib_length = gvnc_read_cint(gvnc);
-			zlib_data = g_malloc(zlib_length);
-
-			gvnc_read(gvnc, zlib_data, zlib_length);
-
-			gvnc->uncompressed_length = 0;
-			gvnc->compressed_length = zlib_length;
-			gvnc->compressed_buffer = zlib_data;
-		}
-
-		switch (filter_id) {
-		case 0: /* copy */
-			gvnc_tight_update_copy(gvnc, x, y, width, height);
-			break;
-		case 1: /* palette */
-			gvnc_tight_update_palette(gvnc, palette_size,
-						  (guint8 *)palette,
-						  x, y, width, height);
-			break;
-		case 2: /* gradient */
-			gvnc_tight_update_gradient(gvnc, x, y, width, height);
-			break;
-		default: /* error */
-			GVNC_DEBUG("Closing the connection: gvnc_tight_update() - filter_id unknown");
-			gvnc->has_error = TRUE;
-			break;
-		}
-
-		if (data_size >= 12) {
-			gvnc->uncompressed_length = 0;
-			gvnc->compressed_length = 0;
-			gvnc->compressed_buffer = NULL;
-
-			g_free(zlib_data);
-		}
-
-		gvnc->strm = NULL;
-	} else if (ccontrol == 8) {
-		/* fill */
-		/* FIXME check each width; endianness */
-		gvnc_read_tpixel(gvnc, pixel);
-		gvnc_fill(gvnc, pixel, x, y, width, height);
-	} else if (ccontrol == 9) {
-		/* jpeg */
-		guint32 length;
-		guint8 *jpeg_data;
-
-		length = gvnc_read_cint(gvnc);
-		jpeg_data = g_malloc(length);
-		gvnc_read(gvnc, jpeg_data, length);
-		gvnc_tight_update_jpeg(gvnc, x, y, width, height,
-				       jpeg_data, length);
-		g_free(jpeg_data);
-	} else {
-		/* error */
-		GVNC_DEBUG("Closing the connection: gvnc_tight_update() - ccontrol unknown");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_update(struct gvnc *gvnc, int x, int y, int width, int height)
-{
-	if (gvnc->has_error || !gvnc->ops.update)
-		return;
-	if (!gvnc->ops.update(gvnc->ops_data, x, y, width, height)) {
-		GVNC_DEBUG("Closing the connection: gvnc_update");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_set_color_map_entry(struct gvnc *gvnc, guint16 color,
-				     guint16 red, guint16 green,
-				     guint16 blue)
-{
-	if (gvnc->has_error || !gvnc->ops.set_color_map_entry)
-		return;
-	if (!gvnc->ops.set_color_map_entry(gvnc->ops_data, color,
-					    red, green, blue)) {
-		GVNC_DEBUG("Closing the connection: gvnc_set_color_map_entry");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_bell(struct gvnc *gvnc)
-{
-	if (gvnc->has_error || !gvnc->ops.bell)
-		return;
-
-	GVNC_DEBUG("Server beep");
-
-	if (!gvnc->ops.bell(gvnc->ops_data)) {
-		GVNC_DEBUG("Closing the connection: gvnc_bell");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_server_cut_text(struct gvnc *gvnc, const void *data,
-				 size_t len)
-{
-	if (gvnc->has_error || !gvnc->ops.server_cut_text)
-		return;
-
-	if (!gvnc->ops.server_cut_text(gvnc->ops_data, data, len)) {
-		GVNC_DEBUG("Closing the connection: gvnc_server_cut_text");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_resize(struct gvnc *gvnc, int width, int height)
-{
-	if (gvnc->has_error)
-		return;
-
-	gvnc->width = width;
-	gvnc->height = height;
-
-	if (!gvnc->ops.resize)
-		return;
-
-	if (!gvnc->ops.resize(gvnc->ops_data, width, height)) {
-		GVNC_DEBUG("Closing the connection: gvnc_resize");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_pixel_format(struct gvnc *gvnc)
-{
-        if (gvnc->has_error || !gvnc->ops.pixel_format)
-                return;
-        if (!gvnc->ops.pixel_format(gvnc->ops_data, &gvnc->fmt))
-                gvnc->has_error = TRUE;
-}
-
-static void gvnc_pointer_type_change(struct gvnc *gvnc, int absolute)
-{
-	if (gvnc->has_error || !gvnc->ops.pointer_type_change)
-		return;
-	if (!gvnc->ops.pointer_type_change(gvnc->ops_data, absolute)) {
-		GVNC_DEBUG("Closing the connection: gvnc_pointer_type_change");
-		gvnc->has_error = TRUE;
-	}
-}
-
-static void gvnc_rich_cursor_blt(struct gvnc *gvnc, guint8 *pixbuf,
-				 guint8 *image, guint8 *mask,
-				 int pitch, guint16 width, guint16 height)
-{
-	gvnc->rich_cursor_blt(gvnc, pixbuf, image, mask, pitch, width, height);
-}
-
-static void gvnc_rich_cursor(struct gvnc *gvnc, int x, int y, int width, int height)
-{
-	guint8 *pixbuf = NULL;
-
-	if (width && height) {
-		guint8 *image, *mask;
-		int imagelen, masklen;
-
-		imagelen = width * height * (gvnc->fmt.bits_per_pixel / 8);
-		masklen = ((width + 7)/8) * height;
-
-		image = g_malloc(imagelen);
-		mask = g_malloc(masklen);
-		pixbuf = g_malloc(width * height * 4); /* RGB-A 8bit */
-
-		gvnc_read(gvnc, image, imagelen);
-		gvnc_read(gvnc, mask, masklen);
-
-		gvnc_rich_cursor_blt(gvnc, pixbuf, image, mask,
-				     width * (gvnc->fmt.bits_per_pixel/8),
-				     width, height);
-
-		g_free(image);
-		g_free(mask);
-	}
-
-	if (gvnc->has_error || !gvnc->ops.local_cursor)
-		return;
-	if (!gvnc->ops.local_cursor(gvnc->ops_data, x, y, width, height, pixbuf)) {
-		GVNC_DEBUG("Closing the connection: gvnc_rich_cursor() - !ops.local_cursor()");
-		gvnc->has_error = TRUE;
-	}
-
-	g_free(pixbuf);
-}
-
-static void gvnc_xcursor(struct gvnc *gvnc, int x, int y, int width, int height)
-{
-	guint8 *pixbuf = NULL;
-
-	if (width && height) {
-		guint8 *data, *mask, *datap, *maskp;
-		guint32 *pixp;
-		int rowlen;
-		int x1, y1;
-		guint8 fgrgb[3], bgrgb[3];
-		guint32 fg, bg;
-		gvnc_read(gvnc, fgrgb, 3);
-		gvnc_read(gvnc, bgrgb, 3);
-		fg = (255 << 24) | (fgrgb[0] << 16) | (fgrgb[1] << 8) | fgrgb[2];
-		bg = (255 << 24) | (bgrgb[0] << 16) | (bgrgb[1] << 8) | bgrgb[2];
-
-		rowlen = ((width + 7)/8);
-		data = g_malloc(rowlen*height);
-		mask = g_malloc(rowlen*height);
-		pixbuf = g_malloc(width * height * 4); /* RGB-A 8bit */
-
-		gvnc_read(gvnc, data, rowlen*height);
-		gvnc_read(gvnc, mask, rowlen*height);
-		datap = data;
-		maskp = mask;
-		pixp = (guint32*)pixbuf;
-		for (y1 = 0; y1 < height; y1++) {
-			for (x1 = 0; x1 < width; x1++) {
-				*pixp++ = ((maskp[x1 / 8] >> (7-(x1 % 8))) & 1) ?
-					(((datap[x1 / 8] >> (7-(x1 % 8))) & 1) ? fg : bg) : 0;
-			}
-			datap += rowlen;
-			maskp += rowlen;
-		}
-		g_free(data);
-		g_free(mask);
-	}
-
-	if (gvnc->has_error || !gvnc->ops.local_cursor)
-		return;
-	if (!gvnc->ops.local_cursor(gvnc->ops_data, x, y, width, height, pixbuf)) {
-		GVNC_DEBUG("Closing the connection: gvnc_xcursor() - !ops.local_cursor()");
-		gvnc->has_error = TRUE;
-	}
-
-	g_free(pixbuf);
-}
-
-static void gvnc_ext_key_event(struct gvnc *gvnc)
-{
-	gvnc->has_ext_key_event = TRUE;
-	gvnc->keycode_map = x_keycode_to_pc_keycode_map();
-}
-
-static void gvnc_framebuffer_update(struct gvnc *gvnc, gint32 etype,
-				    guint16 x, guint16 y,
-				    guint16 width, guint16 height)
-{
-	GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)",
-		   etype, x, y, width, height);
-
-	switch (etype) {
-	case GVNC_ENCODING_RAW:
-		gvnc_raw_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_COPY_RECT:
-		gvnc_copyrect_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_RRE:
-		gvnc_rre_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_HEXTILE:
-		gvnc_hextile_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_ZRLE:
-		gvnc_zrle_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_TIGHT:
-		gvnc_tight_update(gvnc, x, y, width, height);
-		gvnc_update(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_DESKTOP_RESIZE:
-		gvnc_framebuffer_update_request (gvnc, 0, 0, 0, width, height);
-		gvnc_resize(gvnc, width, height);
-		break;
-	case GVNC_ENCODING_POINTER_CHANGE:
-		gvnc_pointer_type_change(gvnc, x);
-		break;
-        case GVNC_ENCODING_WMVi:
-                gvnc_read_pixel_format(gvnc, &gvnc->fmt);
-                gvnc_pixel_format(gvnc);
-                break;
-	case GVNC_ENCODING_RICH_CURSOR:
-		gvnc_rich_cursor(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_XCURSOR:
-		gvnc_xcursor(gvnc, x, y, width, height);
-		break;
-	case GVNC_ENCODING_EXT_KEY_EVENT:
-		gvnc_ext_key_event(gvnc);
-		break;
-	default:
-		GVNC_DEBUG("Received an unknown encoding type: %d", etype);
-		gvnc->has_error = TRUE;
-		break;
-	}
-}
-
-gboolean gvnc_server_message(struct gvnc *gvnc)
-{
-	guint8 msg;
-	int ret;
-
-	/* NB: make sure that all server message functions
-	   handle has_error appropriately */
-
-	do {
-		if (gvnc->xmit_buffer_size) {
-			gvnc_write(gvnc, gvnc->xmit_buffer, gvnc->xmit_buffer_size);
-			gvnc_flush(gvnc);
-			gvnc->xmit_buffer_size = 0;
-		}
-	} while ((ret = gvnc_read_u8_interruptable(gvnc, &msg)) == -EAGAIN);
-
-	if (ret < 0) {
-		GVNC_DEBUG("Aborting message processing on error");
-		return !gvnc_has_error(gvnc);
-	}
-
-	switch (msg) {
-	case 0: { /* FramebufferUpdate */
-		guint8 pad[1];
-		guint16 n_rects;
-		int i;
-
-		gvnc_read(gvnc, pad, 1);
-		n_rects = gvnc_read_u16(gvnc);
-		for (i = 0; i < n_rects; i++) {
-			guint16 x, y, w, h;
-			gint32 etype;
-
-			x = gvnc_read_u16(gvnc);
-			y = gvnc_read_u16(gvnc);
-			w = gvnc_read_u16(gvnc);
-			h = gvnc_read_u16(gvnc);
-			etype = gvnc_read_s32(gvnc);
-
-			gvnc_framebuffer_update(gvnc, etype, x, y, w, h);
-		}
-	}	break;
-	case 1: { /* SetColorMapEntries */
-		guint16 first_color;
-		guint16 n_colors;
-		guint8 pad[1];
-		int i;
-
-		gvnc_read(gvnc, pad, 1);
-		first_color = gvnc_read_u16(gvnc);
-		n_colors = gvnc_read_u16(gvnc);
-
-		for (i = 0; i < n_colors; i++) {
-			guint16 red, green, blue;
-
-			red = gvnc_read_u16(gvnc);
-			green = gvnc_read_u16(gvnc);
-			blue = gvnc_read_u16(gvnc);
-
-			gvnc_set_color_map_entry(gvnc,
-						 i + first_color,
-						 red, green, blue);
-		}
-	}	break;
-	case 2: /* Bell */
-		gvnc_bell(gvnc);
-		break;
-	case 3: { /* ServerCutText */
-		guint8 pad[3];
-		guint32 n_text;
-		char *data;
-
-		gvnc_read(gvnc, pad, 3);
-		n_text = gvnc_read_u32(gvnc);
-		if (n_text > (32 << 20)) {
-			GVNC_DEBUG("Closing the connection: gvnc_server_message() - cutText > allowed");
-			gvnc->has_error = TRUE;
-			break;
-		}
-
-		data = g_new(char, n_text + 1);
-		if (data == NULL) {
-			GVNC_DEBUG("Closing the connection: gvnc_server_message() - cutText - !data");
-			gvnc->has_error = TRUE;
-			break;
-		}
-
-		gvnc_read(gvnc, data, n_text);
-		data[n_text] = 0;
-
-		gvnc_server_cut_text(gvnc, data, n_text);
-		g_free(data);
-	}	break;
-	default:
-		GVNC_DEBUG("Received an unknown message: %u", msg);
-		gvnc->has_error = TRUE;
-		break;
-	}
-
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_wants_credential_password(struct gvnc *gvnc)
-{
-	return gvnc->want_cred_password;
-}
-
-gboolean gvnc_wants_credential_username(struct gvnc *gvnc)
-{
-	return gvnc->want_cred_username;
-}
-
-gboolean gvnc_wants_credential_x509(struct gvnc *gvnc)
-{
-	return gvnc->want_cred_x509;
-}
-
-static gboolean gvnc_has_credentials(gpointer data)
-{
-	struct gvnc *gvnc = (struct gvnc *)data;
-
-	if (gvnc->has_error)
-		return TRUE;
-	if (gvnc_wants_credential_username(gvnc) && !gvnc->cred_username)
-		return FALSE;
-	if (gvnc_wants_credential_password(gvnc) && !gvnc->cred_password)
-		return FALSE;
-	/*
-	 * For x509 we require a minimum of the CA cert.
-	 * Anything else is a bonus - though the server
-	 * may reject auth if it decides it wants a client
-	 * cert. We can't express that based on auth type
-	 * alone though - we'll merely find out when TLS
-	 * negotiation takes place.
-	 */
-	if (gvnc_wants_credential_x509(gvnc) && !gvnc->cred_x509_cacert)
-		return FALSE;
-	return TRUE;
-}
-
-static gboolean gvnc_gather_credentials(struct gvnc *gvnc)
-{
-	if (!gvnc_has_credentials(gvnc)) {
-		GVNC_DEBUG("Requesting missing credentials");
-		if (gvnc->has_error || !gvnc->ops.auth_cred) {
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-		if (!gvnc->ops.auth_cred(gvnc->ops_data))
-		    gvnc->has_error = TRUE;
-		if (gvnc->has_error)
-			return FALSE;
-		GVNC_DEBUG("Waiting for missing credentials");
-		g_condition_wait(gvnc_has_credentials, gvnc);
-		GVNC_DEBUG("Got all credentials");
-	}
-	return !gvnc_has_error(gvnc);
-}
-
-
-static gboolean gvnc_check_auth_result(struct gvnc *gvnc)
-{
-	guint32 result;
-	GVNC_DEBUG("Checking auth result");
-	result = gvnc_read_u32(gvnc);
-	if (!result) {
-		GVNC_DEBUG("Success");
-		return TRUE;
-	}
-
-	if (gvnc->minor >= 8) {
-		guint32 len;
-		char reason[1024];
-		len = gvnc_read_u32(gvnc);
-		if (len > (sizeof(reason)-1))
-			return FALSE;
-		gvnc_read(gvnc, reason, len);
-		reason[len] = '\0';
-		GVNC_DEBUG("Fail %s", reason);
-		if (!gvnc->has_error && gvnc->ops.auth_failure)
-			gvnc->ops.auth_failure(gvnc->ops_data, reason);
-	} else {
-		GVNC_DEBUG("Fail auth no result");
-		if (!gvnc->has_error && gvnc->ops.auth_failure)
-			gvnc->ops.auth_failure(gvnc->ops_data, NULL);
-	}
-	return FALSE;
-}
-
-static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc)
-{
-	guint8 challenge[16];
-	guint8 key[8];
-
-	GVNC_DEBUG("Do Challenge");
-	gvnc->want_cred_password = TRUE;
-	gvnc->want_cred_username = FALSE;
-	gvnc->want_cred_x509 = FALSE;
-	if (!gvnc_gather_credentials(gvnc))
-		return FALSE;
-
-	if (!gvnc->cred_password)
-		return FALSE;
-
-	gvnc_read(gvnc, challenge, 16);
-
-	memset(key, 0, 8);
-	strncpy((char*)key, (char*)gvnc->cred_password, 8);
-
-	deskey(key, EN0);
-	des(challenge, challenge);
-	des(challenge + 8, challenge + 8);
-
-	gvnc_write(gvnc, challenge, 16);
-	gvnc_flush(gvnc);
-	return gvnc_check_auth_result(gvnc);
-}
-
-/*
- *   marscha 2006 - Martin Scharpf
- *   Encrypt bytes[length] in memory using key.
- *   Key has to be 8 bytes, length a multiple of 8 bytes.
- */
-static void
-vncEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
-       int i, j;
-       deskey(key, EN0);
-       for (i = 0; i< 8; i++)
-               where[i] ^= key[i];
-       des(where, where);
-       for (i = 8; i < length; i += 8) {
-               for (j = 0; j < 8; j++)
-                       where[i + j] ^= where[i + j - 8];
-               des(where + i, where + i);
-       }
-}
-
-static gboolean gvnc_perform_auth_mslogon(struct gvnc *gvnc)
-{
-       struct gvnc_dh *dh;
-       guchar gen[8], mod[8], resp[8], pub[8], key[8];
-       gcry_mpi_t genmpi, modmpi, respmpi, pubmpi, keympi;
-       guchar username[256], password[64];
-       guint passwordLen, usernameLen;
-
-       GVNC_DEBUG("Do Challenge");
-       gvnc->want_cred_password = TRUE;
-       gvnc->want_cred_username = TRUE;
-       gvnc->want_cred_x509 = FALSE;
-       if (!gvnc_gather_credentials(gvnc))
-	       return FALSE;
-
-       gvnc_read(gvnc, gen, sizeof(gen));
-       gvnc_read(gvnc, mod, sizeof(mod));
-       gvnc_read(gvnc, resp, sizeof(resp));
-
-       genmpi = gvnc_bytes_to_mpi(gen);
-       modmpi = gvnc_bytes_to_mpi(mod);
-       respmpi = gvnc_bytes_to_mpi(resp);
-
-       dh = gvnc_dh_new(genmpi, modmpi);
-
-       pubmpi = gvnc_dh_gen_secret(dh);
-       gvnc_mpi_to_bytes(pubmpi, pub);
-
-       gvnc_write(gvnc, pub, sizeof(pub));
-
-       keympi = gvnc_dh_gen_key(dh, respmpi);
-       gvnc_mpi_to_bytes(keympi, key);
-
-       passwordLen = strlen(gvnc->cred_password);
-       usernameLen = strlen(gvnc->cred_username);
-       if (passwordLen > sizeof(password))
-               passwordLen = sizeof(password);
-       if (usernameLen > sizeof(username))
-               usernameLen = sizeof(username);
-
-       memset(password, 0, sizeof password);
-       memset(username, 0, sizeof username);
-       memcpy(password, gvnc->cred_password, passwordLen);
-       memcpy(username, gvnc->cred_username, usernameLen);
-
-       vncEncryptBytes2(username, sizeof(username), key);
-       vncEncryptBytes2(password, sizeof(password), key);
-
-       gvnc_write(gvnc, username, sizeof(username));
-       gvnc_write(gvnc, password, sizeof(password));
-       gvnc_flush(gvnc);
-
-       gcry_mpi_release(genmpi);
-       gcry_mpi_release(modmpi);
-       gcry_mpi_release(respmpi);
-       gvnc_dh_free (dh);
-
-       return gvnc_check_auth_result(gvnc);
-}
-
-#if HAVE_SASL
-/*
- * NB, keep in sync with similar method in qemud/remote.c
- */
-static char *gvnc_addr_to_string(struct sockaddr_storage *sa, socklen_t salen)
-{
-    char host[NI_MAXHOST], port[NI_MAXSERV];
-    char *addr;
-    int err;
-
-    if ((err = getnameinfo((struct sockaddr *)sa, salen,
-                           host, sizeof(host),
-                           port, sizeof(port),
-                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
-	    GVNC_DEBUG("Cannot resolve address %d: %s",
-		       err, gai_strerror(err));
-        return NULL;
-    }
-
-    addr = g_malloc0(strlen(host) + 1 + strlen(port) + 1);
-    strcpy(addr, host);
-    strcat(addr, ";");
-    strcat(addr, port);
-    return addr;
-}
-
-
-
-static gboolean
-gvnc_gather_sasl_credentials(struct gvnc *gvnc,
-			     sasl_interact_t *interact)
-{
-	int ninteract;
-
-	gvnc->want_cred_password = FALSE;
-	gvnc->want_cred_username = FALSE;
-	gvnc->want_cred_x509 = FALSE;
-
-	for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
-		switch (interact[ninteract].id) {
-		case SASL_CB_AUTHNAME:
-		case SASL_CB_USER:
-			gvnc->want_cred_username = TRUE;
-			break;
-
-		case SASL_CB_PASS:
-			gvnc->want_cred_password = TRUE;
-			break;
-
-		default:
-			GVNC_DEBUG("Unsupported credential %lu",
-				   interact[ninteract].id);
-			/* Unsupported */
-			return FALSE;
-		}
-	}
-
-	if ((gvnc->want_cred_password ||
-	     gvnc->want_cred_username) &&
-	    !gvnc_gather_credentials(gvnc)) {
-		GVNC_DEBUG("%s", "cannot gather sasl credentials");
-		return FALSE;
-	}
-
-	for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
-		switch (interact[ninteract].id) {
-		case SASL_CB_AUTHNAME:
-		case SASL_CB_USER:
-			interact[ninteract].result = gvnc->cred_username;
-			interact[ninteract].len = strlen(gvnc->cred_username);
-			GVNC_DEBUG("Gather Username %s", gvnc->cred_username);
-			break;
-
-		case SASL_CB_PASS:
-			interact[ninteract].result =  gvnc->cred_password;
-			interact[ninteract].len = strlen(gvnc->cred_password);
-			//GVNC_DEBUG("Gather Password %s", gvnc->cred_password);
-			break;
-		}
-	}
-
-	GVNC_DEBUG("%s", "Filled SASL interact");
-
-	return TRUE;
-}
-
-
-
-/*
- *
- * Init msg from server
- *
- *  u32 mechlist-length
- *  u8-array mechlist-string
- *
- * Start msg to server
- *
- *  u32 mechname-length
- *  u8-array mechname-string
- *  u32 clientout-length
- *  u8-array clientout-string
- *
- * Start msg from server
- *
- *  u32 serverin-length
- *  u8-array serverin-string
- *  u8 continue
- *
- * Step msg to server
- *
- *  u32 clientout-length
- *  u8-array clientout-string
- *
- * Step msg from server
- *
- *  u32 serverin-length
- *  u8-array serverin-string
- *  u8 continue
- */
-
-#define SASL_MAX_MECHLIST_LEN 300
-#define SASL_MAX_MECHNAME_LEN 100
-#define SASL_MAX_DATA_LEN (1024 * 1024)
-
-/* Perform the SASL authentication process
- */
-static gboolean gvnc_perform_auth_sasl(struct gvnc *gvnc)
-{
-	sasl_conn_t *saslconn = NULL;
-	sasl_security_properties_t secprops;
-	const char *clientout;
-	char *serverin = NULL;
-	unsigned int clientoutlen, serverinlen;
-	int err, complete;
-	struct sockaddr_storage sa;
-	socklen_t salen;
-	char *localAddr = NULL, *remoteAddr = NULL;
-	const void *val;
-	sasl_ssf_t ssf;
-	sasl_callback_t saslcb[] = {
-		{ .id = SASL_CB_AUTHNAME },
-		//		{ .id = SASL_CB_USER },
-		{ .id = SASL_CB_PASS },
-		{ .id = 0 },
-	};
-	sasl_interact_t *interact = NULL;
-	guint32 mechlistlen;
-        char *mechlist;
-	const char *mechname;
-	gboolean ret;
-
-	/* Sets up the SASL library as a whole */
-	err = sasl_client_init(NULL);
-	GVNC_DEBUG("Client initialize SASL authentication %d", err);
-	if (err != SASL_OK) {
-		GVNC_DEBUG("failed to initialize SASL library: %d (%s)",
-			   err, sasl_errstring(err, NULL, NULL));
-		goto error;
-	}
-
-	/* Get local address in form  IPADDR:PORT */
-	salen = sizeof(sa);
-	if (getsockname(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) {
-		GVNC_DEBUG("failed to get sock address %d (%s)",
-			   errno, strerror(errno));
-		goto error;
-	}
-	if ((sa.ss_family == AF_INET ||
-	     sa.ss_family == AF_INET6) &&
-	    (localAddr = gvnc_addr_to_string(&sa, salen)) == NULL)
-		goto error;
-
-	/* Get remote address in form  IPADDR:PORT */
-	salen = sizeof(sa);
-	if (getpeername(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) {
-		GVNC_DEBUG("failed to get peer address %d (%s)",
-			   errno, strerror(errno));
-		g_free(localAddr);
-		goto error;
-	}
-	if ((sa.ss_family == AF_INET ||
-	     sa.ss_family == AF_INET6) &&
-	    (remoteAddr = gvnc_addr_to_string(&sa, salen)) == NULL) {
-		g_free(localAddr);
-		goto error;
-	}
-
-	GVNC_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'", gvnc->host, localAddr, remoteAddr);
-
-	/* Setup a handle for being a client */
-	err = sasl_client_new("vnc",
-			      gvnc->host,
-			      localAddr,
-			      remoteAddr,
-			      saslcb,
-			      SASL_SUCCESS_DATA,
-			      &saslconn);
-	g_free(localAddr);
-	g_free(remoteAddr);
-
-	if (err != SASL_OK) {
-		GVNC_DEBUG("Failed to create SASL client context: %d (%s)",
-			   err, sasl_errstring(err, NULL, NULL));
-		goto error;
-	}
-
-	/* Initialize some connection props we care about */
-	if (gvnc->tls_session) {
-		gnutls_cipher_algorithm_t cipher;
-
-		cipher = gnutls_cipher_get(gvnc->tls_session);
-		if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
-			GVNC_DEBUG("%s", "invalid cipher size for TLS session");
-			goto error;
-		}
-		ssf *= 8; /* key size is bytes, sasl wants bits */
-
-		GVNC_DEBUG("Setting external SSF %d", ssf);
-		err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
-		if (err != SASL_OK) {
-			GVNC_DEBUG("cannot set external SSF %d (%s)",
-				   err, sasl_errstring(err, NULL, NULL));
-			goto error;
-		}
-	}
-
-	memset (&secprops, 0, sizeof secprops);
-	/* If we've got TLS, we don't care about SSF */
-	secprops.min_ssf = gvnc->tls_session ? 0 : 56; /* Equiv to DES supported by all Kerberos */
-	secprops.max_ssf = gvnc->tls_session ? 0 : 100000; /* Very strong ! AES == 256 */
-	secprops.maxbufsize = 100000;
-	/* If we're not TLS, then forbid any anonymous or trivially crackable auth */
-	secprops.security_flags = gvnc->tls_session ? 0 :
-		SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
-
-	err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
-	if (err != SASL_OK) {
-		GVNC_DEBUG("cannot set security props %d (%s)",
-			   err, sasl_errstring(err, NULL, NULL));
-		goto error;
-	}
-
-	/* Get the supported mechanisms from the server */
-	mechlistlen = gvnc_read_u32(gvnc);
-	if (gvnc->has_error)
-		goto error;
-	if (mechlistlen > SASL_MAX_MECHLIST_LEN) {
-		GVNC_DEBUG("mechlistlen %d too long", mechlistlen);
-		goto error;
-	}
-
-	mechlist = g_malloc(mechlistlen+1);
-        gvnc_read(gvnc, mechlist, mechlistlen);
-	mechlist[mechlistlen] = '\0';
-	if (gvnc->has_error) {
-		g_free(mechlist);
-		mechlist = NULL;
-		goto error;
-	}
-
-#if 0
-	if (wantmech) {
-		if (strstr(mechlist, wantmech) == NULL) {
-			GVNC_DEBUG("SASL mechanism %s not supported by server",
-				   wantmech);
-			VIR_FREE(iret.mechlist);
-			goto error;
-		}
-		mechlist = wantmech;
-	}
-#endif
-
- restart:
-	/* Start the auth negotiation on the client end first */
-	GVNC_DEBUG("Client start negotiation mechlist '%s'", mechlist);
-	err = sasl_client_start(saslconn,
-				mechlist,
-				&interact,
-				&clientout,
-				&clientoutlen,
-				&mechname);
-	if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
-		GVNC_DEBUG("Failed to start SASL negotiation: %d (%s)",
-			   err, sasl_errdetail(saslconn));
-		g_free(mechlist);
-		mechlist = NULL;
-		goto error;
-	}
-
-	/* Need to gather some credentials from the client */
-	if (err == SASL_INTERACT) {
-		if (!gvnc_gather_sasl_credentials(gvnc,
-						  interact)) {
-			GVNC_DEBUG("%s", "Failed to collect auth credentials");
-			goto error;
-		}
-		goto restart;
-	}
-
-	GVNC_DEBUG("Server start negotiation with mech %s. Data %d bytes %p '%s'",
-		   mechname, clientoutlen, clientout, clientout);
-
-	if (clientoutlen > SASL_MAX_DATA_LEN) {
-		GVNC_DEBUG("SASL negotiation data too long: %d bytes",
-			   clientoutlen);
-		goto error;
-	}
-
-	/* Send back the chosen mechname */
-	gvnc_write_u32(gvnc, strlen(mechname));
-	gvnc_write(gvnc, mechname, strlen(mechname));
-
-	/* NB, distinction of NULL vs "" is *critical* in SASL */
-	if (clientout) {
-		gvnc_write_u32(gvnc, clientoutlen + 1);
-		gvnc_write(gvnc, clientout, clientoutlen + 1);
-	} else {
-		gvnc_write_u32(gvnc, 0);
-	}
-	gvnc_flush(gvnc);
-	if (gvnc->has_error)
-		goto error;
-
-
-	GVNC_DEBUG("%s", "Getting sever start negotiation reply");
-	/* Read the 'START' message reply from server */
-	serverinlen = gvnc_read_u32(gvnc);
-	if (gvnc->has_error)
-		goto error;
-	if (serverinlen > SASL_MAX_DATA_LEN) {
-		GVNC_DEBUG("SASL negotiation data too long: %d bytes",
-			   clientoutlen);
-		goto error;
-	}
-
-	/* NB, distinction of NULL vs "" is *critical* in SASL */
-	if (serverinlen) {
-		serverin = g_malloc(serverinlen);
-		gvnc_read(gvnc, serverin, serverinlen);
-		serverin[serverinlen-1] = '\0';
-		serverinlen--;
-	} else {
-		serverin = NULL;
-	}
-	complete = gvnc_read_u8(gvnc);
-	if (gvnc->has_error)
-		goto error;
-
-	GVNC_DEBUG("Client start result complete: %d. Data %d bytes %p '%s'",
-		   complete, serverinlen, serverin, serverin);
-
-	/* Loop-the-loop...
-	 * Even if the server has completed, the client must *always* do at least one step
-	 * in this loop to verify the server isn't lying about something. Mutual auth */
-	for (;;) {
-	restep:
-		err = sasl_client_step(saslconn,
-				       serverin,
-				       serverinlen,
-				       &interact,
-				       &clientout,
-				       &clientoutlen);
-		if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
-			GVNC_DEBUG("Failed SASL step: %d (%s)",
-				   err, sasl_errdetail(saslconn));
-			goto error;
-		}
-
-		/* Need to gather some credentials from the client */
-		if (err == SASL_INTERACT) {
-			if (!gvnc_gather_sasl_credentials(gvnc,
-							  interact)) {
-				GVNC_DEBUG("%s", "Failed to collect auth credentials");
-				goto error;
-			}
-			goto restep;
-		}
-
-		if (serverin) {
-			g_free(serverin);
-			serverin = NULL;
-		}
-
-		GVNC_DEBUG("Client step result %d. Data %d bytes %p '%s'", err, clientoutlen, clientout, clientout);
-
-		/* Previous server call showed completion & we're now locally complete too */
-		if (complete && err == SASL_OK)
-			break;
-
-		/* Not done, prepare to talk with the server for another iteration */
-
-		/* NB, distinction of NULL vs "" is *critical* in SASL */
-		if (clientout) {
-			gvnc_write_u32(gvnc, clientoutlen + 1);
-			gvnc_write(gvnc, clientout, clientoutlen + 1);
-		} else {
-			gvnc_write_u32(gvnc, 0);
-		}
-		gvnc_flush(gvnc);
-		if (gvnc->has_error)
-			goto error;
-
-		GVNC_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
-
-		serverinlen = gvnc_read_u32(gvnc);
-		if (gvnc->has_error)
-			goto error;
-		if (serverinlen > SASL_MAX_DATA_LEN) {
-			GVNC_DEBUG("SASL negotiation data too long: %d bytes",
-				   clientoutlen);
-			goto error;
-		}
-
-		/* NB, distinction of NULL vs "" is *critical* in SASL */
-		if (serverinlen) {
-			serverin = g_malloc(serverinlen);
-			gvnc_read(gvnc, serverin, serverinlen);
-			serverin[serverinlen-1] = '\0';
-			serverinlen--;
-		} else {
-			serverin = NULL;
-		}
-		complete = gvnc_read_u8(gvnc);
-		if (gvnc->has_error)
-			goto error;
-
-		GVNC_DEBUG("Client step result complete: %d. Data %d bytes %p '%s'",
-			   complete, serverinlen, serverin, serverin);
-
-		/* This server call shows complete, and earlier client step was OK */
-		if (complete && err == SASL_OK) {
-			g_free(serverin);
-			serverin = NULL;
-			break;
-		}
-	}
-
-	/* Check for suitable SSF if non-TLS */
-	if (!gvnc->tls_session) {
-		err = sasl_getprop(saslconn, SASL_SSF, &val);
-		if (err != SASL_OK) {
-			GVNC_DEBUG("cannot query SASL ssf on connection %d (%s)",
-				   err, sasl_errstring(err, NULL, NULL));
-			goto error;
-		}
-		ssf = *(const int *)val;
-		GVNC_DEBUG("SASL SSF value %d", ssf);
-		if (ssf < 56) { /* 56 == DES level, good for Kerberos */
-			GVNC_DEBUG("negotiation SSF %d was not strong enough", ssf);
-			goto error;
-		}
-	}
-
-	GVNC_DEBUG("%s", "SASL authentication complete");
-	ret = gvnc_check_auth_result(gvnc);
-	/* This must come *after* check-auth-result, because the former
-	 * is defined to be sent unencrypted, and setting saslconn turns
-	 * on the SSF layer encryption processing */
-	gvnc->saslconn = saslconn;
-	return ret;
-
- error:
-	gvnc->has_error = TRUE;
-	if (saslconn)
-		sasl_dispose(&saslconn);
-	return FALSE;
-}
-#endif /* HAVE_SASL */
-
-
-static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS)
-{
-	static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-	static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-	static const int kx_priority[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
-	static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-	int ret;
-
-	GVNC_DEBUG("Do TLS handshake");
-	if (gvnc_tls_initialize() < 0) {
-		GVNC_DEBUG("Failed to init TLS");
-		gvnc->has_error = TRUE;
-		return FALSE;
-	}
-	if (gvnc->tls_session == NULL) {
-		if (gnutls_init(&gvnc->tls_session, GNUTLS_CLIENT) < 0) {
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-
-		if (gnutls_set_default_priority(gvnc->tls_session) < 0) {
-			gnutls_deinit(gvnc->tls_session);
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-
-		if (gnutls_kx_set_priority(gvnc->tls_session, anonTLS ? kx_anon : kx_priority) < 0) {
-			gnutls_deinit(gvnc->tls_session);
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-
-		if (gnutls_certificate_type_set_priority(gvnc->tls_session, cert_type_priority) < 0) {
-			gnutls_deinit(gvnc->tls_session);
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-
-		if (gnutls_protocol_set_priority(gvnc->tls_session, protocol_priority) < 0) {
-			gnutls_deinit(gvnc->tls_session);
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-
-		if (anonTLS) {
-			gnutls_anon_client_credentials anon_cred = gvnc_tls_initialize_anon_cred();
-			if (!anon_cred) {
-				gnutls_deinit(gvnc->tls_session);
-				gvnc->has_error = TRUE;
-				return FALSE;
-			}
-			if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
-				gnutls_deinit(gvnc->tls_session);
-				gvnc->has_error = TRUE;
-				return FALSE;
-			}
-		} else {
-			gvnc->want_cred_password = FALSE;
-			gvnc->want_cred_username = FALSE;
-			gvnc->want_cred_x509 = TRUE;
-			if (!gvnc_gather_credentials(gvnc))
-				return FALSE;
-
-			gnutls_certificate_credentials_t x509_cred = gvnc_tls_initialize_cert_cred(gvnc);
-			if (!x509_cred) {
-				gnutls_deinit(gvnc->tls_session);
-				gvnc->has_error = TRUE;
-				return FALSE;
-			}
-			if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
-				gnutls_deinit(gvnc->tls_session);
-				gvnc->has_error = TRUE;
-				return FALSE;
-			}
-		}
-
-		gnutls_transport_set_ptr(gvnc->tls_session, (gnutls_transport_ptr_t)gvnc);
-		gnutls_transport_set_push_function(gvnc->tls_session, gvnc_tls_push);
-		gnutls_transport_set_pull_function(gvnc->tls_session, gvnc_tls_pull);
-	}
-
- retry:
-	if ((ret = gnutls_handshake(gvnc->tls_session)) < 0) {
-		if (!gnutls_error_is_fatal(ret)) {
-			GVNC_DEBUG("Handshake was blocking");
-			if (!gnutls_record_get_direction(gvnc->tls_session))
-				g_io_wait(gvnc->channel, G_IO_IN);
-			else
-				g_io_wait(gvnc->channel, G_IO_OUT);
-			goto retry;
-		}
-		GVNC_DEBUG("Handshake failed %s", gnutls_strerror(ret));
-		gnutls_deinit(gvnc->tls_session);
-		gvnc->tls_session = NULL;
-		gvnc->has_error = TRUE;
-		return FALSE;
-	}
-
-	GVNC_DEBUG("Handshake done");
-
-	if (anonTLS) {
-		return TRUE;
-	} else {
-		if (!gvnc_validate_certificate(gvnc)) {
-			GVNC_DEBUG("Certificate validation failed");
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-		return TRUE;
-	}
-}
-
-static gboolean gvnc_has_auth_subtype(gpointer data)
-{
-	struct gvnc *gvnc = (struct gvnc *)data;
-
-	if (gvnc->has_error)
-		return TRUE;
-	if (gvnc->auth_subtype == GVNC_AUTH_INVALID)
-		return FALSE;
-	return TRUE;
-}
-
-
-static gboolean gvnc_perform_auth_tls(struct gvnc *gvnc)
-{
-	unsigned int nauth, i;
-	unsigned int auth[20];
-
-	if (!gvnc_start_tls(gvnc, 1)) {
-		GVNC_DEBUG("Could not start TLS");
-		return FALSE;
-	}
-	GVNC_DEBUG("Completed TLS setup");
-
-	nauth = gvnc_read_u8(gvnc);
-	GVNC_DEBUG("Got %d subauths", nauth);
-	if (gvnc_has_error(gvnc))
-		return FALSE;
-
-	GVNC_DEBUG("Got %d subauths", nauth);
-	if (nauth == 0) {
-		GVNC_DEBUG("No sub-auth types requested");
-		return gvnc_check_auth_result(gvnc);
-	}
-
-	if (nauth > sizeof(auth)) {
-		GVNC_DEBUG("Too many (%d) auth types", nauth);
-		gvnc->has_error = TRUE;
-		return FALSE;
-	}
-	for (i = 0 ; i < nauth ; i++) {
-		auth[i] = gvnc_read_u8(gvnc);
-	}
-
-	for (i = 0 ; i < nauth ; i++) {
-		GVNC_DEBUG("Possible sub-auth %d", auth[i]);
-	}
-
-	if (gvnc->has_error || !gvnc->ops.auth_subtype)
-		return FALSE;
-
-	if (!gvnc->ops.auth_subtype(gvnc->ops_data, nauth, auth))
-		gvnc->has_error = TRUE;
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Waiting for auth subtype");
-	g_condition_wait(gvnc_has_auth_subtype, gvnc);
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Choose auth %d", gvnc->auth_subtype);
-
-	gvnc_write_u8(gvnc, gvnc->auth_subtype);
-	gvnc_flush(gvnc);
-
-	switch (gvnc->auth_subtype) {
-	case GVNC_AUTH_NONE:
-		if (gvnc->minor == 8)
-			return gvnc_check_auth_result(gvnc);
-		return TRUE;
-	case GVNC_AUTH_VNC:
-		return gvnc_perform_auth_vnc(gvnc);
-#if HAVE_SASL
-	case GVNC_AUTH_SASL:
-		return gvnc_perform_auth_sasl(gvnc);
-#endif
-	default:
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc)
-{
-	int major, minor, status, anonTLS;
-	unsigned int nauth, i;
-	unsigned int auth[20];
-
-	major = gvnc_read_u8(gvnc);
-	minor = gvnc_read_u8(gvnc);
-
-	if (major != 0 &&
-	    minor != 2) {
-		GVNC_DEBUG("Unsupported VeNCrypt version %d %d", major, minor);
-		return FALSE;
-	}
-
-	gvnc_write_u8(gvnc, major);
-	gvnc_write_u8(gvnc, minor);
-	gvnc_flush(gvnc);
-	status = gvnc_read_u8(gvnc);
-	if (status != 0) {
-		GVNC_DEBUG("Server refused VeNCrypt version %d %d", major, minor);
-		return FALSE;
-	}
-
-	nauth = gvnc_read_u8(gvnc);
-	if (nauth > (sizeof(auth)/sizeof(auth[0]))) {
-		GVNC_DEBUG("Too many (%d) auth types", nauth);
-		return FALSE;
-	}
-
-	for (i = 0 ; i < nauth ; i++) {
-		auth[i] = gvnc_read_u32(gvnc);
-	}
-
-	for (i = 0 ; i < nauth ; i++) {
-		GVNC_DEBUG("Possible auth %d", auth[i]);
-	}
-
-	if (gvnc->has_error || !gvnc->ops.auth_subtype)
-		return FALSE;
-
-	if (!gvnc->ops.auth_subtype(gvnc->ops_data, nauth, auth))
-		gvnc->has_error = TRUE;
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Waiting for auth subtype");
-	g_condition_wait(gvnc_has_auth_subtype, gvnc);
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Choose auth %d", gvnc->auth_subtype);
-
-	if (!gvnc_gather_credentials(gvnc))
-		return FALSE;
-
-#if !DEBUG
-	if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN) {
-		GVNC_DEBUG("Cowardly refusing to transmit plain text password");
-		return FALSE;
-	}
-#endif
-
-	gvnc_write_u32(gvnc, gvnc->auth_subtype);
-	gvnc_flush(gvnc);
-	status = gvnc_read_u8(gvnc);
-	if (status != 1) {
-		GVNC_DEBUG("Server refused VeNCrypt auth %d %d", gvnc->auth_subtype, status);
-		return FALSE;
-	}
-
-	switch (gvnc->auth_subtype) {
-	case GVNC_AUTH_VENCRYPT_TLSNONE:
-	case GVNC_AUTH_VENCRYPT_TLSPLAIN:
-	case GVNC_AUTH_VENCRYPT_TLSVNC:
-	case GVNC_AUTH_VENCRYPT_TLSSASL:
-		anonTLS = 1;
-		break;
-	default:
-		anonTLS = 0;
-	}
-
-	if (!gvnc_start_tls(gvnc, anonTLS)) {
-		GVNC_DEBUG("Could not start TLS");
-		return FALSE;
-	}
-	GVNC_DEBUG("Completed TLS setup, do subauth %d", gvnc->auth_subtype);
-
-	switch (gvnc->auth_subtype) {
-		/* Plain certificate based auth */
-	case GVNC_AUTH_VENCRYPT_TLSNONE:
-	case GVNC_AUTH_VENCRYPT_X509NONE:
-		GVNC_DEBUG("Completing auth");
-		return gvnc_check_auth_result(gvnc);
-
-		/* Regular VNC layered over TLS */
-	case GVNC_AUTH_VENCRYPT_TLSVNC:
-	case GVNC_AUTH_VENCRYPT_X509VNC:
-		GVNC_DEBUG("Handing off to VNC auth");
-		return gvnc_perform_auth_vnc(gvnc);
-
-#if HAVE_SASL
-		/* SASL layered over TLS */
-	case GVNC_AUTH_VENCRYPT_TLSSASL:
-	case GVNC_AUTH_VENCRYPT_X509SASL:
-		GVNC_DEBUG("Handing off to SASL auth");
-		return gvnc_perform_auth_sasl(gvnc);
-#endif
-
-	default:
-		GVNC_DEBUG("Unknown auth subtype %d", gvnc->auth_subtype);
-		return FALSE;
-	}
-}
-
-static gboolean gvnc_has_auth_type(gpointer data)
-{
-	struct gvnc *gvnc = (struct gvnc *)data;
-
-	if (gvnc->has_error)
-		return TRUE;
-	if (gvnc->auth_type == GVNC_AUTH_INVALID)
-		return FALSE;
-	return TRUE;
-}
-
-static gboolean gvnc_perform_auth(struct gvnc *gvnc)
-{
-	unsigned int nauth, i;
-	unsigned int auth[10];
-
-	if (gvnc->minor <= 6) {
-		nauth = 1;
-		auth[0] = gvnc_read_u32(gvnc);
-	} else {
-		nauth = gvnc_read_u8(gvnc);
-		if (gvnc_has_error(gvnc))
-			return FALSE;
-
-		if (nauth == 0)
-			return gvnc_check_auth_result(gvnc);
-
-		if (nauth > sizeof(auth)) {
-			gvnc->has_error = TRUE;
-			return FALSE;
-		}
-		for (i = 0 ; i < nauth ; i++)
-			auth[i] = gvnc_read_u8(gvnc);
-	}
-
-	for (i = 0 ; i < nauth ; i++) {
-		GVNC_DEBUG("Possible auth %u", auth[i]);
-	}
-
-	if (gvnc->has_error || !gvnc->ops.auth_type)
-		return FALSE;
-
-	if (!gvnc->ops.auth_type(gvnc->ops_data, nauth, auth))
-		gvnc->has_error = TRUE;
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Waiting for auth type");
-	g_condition_wait(gvnc_has_auth_type, gvnc);
-	if (gvnc->has_error)
-		return FALSE;
-
-	GVNC_DEBUG("Choose auth %u", gvnc->auth_type);
-	if (!gvnc_gather_credentials(gvnc))
-		return FALSE;
-
-	if (gvnc->minor > 6) {
-		gvnc_write_u8(gvnc, gvnc->auth_type);
-		gvnc_flush(gvnc);
-	}
-
-	switch (gvnc->auth_type) {
-	case GVNC_AUTH_NONE:
-		if (gvnc->minor == 8)
-			return gvnc_check_auth_result(gvnc);
-		return TRUE;
-	case GVNC_AUTH_VNC:
-		return gvnc_perform_auth_vnc(gvnc);
-
-	case GVNC_AUTH_TLS:
-		if (gvnc->minor < 7)
-			return FALSE;
-		return gvnc_perform_auth_tls(gvnc);
-
-	case GVNC_AUTH_VENCRYPT:
-		return gvnc_perform_auth_vencrypt(gvnc);
-
-#if HAVE_SASL
-	case GVNC_AUTH_SASL:
- 		return gvnc_perform_auth_sasl(gvnc);
-#endif
-
-	case GVNC_AUTH_MSLOGON:
-		return gvnc_perform_auth_mslogon(gvnc);
-
-	default:
-		if (gvnc->ops.auth_unsupported)
-			gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type);
-		gvnc->has_error = TRUE;
-
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data)
-{
-	struct gvnc *gvnc = g_malloc0(sizeof(*gvnc));
-
-	gvnc->fd = -1;
-
-	memcpy(&gvnc->ops, ops, sizeof(*ops));
-	gvnc->ops_data = ops_data;
-	gvnc->auth_type = GVNC_AUTH_INVALID;
-	gvnc->auth_subtype = GVNC_AUTH_INVALID;
-
-	return gvnc;
-}
-
-void gvnc_free(struct gvnc *gvnc)
-{
-	if (!gvnc)
-		return;
-
-	if (gvnc_is_open(gvnc))
-		gvnc_close(gvnc);
-
-	g_free(gvnc);
-	gvnc = NULL;
-}
-
-void gvnc_close(struct gvnc *gvnc)
-{
-	int i;
-
-	if (gvnc->tls_session) {
-		gnutls_bye(gvnc->tls_session, GNUTLS_SHUT_RDWR);
-		gvnc->tls_session = NULL;
-	}
-#if HAVE_SASL
-	if (gvnc->saslconn)
-		sasl_dispose (&gvnc->saslconn);
-#endif
-
-	if (gvnc->channel) {
-		g_io_channel_unref(gvnc->channel);
-		gvnc->channel = NULL;
-	}
-	if (gvnc->fd != -1) {
-		close(gvnc->fd);
-		gvnc->fd = -1;
-	}
-
-	if (gvnc->host) {
-		g_free(gvnc->host);
-		gvnc->host = NULL;
-	}
-
-	if (gvnc->port) {
-		g_free(gvnc->port);
-		gvnc->port = NULL;
-	}
-
-	if (gvnc->name) {
-		g_free(gvnc->name);
-		gvnc->name = NULL;
-	}
-
-	g_free (gvnc->xmit_buffer);
-
-	if (gvnc->cred_username) {
-		g_free(gvnc->cred_username);
-		gvnc->cred_username = NULL;
-	}
-	if (gvnc->cred_password) {
-		g_free(gvnc->cred_password);
-		gvnc->cred_password = NULL;
-	}
-
-	if (gvnc->cred_x509_cacert) {
-		g_free(gvnc->cred_x509_cacert);
-		gvnc->cred_x509_cacert = NULL;
-	}
-	if (gvnc->cred_x509_cacrl) {
-		g_free(gvnc->cred_x509_cacrl);
-		gvnc->cred_x509_cacrl = NULL;
-	}
-	if (gvnc->cred_x509_cert) {
-		g_free(gvnc->cred_x509_cert);
-		gvnc->cred_x509_cert = NULL;
-	}
-	if (gvnc->cred_x509_key) {
-		g_free(gvnc->cred_x509_key);
-		gvnc->cred_x509_key = NULL;
-	}
-
-	for (i = 0; i < 5; i++)
-		inflateEnd(&gvnc->streams[i]);
-
-	gvnc->auth_type = GVNC_AUTH_INVALID;
-	gvnc->auth_subtype = GVNC_AUTH_INVALID;
-
-	gvnc->has_error = 0;
-}
-
-void gvnc_shutdown(struct gvnc *gvnc)
-{
-	close(gvnc->fd);
-	gvnc->fd = -1;
-	gvnc->has_error = 1;
-	GVNC_DEBUG("Waking up couroutine to shutdown gracefully");
-	g_io_wakeup(&gvnc->wait);
-}
-
-gboolean gvnc_is_open(struct gvnc *gvnc)
-{
-	if (!gvnc)
-		return FALSE;
-
-	if (gvnc->fd != -1)
-		return TRUE;
-	if (gvnc->host)
-		return TRUE;
-	return FALSE;
-}
-
-
-gboolean gvnc_is_initialized(struct gvnc *gvnc)
-{
-	if (!gvnc_is_open(gvnc))
-		return FALSE;
-	if (gvnc->name)
-		return TRUE;
-	return FALSE;
-}
-
-static gboolean gvnc_before_version (struct gvnc *gvnc, int major, int minor) {
-	return (gvnc->major < major) || (gvnc->major == major && gvnc->minor < minor);
-}
-static gboolean gvnc_after_version (struct gvnc *gvnc, int major, int minor) {
-	return !gvnc_before_version (gvnc, major, minor+1);
-}
-
-gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag)
-{
-	int ret, i;
-	char version[13];
-	guint32 n_name;
-
-	gvnc->absolute = 1;
-
-	gvnc_read(gvnc, version, 12);
-	version[12] = 0;
-
- 	ret = sscanf(version, "RFB %03d.%03d\n", &gvnc->major, &gvnc->minor);
-	if (ret != 2) {
-		GVNC_DEBUG("Error while getting server version");
-		goto fail;
-	}
-
-	GVNC_DEBUG("Server version: %d.%d", gvnc->major, gvnc->minor);
-
-	if (gvnc_before_version(gvnc, 3, 3)) {
-		GVNC_DEBUG("Server version is not supported (%d.%d)", gvnc->major, gvnc->minor);
-		goto fail;
-	} else if (gvnc_before_version(gvnc, 3, 7)) {
-		gvnc->minor = 3;
-	} else if (gvnc_after_version(gvnc, 3, 8)) {
-		gvnc->major = 3;
-		gvnc->minor = 8;
-	}
-
-	snprintf(version, 12, "RFB %03d.%03d\n", gvnc->major, gvnc->minor);
-	gvnc_write(gvnc, version, 12);
-	gvnc_flush(gvnc);
-	GVNC_DEBUG("Using version: %d.%d", gvnc->major, gvnc->minor);
-
-	if (!gvnc_perform_auth(gvnc)) {
-		GVNC_DEBUG("Auth failed");
-		goto fail;
-	}
-
-	gvnc_write_u8(gvnc, shared_flag); /* shared flag */
-	gvnc_flush(gvnc);
-	gvnc->width = gvnc_read_u16(gvnc);
-	gvnc->height = gvnc_read_u16(gvnc);
-
-	if (gvnc_has_error(gvnc))
-		return FALSE;
-
-	gvnc_read_pixel_format(gvnc, &gvnc->fmt);
-
-	n_name = gvnc_read_u32(gvnc);
-	if (n_name > 4096)
-		goto fail;
-
-	gvnc->name = g_new(char, n_name + 1);
-
-	gvnc_read(gvnc, gvnc->name, n_name);
-	gvnc->name[n_name] = 0;
-	GVNC_DEBUG("Display name '%s'", gvnc->name);
-
-	if (gvnc_has_error(gvnc))
-		return FALSE;
-
-	if (!gvnc->ops.get_preferred_pixel_format)
-		goto fail;
-	if (gvnc->ops.get_preferred_pixel_format(gvnc->ops_data, &gvnc->fmt))
-		gvnc_set_pixel_format(gvnc, &gvnc->fmt);
-	else
-		goto fail;
-	memset(&gvnc->strm, 0, sizeof(gvnc->strm));
-	/* FIXME what level? */
-	for (i = 0; i < 5; i++)
-		inflateInit(&gvnc->streams[i]);
-	gvnc->strm = NULL;
-
-	gvnc_resize(gvnc, gvnc->width, gvnc->height);
-	return !gvnc_has_error(gvnc);
-
- fail:
-	gvnc->has_error = 1;
-	return !gvnc_has_error(gvnc);
-}
-
-static gboolean gvnc_set_nonblock(int fd)
-{
-#ifndef WIN32
-	int flags;
-	if ((flags = fcntl(fd, F_GETFL)) < 0) {
-		GVNC_DEBUG ("Failed to fcntl()");
-		return FALSE;
-	}
-	flags |= O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, flags) < 0) {
-		GVNC_DEBUG ("Failed to fcntl()");
-		return FALSE;
-	}
-
-#else /* WIN32 */
-	unsigned long flag = 1;
-
-	/* This is actually Gnulib's replacement rpl_ioctl function.
-	 * We can't call ioctlsocket directly in any case.
-	 */
-	if (ioctl (fd, FIONBIO, (void *) &flag) == -1) {
-		GVNC_DEBUG ("Failed to set nonblocking flag, winsock error = %d",
-			    WSAGetLastError ());
-		return FALSE;
-	}
-#endif /* WIN32 */
-
-	return TRUE;
-}
-
-gboolean gvnc_open_fd(struct gvnc *gvnc, int fd)
-{
-	if (gvnc_is_open(gvnc)) {
-		GVNC_DEBUG ("Error: already connected?");
-		return FALSE;
-	}
-
-	GVNC_DEBUG("Connecting to FD %d", fd);
-
-	if (!gvnc_set_nonblock(fd))
-		return FALSE;
-
-	if (!(gvnc->channel =
-#ifdef WIN32
-	      g_io_channel_win32_new_socket(_get_osfhandle(fd))
-#else
-	      g_io_channel_unix_new(fd)
-#endif
-	      )) {
-		GVNC_DEBUG ("Failed to g_io_channel_unix_new()");
-		return FALSE;
-	}
-	gvnc->fd = fd;
-
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_open_host(struct gvnc *gvnc, const char *host, const char *port)
-{
-        struct addrinfo *ai, *runp, hints;
-        int ret;
-	if (gvnc_is_open(gvnc))
-		return FALSE;
-
-	gvnc->host = g_strdup(host);
-	gvnc->port = g_strdup(port);
-
-        GVNC_DEBUG("Resolving host %s %s", host, port);
-        memset (&hints, '\0', sizeof (hints));
-        hints.ai_flags = AI_ADDRCONFIG;
-        hints.ai_socktype = SOCK_STREAM;
-        hints.ai_protocol = IPPROTO_TCP;
-
-        if ((ret = getaddrinfo(host, port, &hints, &ai)) != 0) {
-		GVNC_DEBUG ("Failed to resolve hostname");
-		return FALSE;
-	}
-
-        runp = ai;
-        while (runp != NULL) {
-                int fd;
-                GIOChannel *chan;
-
-		if ((fd = socket(runp->ai_family, runp->ai_socktype,
-			runp->ai_protocol)) < 0) {
-			GVNC_DEBUG ("Failed to socket()");
-			break;
-		}
-
-                GVNC_DEBUG("Trying socket %d", fd);
-		if (!gvnc_set_nonblock(fd))
-			break;
-
-                if (!(chan =
-#ifdef WIN32
-		      g_io_channel_win32_new_socket(_get_osfhandle(fd))
-#else
-		      g_io_channel_unix_new(fd)
-#endif
-		      )) {
-                        close(fd);
-                        GVNC_DEBUG ("Failed to g_io_channel_unix_new()");
-                        break;
-                }
-
-        reconnect:
-                /* FIXME: Better handle EINPROGRESS/EISCONN return values,
-                   as explained in connect(2) man page */
-                if ((connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) ||
-		    errno == EISCONN) {
-                        gvnc->channel = chan;
-                        gvnc->fd = fd;
-                        freeaddrinfo(ai);
-                        return !gvnc_has_error(gvnc);
-                }
-                if (errno == EINPROGRESS ||
-                    errno == EWOULDBLOCK) {
-                        g_io_wait(chan, G_IO_OUT|G_IO_ERR|G_IO_HUP);
-                        goto reconnect;
-                } else if (errno != ECONNREFUSED &&
-                           errno != EHOSTUNREACH) {
-                        g_io_channel_unref(chan);
-                        close(fd);
-                        GVNC_DEBUG ("Failed with errno = %d", errno);
-                        break;
-                }
-                close(fd);
-                g_io_channel_unref(chan);
-                runp = runp->ai_next;
-        }
-        freeaddrinfo (ai);
-	return FALSE;
-}
-
-
-gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type)
-{
-        GVNC_DEBUG("Thinking about auth type %u", type);
-        if (gvnc->auth_type != GVNC_AUTH_INVALID) {
-                gvnc->has_error = TRUE;
-                return !gvnc_has_error(gvnc);
-        }
-        if (type != GVNC_AUTH_NONE &&
-            type != GVNC_AUTH_VNC &&
-            type != GVNC_AUTH_MSLOGON &&
-            type != GVNC_AUTH_TLS &&
-            type != GVNC_AUTH_VENCRYPT &&
-            type != GVNC_AUTH_SASL) {
-		GVNC_DEBUG("Unsupported auth type %u", type);
-            	if (gvnc->ops.auth_unsupported)
-			gvnc->ops.auth_unsupported (gvnc->ops_data, type);
-
-                gvnc->has_error = TRUE;
-                return !gvnc_has_error(gvnc);
-        }
-        GVNC_DEBUG("Decided on auth type %u", type);
-        gvnc->auth_type = type;
-        gvnc->auth_subtype = GVNC_AUTH_INVALID;
-
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type)
-{
-        GVNC_DEBUG("Requested auth subtype %d", type);
-        if (gvnc->auth_type != GVNC_AUTH_VENCRYPT &&
-	    gvnc->auth_type != GVNC_AUTH_TLS) {
-                gvnc->has_error = TRUE;
-		return !gvnc_has_error(gvnc);
-        }
-        if (gvnc->auth_subtype != GVNC_AUTH_INVALID) {
-                gvnc->has_error = TRUE;
-		return !gvnc_has_error(gvnc);
-        }
-        gvnc->auth_subtype = type;
-
-	return !gvnc_has_error(gvnc);
-}
-
-gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password)
-{
-        GVNC_DEBUG("Set password credential %s", password);
-        if (gvnc->cred_password)
-                g_free(gvnc->cred_password);
-        if (!(gvnc->cred_password = g_strdup(password))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username)
-{
-        GVNC_DEBUG("Set username credential %s", username);
-        if (gvnc->cred_username)
-                g_free(gvnc->cred_username);
-        if (!(gvnc->cred_username = g_strdup(username))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file)
-{
-        GVNC_DEBUG("Set x509 cacert %s", file);
-        if (gvnc->cred_x509_cacert)
-                g_free(gvnc->cred_x509_cacert);
-        if (!(gvnc->cred_x509_cacert = g_strdup(file))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file)
-{
-        GVNC_DEBUG("Set x509 cacrl %s", file);
-        if (gvnc->cred_x509_cacrl)
-                g_free(gvnc->cred_x509_cacrl);
-        if (!(gvnc->cred_x509_cacrl = g_strdup(file))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file)
-{
-        GVNC_DEBUG("Set x509 key %s", file);
-        if (gvnc->cred_x509_key)
-                g_free(gvnc->cred_x509_key);
-        if (!(gvnc->cred_x509_key = g_strdup(file))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file)
-{
-        GVNC_DEBUG("Set x509 cert %s", file);
-        if (gvnc->cred_x509_cert)
-                g_free(gvnc->cred_x509_cert);
-        if (!(gvnc->cred_x509_cert = g_strdup(file))) {
-                gvnc->has_error = TRUE;
-                return FALSE;
-        }
-        return TRUE;
-}
-
-
-gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb)
-{
-	int i, j, n;
-	int depth;
-
-	memcpy(&gvnc->local, fb, sizeof(*fb));
-
-	if (fb->bpp == (gvnc->fmt.bits_per_pixel / 8) &&
-	    fb->red_mask == gvnc->fmt.red_max &&
-	    fb->green_mask == gvnc->fmt.green_max &&
-	    fb->blue_mask == gvnc->fmt.blue_max &&
-	    fb->red_shift == gvnc->fmt.red_shift &&
-	    fb->green_shift == gvnc->fmt.green_shift &&
-	    fb->blue_shift == gvnc->fmt.blue_shift &&
-	    fb->byte_order == G_BYTE_ORDER &&
-	    gvnc->fmt.byte_order == G_BYTE_ORDER)
-		gvnc->perfect_match = TRUE;
-	else
-		gvnc->perfect_match = FALSE;
-
-	depth = gvnc->fmt.depth;
-	if (depth == 32)
-		depth = 24;
-
-	gvnc->rm = gvnc->local.red_mask & gvnc->fmt.red_max;
-	gvnc->gm = gvnc->local.green_mask & gvnc->fmt.green_max;
-	gvnc->bm = gvnc->local.blue_mask & gvnc->fmt.blue_max;
-	GVNC_DEBUG("Mask local: %3d %3d %3d\n"
-		   "    remote: %3d %3d %3d\n"
-		   "    merged: %3d %3d %3d",
-		   gvnc->local.red_mask, gvnc->local.green_mask, gvnc->local.blue_mask,
-		   gvnc->fmt.red_max, gvnc->fmt.green_max, gvnc->fmt.blue_max,
-		   gvnc->rm, gvnc->gm, gvnc->bm);
-
-	/* Setup shifts assuming matched bpp (but not necessarily match rgb order)*/
-	gvnc->rrs = gvnc->fmt.red_shift;
-	gvnc->grs = gvnc->fmt.green_shift;
-	gvnc->brs = gvnc->fmt.blue_shift;
-
-	gvnc->rls = gvnc->local.red_shift;
-	gvnc->gls = gvnc->local.green_shift;
-	gvnc->bls = gvnc->local.blue_shift;
-
-	/* This adjusts for remote having more bpp than local */
-	for (n = gvnc->fmt.red_max; n > gvnc->local.red_mask ; n>>= 1)
-		gvnc->rrs++;
-	for (n = gvnc->fmt.green_max; n > gvnc->local.green_mask ; n>>= 1)
-		gvnc->grs++;
-	for (n = gvnc->fmt.blue_max; n > gvnc->local.blue_mask ; n>>= 1)
-		gvnc->brs++;
-
-	/* This adjusts for remote having less bpp than remote */
-	for (n = gvnc->local.red_mask ; n > gvnc->fmt.red_max ; n>>= 1)
-		gvnc->rls++;
-	for (n = gvnc->local.green_mask ; n > gvnc->fmt.green_max ; n>>= 1)
-		gvnc->gls++;
-	for (n = gvnc->local.blue_mask ; n > gvnc->fmt.blue_max ; n>>= 1)
-		gvnc->bls++;
-	GVNC_DEBUG("Pixel shifts\n   right: %3d %3d %3d\n    left: %3d %3d %3d",
-		   gvnc->rrs, gvnc->grs, gvnc->brs,
-		   gvnc->rls, gvnc->gls, gvnc->bls);
-
-	i = gvnc->fmt.bits_per_pixel / 8;
-	j = gvnc->local.bpp;
-
-	if (i == 4) i = 3;
-	if (j == 4) j = 3;
-
-	gvnc->blt = gvnc_blt_table[i - 1][j - 1];
-	gvnc->fill = gvnc_fill_table[i - 1][j - 1];
-	gvnc->set_pixel_at = gvnc_set_pixel_at_table[i - 1][j - 1];
-	gvnc->hextile = gvnc_hextile_table[i - 1][j - 1];
-	gvnc->rich_cursor_blt = gvnc_rich_cursor_blt_table[i - 1];
-	gvnc->rgb24_blt = gvnc_rgb24_blt_table[i - 1];
-	gvnc->tight_compute_predicted = gvnc_tight_compute_predicted_table[i - 1];
-	gvnc->tight_sum_pixel = gvnc_tight_sum_pixel_table[i - 1];
-
-	if (gvnc->perfect_match)
-		gvnc->blt = gvnc_blt_fast;
-
-	return !gvnc_has_error(gvnc);
-}
-
-const char *gvnc_get_name(struct gvnc *gvnc)
-{
-	return gvnc->name;
-}
-
-int gvnc_get_width(struct gvnc *gvnc)
-{
-	return gvnc->width;
-}
-
-int gvnc_get_height(struct gvnc *gvnc)
-{
-	return gvnc->height;
-}
-
-gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc)
-{
-	return gvnc->has_ext_key_event;
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/src/gvnc.h b/src/gvnc.h
deleted file mode 100644
index 86e69e6..0000000
--- a/src/gvnc.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * GTK VNC Widget
- *
- * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.0 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
- */
-
-#ifndef _GVNC_H_
-#define _GVNC_H_
-
-#include <glib.h>
-#include <stdint.h>
-
-struct gvnc;
-
-struct gvnc_pixel_format;
-
-typedef void (rgb24_render_func)(void *, int, int, int, int, guint8 *, int);
-
-struct gvnc_ops
-{
-	gboolean (*auth_cred)(void *);
-	gboolean (*auth_type)(void *, unsigned int, unsigned int *);
-	gboolean (*auth_subtype)(void *, unsigned int, unsigned int *);
-	gboolean (*auth_failure)(void *, const char *);
-	gboolean (*update)(void *, int, int, int, int);
-	gboolean (*set_color_map_entry)(void *, int, int, int, int);
-	gboolean (*bell)(void *);
-	gboolean (*server_cut_text)(void *, const void *, size_t);
-	gboolean (*resize)(void *, int, int);
-        gboolean (*pixel_format)(void *, struct gvnc_pixel_format *);
-	gboolean (*pointer_type_change)(void *, int);
-	gboolean (*local_cursor)(void *, int, int, int, int, guint8 *);
-	gboolean (*auth_unsupported)(void *, unsigned int);
-	gboolean (*render_jpeg)(void *, rgb24_render_func *render, void *,
-				int, int, int, int, guint8 *, int);
-	gboolean (*get_preferred_pixel_format)(void *, struct gvnc_pixel_format *);
-};
-
-struct gvnc_pixel_format
-{
-	guint8 bits_per_pixel;
-	guint8 depth;
-	guint16 byte_order;
-	guint8 true_color_flag;
-	guint16 red_max;
-	guint16 green_max;
-	guint16 blue_max;
-	guint8 red_shift;
-	guint8 green_shift;
-	guint8 blue_shift;
-};
-
-struct gvnc_framebuffer
-{
-	guint8 *data;
-
-	int width;
-	int height;
-
-	int linesize;
-
-	guint16 byte_order;
-	int depth;
-	int bpp;
-
-	int red_mask;
-	int green_mask;
-	int blue_mask;
-
-	int red_shift;
-	int blue_shift;
-	int green_shift;
-};
-
-typedef enum {
-	GVNC_ENCODING_RAW = 0,
-	GVNC_ENCODING_COPY_RECT = 1,
-	GVNC_ENCODING_RRE = 2,
-	GVNC_ENCODING_CORRE = 4,
-	GVNC_ENCODING_HEXTILE = 5,
-	GVNC_ENCODING_TIGHT = 7,
-	GVNC_ENCODING_ZRLE = 16,
-
-	/* Tight JPEG quality levels */
-	GVNC_ENCODING_TIGHT_JPEG0 = -32,
-	GVNC_ENCODING_TIGHT_JPEG1 = -31,
-	GVNC_ENCODING_TIGHT_JPEG2 = -30,
-	GVNC_ENCODING_TIGHT_JPEG3 = -29,
-	GVNC_ENCODING_TIGHT_JPEG4 = -28,
-	GVNC_ENCODING_TIGHT_JPEG5 = -27,
-	GVNC_ENCODING_TIGHT_JPEG6 = -26,
-	GVNC_ENCODING_TIGHT_JPEG7 = -25,
-	GVNC_ENCODING_TIGHT_JPEG8 = -24,
-	GVNC_ENCODING_TIGHT_JPEG9 = -23,
-
-	/* Pseudo encodings */
-	GVNC_ENCODING_DESKTOP_RESIZE = -223,
-        GVNC_ENCODING_WMVi = 0x574D5669,
-
-	GVNC_ENCODING_CURSOR_POS = -232,
-	GVNC_ENCODING_RICH_CURSOR = -239,
-	GVNC_ENCODING_XCURSOR = -240,
-
-	GVNC_ENCODING_POINTER_CHANGE = -257,
-	GVNC_ENCODING_EXT_KEY_EVENT = -258,
-} gvnc_encoding;
-
-typedef enum {
-	GVNC_AUTH_INVALID = 0,
-	GVNC_AUTH_NONE = 1,
-	GVNC_AUTH_VNC = 2,
-	GVNC_AUTH_RA2 = 5,
-	GVNC_AUTH_RA2NE = 6,
-	GVNC_AUTH_TIGHT = 16,
-	GVNC_AUTH_ULTRA = 17,
-	GVNC_AUTH_TLS = 18,  /* Used by VINO */
-	GVNC_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */
- 	GVNC_AUTH_SASL = 20, /* SASL type used by VINO and QEMU */
-	GVNC_AUTH_MSLOGON = 0xfffffffa, /* Used by UltraVNC */
-} gvnc_auth;
-
-typedef enum {
-	GVNC_AUTH_VENCRYPT_PLAIN = 256,
-	GVNC_AUTH_VENCRYPT_TLSNONE = 257,
-	GVNC_AUTH_VENCRYPT_TLSVNC = 258,
-	GVNC_AUTH_VENCRYPT_TLSPLAIN = 259,
-	GVNC_AUTH_VENCRYPT_X509NONE = 260,
-	GVNC_AUTH_VENCRYPT_X509VNC = 261,
-	GVNC_AUTH_VENCRYPT_X509PLAIN = 262,
-	GVNC_AUTH_VENCRYPT_X509SASL = 263,
-	GVNC_AUTH_VENCRYPT_TLSSASL = 264,
-} gvnc_auth_vencrypt;
-
-
-struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data);
-void gvnc_free(struct gvnc *gvnc);
-
-void gvnc_close(struct gvnc *gvnc);
-void gvnc_shutdown(struct gvnc *gvnc);
-
-gboolean gvnc_open_fd(struct gvnc *gvnc, int fd);
-gboolean gvnc_open_host(struct gvnc *gvnc, const char *host, const char *port);
-gboolean gvnc_is_open(struct gvnc *gvnc);
-
-gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type);
-gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type);
-
-gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password);
-gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username);
-gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file);
-gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file);
-gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file);
-gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file);
-
-gboolean gvnc_wants_credential_password(struct gvnc *gvnc);
-gboolean gvnc_wants_credential_username(struct gvnc *gvnc);
-gboolean gvnc_wants_credential_x509(struct gvnc *gvnc);
-
-gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag);
-gboolean gvnc_is_initialized(struct gvnc *gvnc);
-
-gboolean gvnc_server_message(struct gvnc *gvnc);
-
-gboolean gvnc_client_cut_text(struct gvnc *gvnc,
-			      const void *data, size_t length);
-
-gboolean gvnc_pointer_event(struct gvnc *gvnc, guint8 button_mask,
-			    guint16 x, guint16 y);
-
-gboolean gvnc_key_event(struct gvnc *gvnc, guint8 down_flag,
-			guint32 key, guint16 scancode);
-
-gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
-					 guint8 incremental,
-					 guint16 x, guint16 y,
-					 guint16 width, guint16 height);
-
-gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, gint32 *encoding);
-
-gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
-			       const struct gvnc_pixel_format *fmt);
-
-gboolean gvnc_has_error(struct gvnc *gvnc);
-
-gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb);
-
-gboolean gvnc_shared_memory_enabled(struct gvnc *gvnc);
-
-const char *gvnc_get_name(struct gvnc *gvnc);
-int gvnc_get_width(struct gvnc *gvnc);
-int gvnc_get_height(struct gvnc *gvnc);
-
-/* HACK this is temporary */
-gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc);
-
-#endif
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/src/vncconnection.c b/src/vncconnection.c
new file mode 100644
index 0000000..cdd135d
--- /dev/null
+++ b/src/vncconnection.c
@@ -0,0 +1,3964 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "vncconnection.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "coroutine.h"
+#include "d3des.h"
+
+#include "x_keymap.h"
+
+#include "utils.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
+#include <zlib.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include "getaddrinfo.h"
+#include "dh.h"
+
+/* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
+   even if its emulated getaddrinfo() for us . */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+
+struct wait_queue
+{
+	gboolean waiting;
+	struct coroutine *context;
+};
+
+
+typedef void gvnc_blt_func(struct gvnc *, guint8 *, int, int, int, int, int);
+
+typedef void gvnc_fill_func(struct gvnc *, guint8 *, int, int, int, int);
+
+typedef void gvnc_set_pixel_at_func(struct gvnc *, int, int, guint8 *);
+
+typedef void gvnc_hextile_func(struct gvnc *gvnc, guint8 flags,
+			       guint16 x, guint16 y,
+			       guint16 width, guint16 height,
+			       guint8 *fg, guint8 *bg);
+
+typedef void gvnc_rich_cursor_blt_func(struct gvnc *, guint8 *, guint8 *,
+				       guint8 *, int, guint16, guint16);
+
+typedef void gvnc_rgb24_blt_func(struct gvnc *, int, int, int, int,
+				 guint8 *, int);
+
+typedef void gvnc_tight_compute_predicted_func(struct gvnc *, guint8 *,
+					       guint8 *, guint8 *,
+					       guint8 *);
+
+typedef void gvnc_tight_sum_pixel_func(struct gvnc *, guint8 *, guint8 *);
+
+/*
+ * A special GSource impl which allows us to wait on a certain
+ * condition to be satisfied. This is effectively a boolean test
+ * run on each iteration of the main loop. So whenever a file has
+ * new I/O, or a timer occurs, etc we'll do the check. This is
+ * pretty efficient compared to a normal GLib Idle func which has
+ * to busy wait on a timeout, since our condition is only checked
+ * when some other source's state changes
+ */
+typedef gboolean (*g_condition_wait_func)(gpointer);
+
+struct g_condition_wait_source
+{
+        GSource src;
+        struct coroutine *co;
+	g_condition_wait_func func;
+	gpointer data;
+};
+
+struct gvnc
+{
+	GIOChannel *channel;
+	int fd;
+	char *host;
+	char *port;
+	struct gvnc_pixel_format fmt;
+	gboolean has_error;
+	int width;
+	int height;
+	char *name;
+
+	int major;
+	int minor;
+	gnutls_session_t tls_session;
+
+	/* Auth related params */
+	unsigned int auth_type;
+	unsigned int auth_subtype;
+	char *cred_username;
+	char *cred_password;
+	char *cred_x509_cacert;
+	char *cred_x509_cacrl;
+	char *cred_x509_cert;
+	char *cred_x509_key;
+	gboolean want_cred_username;
+	gboolean want_cred_password;
+	gboolean want_cred_x509;
+
+#if HAVE_SASL
+	sasl_conn_t *saslconn;      /* SASL context */
+	const char *saslDecoded;
+	unsigned int saslDecodedLength;
+	unsigned int saslDecodedOffset;
+#endif
+
+	char read_buffer[4096];
+	size_t read_offset;
+	size_t read_size;
+
+	char write_buffer[4096];
+	size_t write_offset;
+
+	gboolean perfect_match;
+	struct gvnc_framebuffer local;
+
+	int rm, gm, bm;
+	int rrs, grs, brs;
+	int rls, gls, bls;
+
+	gvnc_blt_func *blt;
+	gvnc_fill_func *fill;
+	gvnc_set_pixel_at_func *set_pixel_at;
+	gvnc_hextile_func *hextile;
+	gvnc_rich_cursor_blt_func *rich_cursor_blt;
+	gvnc_rgb24_blt_func *rgb24_blt;
+	gvnc_tight_compute_predicted_func *tight_compute_predicted;
+	gvnc_tight_sum_pixel_func *tight_sum_pixel;
+
+	struct gvnc_ops ops;
+	gpointer ops_data;
+
+	int absolute;
+
+	int wait_interruptable;
+	struct wait_queue wait;
+
+	char *xmit_buffer;
+	int xmit_buffer_capacity;
+	int xmit_buffer_size;
+
+	z_stream *strm;
+	z_stream streams[5];
+
+	size_t uncompressed_length;
+	guint8 uncompressed_buffer[4096];
+
+	size_t compressed_length;
+	guint8 *compressed_buffer;
+
+	guint8 zrle_pi;
+	int zrle_pi_bits;
+
+	gboolean has_ext_key_event;
+	const guint8 const *keycode_map;
+};
+
+#define nibhi(a) (((a) >> 4) & 0x0F)
+#define niblo(a) ((a) & 0x0F)
+
+/* Main loop helper functions */
+static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
+				 GIOCondition cond,
+				 gpointer data)
+{
+	struct coroutine *to = data;
+	coroutine_yieldto(to, &cond);
+	return FALSE;
+}
+
+static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
+{
+	GIOCondition *ret;
+
+	g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, coroutine_self());
+	ret = coroutine_yield(NULL);
+	return *ret;
+}
+
+
+static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
+					    GIOChannel *channel,
+					    GIOCondition cond)
+{
+	GIOCondition *ret;
+	gint id;
+
+	wait->context = coroutine_self();
+	id = g_io_add_watch(channel, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, g_io_wait_helper, wait->context);
+
+	wait->waiting = TRUE;
+	ret = coroutine_yield(NULL);
+	wait->waiting = FALSE;
+
+	if (ret == NULL) {
+		g_source_remove(id);
+		return 0;
+	} else
+		return *ret;
+}
+
+static void g_io_wakeup(struct wait_queue *wait)
+{
+	if (wait->waiting)
+		coroutine_yieldto(wait->context, NULL);
+}
+
+
+/*
+ * Call immediately before the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_prepare(GSource *src,
+					 int *timeout) {
+        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+        *timeout = -1;
+        return vsrc->func(vsrc->data);
+}
+
+/*
+ * Call immediately after the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_check(GSource *src)
+{
+        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+        return vsrc->func(vsrc->data);
+}
+
+static gboolean g_condition_wait_dispatch(GSource *src G_GNUC_UNUSED,
+					  GSourceFunc cb,
+					  gpointer data) {
+        return cb(data);
+}
+
+GSourceFuncs waitFuncs = {
+        .prepare = g_condition_wait_prepare,
+        .check = g_condition_wait_check,
+        .dispatch = g_condition_wait_dispatch,
+  };
+
+static gboolean g_condition_wait_helper(gpointer data)
+{
+        struct coroutine *co = (struct coroutine *)data;
+        coroutine_yieldto(co, NULL);
+        return FALSE;
+}
+
+static gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
+{
+	GSource *src;
+	struct g_condition_wait_source *vsrc;
+
+	/* Short-circuit check in case we've got it ahead of time */
+	if (func(data)) {
+		return TRUE;
+	}
+
+	/*
+	 * Don't have it, so yield to the main loop, checking the condition
+	 * on each iteration of the main loop
+	 */
+	src = g_source_new(&waitFuncs, sizeof(struct g_condition_wait_source));
+	vsrc = (struct g_condition_wait_source *)src;
+
+	vsrc->func = func;
+	vsrc->data = data;
+	vsrc->co = coroutine_self();
+
+	g_source_attach(src, NULL);
+	g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
+	coroutine_yield(NULL);
+	return TRUE;
+}
+
+static gboolean gvnc_use_compression(struct gvnc *gvnc)
+{
+	return gvnc->compressed_buffer != NULL;
+}
+
+static int gvnc_zread(struct gvnc *gvnc, void *buffer, size_t size)
+{
+	char *ptr = buffer;
+	size_t offset = 0;
+
+	while (offset < size) {
+		/* if data is available in the uncompressed buffer, then
+		 * copy */
+		if (gvnc->uncompressed_length) {
+			size_t len = MIN(gvnc->uncompressed_length,
+					 size - offset);
+
+			memcpy(ptr + offset,
+			       gvnc->uncompressed_buffer,
+			       len);
+
+			gvnc->uncompressed_length -= len;
+			if (gvnc->uncompressed_length)
+				memmove(gvnc->uncompressed_buffer,
+					gvnc->uncompressed_buffer + len,
+					gvnc->uncompressed_length);
+			offset += len;
+		} else {
+			int err;
+
+			gvnc->strm->next_in = gvnc->compressed_buffer;
+			gvnc->strm->avail_in = gvnc->compressed_length;
+			gvnc->strm->next_out = gvnc->uncompressed_buffer;
+			gvnc->strm->avail_out = sizeof(gvnc->uncompressed_buffer);
+
+			/* inflate as much as possible */
+			err = inflate(gvnc->strm, Z_SYNC_FLUSH);
+			if (err != Z_OK) {
+				errno = EIO;
+				return -1;
+			}
+
+			gvnc->uncompressed_length = (guint8 *)gvnc->strm->next_out - gvnc->uncompressed_buffer;
+			gvnc->compressed_length -= (guint8 *)gvnc->strm->next_in - gvnc->compressed_buffer;
+			gvnc->compressed_buffer = gvnc->strm->next_in;
+		}
+	}
+
+	return offset;
+}
+
+/* IO functions */
+
+
+/*
+ * Read at least 1 more byte of data straight off the wire
+ * into the requested buffer.
+ */
+static int gvnc_read_wire(struct gvnc *gvnc, void *data, size_t len)
+{
+	int ret;
+
+ reread:
+	if (gvnc->tls_session) {
+		ret = gnutls_read(gvnc->tls_session, data, len);
+		if (ret < 0) {
+			if (ret == GNUTLS_E_AGAIN)
+				errno = EAGAIN;
+			else
+				errno = EIO;
+			ret = -1;
+		}
+	} else
+		ret = recv (gvnc->fd, data, len, 0);
+
+	if (ret == -1) {
+		switch (errno) {
+		case EWOULDBLOCK:
+			if (gvnc->wait_interruptable) {
+				if (!g_io_wait_interruptable(&gvnc->wait,
+							     gvnc->channel, G_IO_IN)) {
+					GVNC_DEBUG("Read blocking interrupted %d", gvnc->has_error);
+					return -EAGAIN;
+				}
+			} else
+				g_io_wait(gvnc->channel, G_IO_IN);
+		case EINTR:
+			goto reread;
+
+		default:
+			GVNC_DEBUG("Closing the connection: gvnc_read() - errno=%d", errno);
+			gvnc->has_error = TRUE;
+			return -errno;
+		}
+	}
+	if (ret == 0) {
+		GVNC_DEBUG("Closing the connection: gvnc_read() - ret=0");
+		gvnc->has_error = TRUE;
+		return -EPIPE;
+	}
+	//GVNC_DEBUG("Read wire %p %d -> %d", data, len, ret);
+
+	return ret;
+}
+
+
+#if HAVE_SASL
+/*
+ * Read at least 1 more byte of data out of the SASL decrypted
+ * data buffer, into the internal read buffer
+ */
+static int gvnc_read_sasl(struct gvnc *gvnc)
+{
+	size_t want;
+	//GVNC_DEBUG("Read SASL %p size %d offset %d", gvnc->saslDecoded,
+	//	   gvnc->saslDecodedLength, gvnc->saslDecodedOffset);
+	if (gvnc->saslDecoded == NULL) {
+		char encoded[8192];
+		int encodedLen = sizeof(encoded);
+		int err, ret;
+
+		ret = gvnc_read_wire(gvnc, encoded, encodedLen);
+		if (ret < 0) {
+			return ret;
+		}
+
+		err = sasl_decode(gvnc->saslconn, encoded, ret,
+				  &gvnc->saslDecoded, &gvnc->saslDecodedLength);
+		if (err != SASL_OK) {
+			GVNC_DEBUG("Failed to decode SASL data %s",
+				   sasl_errstring(err, NULL, NULL));
+			gvnc->has_error = TRUE;
+			return -EINVAL;
+		}
+		gvnc->saslDecodedOffset = 0;
+	}
+
+	want = gvnc->saslDecodedLength - gvnc->saslDecodedOffset;
+	if (want > sizeof(gvnc->read_buffer))
+		want = sizeof(gvnc->read_buffer);
+
+	memcpy(gvnc->read_buffer,
+	       gvnc->saslDecoded + gvnc->saslDecodedOffset,
+	       want);
+	gvnc->saslDecodedOffset += want;
+	if (gvnc->saslDecodedOffset == gvnc->saslDecodedLength) {
+		gvnc->saslDecodedLength = gvnc->saslDecodedOffset = 0;
+		gvnc->saslDecoded = NULL;
+	}
+	//GVNC_DEBUG("Done read write %d - %d", want, gvnc->has_error);
+	return want;
+}
+#endif
+
+
+/*
+ * Read at least 1 more byte of data straight off the wire
+ * into the internal read buffer
+ */
+static int gvnc_read_plain(struct gvnc *gvnc)
+{
+	//GVNC_DEBUG("Read plain %d", sizeof(gvnc->read_buffer));
+	return gvnc_read_wire(gvnc, gvnc->read_buffer, sizeof(gvnc->read_buffer));
+}
+
+/*
+ * Read at least 1 more byte of data into the internal read_buffer
+ */
+static int gvnc_read_buf(struct gvnc *gvnc)
+{
+	//GVNC_DEBUG("Start read %d", gvnc->has_error);
+#if HAVE_SASL
+	if (gvnc->saslconn)
+		return gvnc_read_sasl(gvnc);
+	else
+#endif
+		return gvnc_read_plain(gvnc);
+}
+
+/*
+ * Fill the 'data' buffer up with exactly 'len' bytes worth of data
+ */
+static int gvnc_read(struct gvnc *gvnc, void *data, size_t len)
+{
+	char *ptr = data;
+	size_t offset = 0;
+
+	if (gvnc->has_error) return -EINVAL;
+
+	while (offset < len) {
+		size_t tmp;
+
+		/* compressed data is buffered independently of the read buffer
+		 * so we must by-pass it */
+		if (gvnc_use_compression(gvnc)) {
+			int ret = gvnc_zread(gvnc, ptr + offset, len);
+			if (ret == -1) {
+				GVNC_DEBUG("Closing the connection: gvnc_read() - gvnc_zread() failed");
+				gvnc->has_error = TRUE;
+				return -errno;
+			}
+			offset += ret;
+			continue;
+		} else if (gvnc->read_offset == gvnc->read_size) {
+			int ret = gvnc_read_buf(gvnc);
+
+			if (ret < 0)
+				return ret;
+			gvnc->read_offset = 0;
+			gvnc->read_size = ret;
+		}
+
+		tmp = MIN(gvnc->read_size - gvnc->read_offset, len - offset);
+
+		memcpy(ptr + offset, gvnc->read_buffer + gvnc->read_offset, tmp);
+
+		gvnc->read_offset += tmp;
+		offset += tmp;
+	}
+
+	return 0;
+}
+
+/*
+ * Write all 'data' of length 'datalen' bytes out to
+ * the wire
+ */
+static void gvnc_flush_wire(struct gvnc *gvnc,
+			    const void *data,
+			    size_t datalen)
+{
+	const char *ptr = data;
+	size_t offset = 0;
+	//GVNC_DEBUG("Flush write %p %d", data, datalen);
+	while (offset < datalen) {
+		int ret;
+
+		if (gvnc->tls_session) {
+			ret = gnutls_write(gvnc->tls_session,
+					   ptr+offset,
+					   datalen-offset);
+			if (ret < 0) {
+				if (ret == GNUTLS_E_AGAIN)
+					errno = EAGAIN;
+				else
+					errno = EIO;
+				ret = -1;
+			}
+		} else
+			ret = send (gvnc->fd,
+				    ptr+offset,
+				    datalen-offset, 0);
+		if (ret == -1) {
+			switch (errno) {
+			case EWOULDBLOCK:
+				g_io_wait(gvnc->channel, G_IO_OUT);
+			case EINTR:
+				continue;
+			default:
+				GVNC_DEBUG("Closing the connection: gvnc_flush %d", errno);
+				gvnc->has_error = TRUE;
+				return;
+			}
+		}
+		if (ret == 0) {
+			GVNC_DEBUG("Closing the connection: gvnc_flush");
+			gvnc->has_error = TRUE;
+			return;
+		}
+		offset += ret;
+	}
+}
+
+
+#if HAVE_SASL
+/*
+ * Encode all buffered data, write all encrypted data out
+ * to the wire
+ */
+static void gvnc_flush_sasl(struct gvnc *gvnc)
+{
+	const char *output;
+	unsigned int outputlen;
+	int err;
+
+	err = sasl_encode(gvnc->saslconn,
+			  gvnc->write_buffer,
+			  gvnc->write_offset,
+			  &output, &outputlen);
+	if (err != SASL_OK) {
+		GVNC_DEBUG("Failed to encode SASL data %s",
+			   sasl_errstring(err, NULL, NULL));
+		gvnc->has_error = TRUE;
+		return;
+	}
+	//GVNC_DEBUG("Flush SASL %d: %p %d", gvnc->write_offset, output, outputlen);
+	gvnc_flush_wire(gvnc, output, outputlen);
+}
+#endif
+
+/*
+ * Write all buffered data straight out to the wire
+ */
+static void gvnc_flush_plain(struct gvnc *gvnc)
+{
+	//GVNC_DEBUG("Flush plain %d", gvnc->write_offset);
+	gvnc_flush_wire(gvnc,
+			gvnc->write_buffer,
+			gvnc->write_offset);
+}
+
+
+/*
+ * Write all buffered data out to the wire
+ */
+static void gvnc_flush(struct gvnc *gvnc)
+{
+	//GVNC_DEBUG("STart write %d", gvnc->has_error);
+#if HAVE_SASL
+	if (gvnc->saslconn)
+		gvnc_flush_sasl(gvnc);
+	else
+#endif
+		gvnc_flush_plain(gvnc);
+	gvnc->write_offset = 0;
+}
+
+static void gvnc_write(struct gvnc *gvnc, const void *data, size_t len)
+{
+	const char *ptr = data;
+	size_t offset = 0;
+
+	while (offset < len) {
+		ssize_t tmp;
+
+		if (gvnc->write_offset == sizeof(gvnc->write_buffer)) {
+			gvnc_flush(gvnc);
+		}
+
+		tmp = MIN(sizeof(gvnc->write_buffer), len - offset);
+
+		memcpy(gvnc->write_buffer+gvnc->write_offset, ptr + offset, tmp);
+
+		gvnc->write_offset += tmp;
+		offset += tmp;
+	}
+}
+
+
+static ssize_t gvnc_tls_push(gnutls_transport_ptr_t transport,
+			      const void *data,
+			      size_t len) {
+	struct gvnc *gvnc = (struct gvnc *)transport;
+	int ret;
+
+ retry:
+	ret = write(gvnc->fd, data, len);
+	if (ret < 0) {
+		if (errno == EINTR)
+			goto retry;
+		return -1;
+	}
+	return ret;
+}
+
+
+static ssize_t gvnc_tls_pull(gnutls_transport_ptr_t transport,
+			     void *data,
+			     size_t len) {
+	struct gvnc *gvnc = (struct gvnc *)transport;
+	int ret;
+
+ retry:
+	ret = read(gvnc->fd, data, len);
+	if (ret < 0) {
+		if (errno == EINTR)
+			goto retry;
+		return -1;
+	}
+	return ret;
+}
+
+static size_t gvnc_pixel_size(struct gvnc *gvnc)
+{
+	return gvnc->fmt.bits_per_pixel / 8;
+}
+
+static void gvnc_read_pixel(struct gvnc *gvnc, guint8 *pixel)
+{
+	gvnc_read(gvnc, pixel, gvnc_pixel_size(gvnc));
+}
+
+static guint8 gvnc_read_u8(struct gvnc *gvnc)
+{
+	guint8 value = 0;
+	gvnc_read(gvnc, &value, sizeof(value));
+	return value;
+}
+
+static int gvnc_read_u8_interruptable(struct gvnc *gvnc, guint8 *value)
+{
+	int ret;
+
+	gvnc->wait_interruptable = 1;
+	ret = gvnc_read(gvnc, value, sizeof(*value));
+	gvnc->wait_interruptable = 0;
+
+	return ret;
+}
+
+static guint16 gvnc_read_u16(struct gvnc *gvnc)
+{
+	guint16 value = 0;
+	gvnc_read(gvnc, &value, sizeof(value));
+	return ntohs(value);
+}
+
+static guint32 gvnc_read_u32(struct gvnc *gvnc)
+{
+	guint32 value = 0;
+	gvnc_read(gvnc, &value, sizeof(value));
+	return ntohl(value);
+}
+
+static gint32 gvnc_read_s32(struct gvnc *gvnc)
+{
+	gint32 value = 0;
+	gvnc_read(gvnc, &value, sizeof(value));
+	return ntohl(value);
+}
+
+static void gvnc_write_u8(struct gvnc *gvnc, guint8 value)
+{
+	gvnc_write(gvnc, &value, sizeof(value));
+}
+
+static void gvnc_write_u16(struct gvnc *gvnc, guint16 value)
+{
+	value = htons(value);
+	gvnc_write(gvnc, &value, sizeof(value));
+}
+
+static void gvnc_write_u32(struct gvnc *gvnc, guint32 value)
+{
+	value = htonl(value);
+	gvnc_write(gvnc, &value, sizeof(value));
+}
+
+static void gvnc_write_s32(struct gvnc *gvnc, gint32 value)
+{
+	value = htonl(value);
+	gvnc_write(gvnc, &value, sizeof(value));
+}
+
+#define DH_BITS 1024
+static gnutls_dh_params_t dh_params;
+
+#if 0
+static void gvnc_debug_gnutls_log(int level, const char* str) {
+	GVNC_DEBUG("%d %s", level, str);
+}
+#endif
+
+static gboolean gvnc_tls_initialize(void)
+{
+	static int tlsinitialized = 0;
+
+	if (tlsinitialized)
+		return TRUE;
+
+	if (gnutls_global_init () < 0)
+		return FALSE;
+
+	if (gnutls_dh_params_init (&dh_params) < 0)
+		return FALSE;
+	if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
+		return FALSE;
+
+#if 0
+	if (debug_enabled) {
+		gnutls_global_set_log_level(10);
+		gnutls_global_set_log_function(gvnc_debug_gnutls_log);
+	}
+#endif
+
+	tlsinitialized = TRUE;
+
+	return TRUE;
+}
+
+static gnutls_anon_client_credentials gvnc_tls_initialize_anon_cred(void)
+{
+	gnutls_anon_client_credentials anon_cred;
+	int ret;
+
+	if ((ret = gnutls_anon_allocate_client_credentials(&anon_cred)) < 0) {
+		GVNC_DEBUG("Cannot allocate credentials %s", gnutls_strerror(ret));
+		return NULL;
+	}
+
+	return anon_cred;
+}
+
+static gnutls_certificate_credentials_t gvnc_tls_initialize_cert_cred(struct gvnc *vnc)
+{
+	gnutls_certificate_credentials_t x509_cred;
+	int ret;
+
+	if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
+		GVNC_DEBUG("Cannot allocate credentials %s", gnutls_strerror(ret));
+		return NULL;
+	}
+	if (vnc->cred_x509_cacert) {
+		if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
+								  vnc->cred_x509_cacert,
+								  GNUTLS_X509_FMT_PEM)) < 0) {
+			GVNC_DEBUG("Cannot load CA certificate %s", gnutls_strerror(ret));
+			return NULL;
+		}
+	} else {
+		GVNC_DEBUG("No CA certificate provided");
+		return NULL;
+	}
+
+	if (vnc->cred_x509_cert && vnc->cred_x509_key) {
+		if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
+								 vnc->cred_x509_cert,
+								 vnc->cred_x509_key,
+								 GNUTLS_X509_FMT_PEM)) < 0) {
+			GVNC_DEBUG("Cannot load certificate & key %s", gnutls_strerror(ret));
+			return NULL;
+		}
+	} else {
+		GVNC_DEBUG("No client cert or key provided");
+	}
+
+	if (vnc->cred_x509_cacrl) {
+		if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
+								vnc->cred_x509_cacrl,
+								GNUTLS_X509_FMT_PEM)) < 0) {
+			GVNC_DEBUG("Cannot load CRL %s", gnutls_strerror(ret));
+			return NULL;
+		}
+	} else {
+		GVNC_DEBUG("No CA revocation list provided");
+	}
+
+	gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+	return x509_cred;
+}
+
+static int gvnc_validate_certificate(struct gvnc *vnc)
+{
+	int ret;
+	unsigned int status;
+	const gnutls_datum_t *certs;
+	unsigned int nCerts, i;
+	time_t now;
+
+	GVNC_DEBUG("Validating");
+	if ((ret = gnutls_certificate_verify_peers2 (vnc->tls_session, &status)) < 0) {
+		GVNC_DEBUG("Verify failed %s", gnutls_strerror(ret));
+		return FALSE;
+	}
+
+	if ((now = time(NULL)) == ((time_t)-1)) {
+		return FALSE;
+	}
+
+	if (status != 0) {
+		if (status & GNUTLS_CERT_INVALID)
+			GVNC_DEBUG ("The certificate is not trusted.");
+
+		if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+			GVNC_DEBUG ("The certificate hasn't got a known issuer.");
+
+		if (status & GNUTLS_CERT_REVOKED)
+			GVNC_DEBUG ("The certificate has been revoked.");
+
+		if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+			GVNC_DEBUG ("The certificate uses an insecure algorithm");
+
+		return FALSE;
+	} else {
+		GVNC_DEBUG("Certificate is valid.");
+	}
+
+	if (gnutls_certificate_type_get(vnc->tls_session) != GNUTLS_CRT_X509)
+		return FALSE;
+
+	if (!(certs = gnutls_certificate_get_peers(vnc->tls_session, &nCerts)))
+		return FALSE;
+
+	for (i = 0 ; i < nCerts ; i++) {
+		gnutls_x509_crt_t cert;
+		GVNC_DEBUG ("Checking chain %d", i);
+		if (gnutls_x509_crt_init (&cert) < 0)
+			return FALSE;
+
+		if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+			gnutls_x509_crt_deinit (cert);
+			return FALSE;
+		}
+
+		if (gnutls_x509_crt_get_expiration_time (cert) < now) {
+			GVNC_DEBUG("The certificate has expired");
+			gnutls_x509_crt_deinit (cert);
+			return FALSE;
+		}
+
+		if (gnutls_x509_crt_get_activation_time (cert) > now) {
+			GVNC_DEBUG("The certificate is not yet activated");
+			gnutls_x509_crt_deinit (cert);
+			return FALSE;
+		}
+
+		if (gnutls_x509_crt_get_activation_time (cert) > now) {
+			GVNC_DEBUG("The certificate is not yet activated");
+			gnutls_x509_crt_deinit (cert);
+			return FALSE;
+		}
+
+		if (i == 0) {
+			if (!vnc->host) {
+				GVNC_DEBUG ("No hostname provided for certificate verification");
+				gnutls_x509_crt_deinit (cert);
+				return FALSE;
+			}
+			if (!gnutls_x509_crt_check_hostname (cert, vnc->host)) {
+				GVNC_DEBUG ("The certificate's owner does not match hostname '%s'",
+					    vnc->host);
+				gnutls_x509_crt_deinit (cert);
+				return FALSE;
+			}
+		}
+	}
+
+	return TRUE;
+}
+
+
+static void gvnc_read_pixel_format(struct gvnc *gvnc, struct gvnc_pixel_format *fmt)
+{
+	guint8 pad[3];
+
+	fmt->bits_per_pixel  = gvnc_read_u8(gvnc);
+	fmt->depth           = gvnc_read_u8(gvnc);
+	fmt->byte_order      = gvnc_read_u8(gvnc) ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
+	fmt->true_color_flag = gvnc_read_u8(gvnc);
+
+	fmt->red_max         = gvnc_read_u16(gvnc);
+	fmt->green_max       = gvnc_read_u16(gvnc);
+	fmt->blue_max        = gvnc_read_u16(gvnc);
+
+	fmt->red_shift       = gvnc_read_u8(gvnc);
+	fmt->green_shift     = gvnc_read_u8(gvnc);
+	fmt->blue_shift      = gvnc_read_u8(gvnc);
+
+	gvnc_read(gvnc, pad, 3);
+
+	GVNC_DEBUG("Pixel format BPP: %d,  Depth: %d, Byte order: %d, True color: %d\n"
+		   "             Mask  red: %3d, green: %3d, blue: %3d\n"
+		   "             Shift red: %3d, green: %3d, blue: %3d",
+		   fmt->bits_per_pixel, fmt->depth, fmt->byte_order, fmt->true_color_flag,
+		   fmt->red_max, fmt->green_max, fmt->blue_max,
+		   fmt->red_shift, fmt->green_shift, fmt->blue_shift);
+}
+
+/* initialize function */
+
+gboolean gvnc_has_error(struct gvnc *gvnc)
+{
+	return gvnc->has_error;
+}
+
+gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
+			       const struct gvnc_pixel_format *fmt)
+{
+	guint8 pad[3] = {0};
+
+	gvnc_write_u8(gvnc, 0);
+	gvnc_write(gvnc, pad, 3);
+
+	gvnc_write_u8(gvnc, fmt->bits_per_pixel);
+	gvnc_write_u8(gvnc, fmt->depth);
+	gvnc_write_u8(gvnc, fmt->byte_order == G_BIG_ENDIAN ? 1 : 0);
+	gvnc_write_u8(gvnc, fmt->true_color_flag);
+
+	gvnc_write_u16(gvnc, fmt->red_max);
+	gvnc_write_u16(gvnc, fmt->green_max);
+	gvnc_write_u16(gvnc, fmt->blue_max);
+
+	gvnc_write_u8(gvnc, fmt->red_shift);
+	gvnc_write_u8(gvnc, fmt->green_shift);
+	gvnc_write_u8(gvnc, fmt->blue_shift);
+
+	gvnc_write(gvnc, pad, 3);
+	gvnc_flush(gvnc);
+
+	if (&gvnc->fmt != fmt)
+		memcpy(&gvnc->fmt, fmt, sizeof(*fmt));
+
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, gint32 *encoding)
+{
+	guint8 pad[1] = {0};
+	int i, skip_zrle=0;
+
+	/*
+	 * RealVNC server is broken for ZRLE in some pixel formats.
+	 * Specifically if you have a format with either R, G or B
+	 * components with a max value > 255, it still uses a CPIXEL
+	 * of 3 bytes, even though the colour requirs 4 bytes. It
+	 * thus messes up the colours of the server in a way we can't
+	 * recover from on the client. Most VNC clients don't see this
+	 * problem since they send a 'set pixel format' message instead
+	 * of running with the server's default format.
+	 *
+	 * So we kill off ZRLE encoding for problematic pixel formats
+	 */
+	for (i = 0; i < n_encoding; i++)
+		if (gvnc->fmt.depth == 32 &&
+		    (gvnc->fmt.red_max > 255 ||
+		     gvnc->fmt.blue_max > 255 ||
+		     gvnc->fmt.green_max > 255) &&
+		    encoding[i] == GVNC_ENCODING_ZRLE) {
+			GVNC_DEBUG("Dropping ZRLE encoding for broken pixel format");
+			skip_zrle++;
+		}
+
+	gvnc->has_ext_key_event = FALSE;
+	gvnc_write_u8(gvnc, 2);
+	gvnc_write(gvnc, pad, 1);
+	gvnc_write_u16(gvnc, n_encoding - skip_zrle);
+	for (i = 0; i < n_encoding; i++) {
+		if (skip_zrle && encoding[i] == GVNC_ENCODING_ZRLE)
+			continue;
+		gvnc_write_s32(gvnc, encoding[i]);
+	}
+	gvnc_flush(gvnc);
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
+					 guint8 incremental,
+					 guint16 x, guint16 y,
+					 guint16 width, guint16 height)
+{
+	gvnc_write_u8(gvnc, 3);
+	gvnc_write_u8(gvnc, incremental);
+	gvnc_write_u16(gvnc, x);
+	gvnc_write_u16(gvnc, y);
+	gvnc_write_u16(gvnc, width);
+	gvnc_write_u16(gvnc, height);
+	gvnc_flush(gvnc);
+	return !gvnc_has_error(gvnc);
+}
+
+static void gvnc_buffered_write(struct gvnc *gvnc, const void *data, size_t size)
+{
+	size_t left;
+
+	left = gvnc->xmit_buffer_capacity - gvnc->xmit_buffer_size;
+	if (left < size) {
+		gvnc->xmit_buffer_capacity += size + 4095;
+		gvnc->xmit_buffer_capacity &= ~4095;
+
+		gvnc->xmit_buffer = g_realloc(gvnc->xmit_buffer, gvnc->xmit_buffer_capacity);
+	}
+
+	memcpy(&gvnc->xmit_buffer[gvnc->xmit_buffer_size],
+	       data, size);
+
+	gvnc->xmit_buffer_size += size;
+}
+
+static void gvnc_buffered_write_u8(struct gvnc *gvnc, guint8 value)
+{
+	gvnc_buffered_write(gvnc, &value, 1);
+}
+
+static void gvnc_buffered_write_u16(struct gvnc *gvnc, guint16 value)
+{
+	value = htons(value);
+	gvnc_buffered_write(gvnc, &value, 2);
+}
+
+static void gvnc_buffered_write_u32(struct gvnc *gvnc, guint32 value)
+{
+	value = htonl(value);
+	gvnc_buffered_write(gvnc, &value, 4);
+}
+
+static void gvnc_buffered_flush(struct gvnc *gvnc)
+{
+	g_io_wakeup(&gvnc->wait);
+}
+
+gboolean gvnc_key_event(struct gvnc *gvnc, guint8 down_flag,
+			guint32 key, guint16 scancode)
+{
+	guint8 pad[2] = {0};
+
+	GVNC_DEBUG("Key event %d %d %d %d", key, scancode, down_flag, gvnc->has_ext_key_event);
+	if (gvnc->has_ext_key_event) {
+		scancode = x_keycode_to_pc_keycode(gvnc->keycode_map, scancode);
+
+		gvnc_buffered_write_u8(gvnc, 255);
+		gvnc_buffered_write_u8(gvnc, 0);
+		gvnc_buffered_write_u16(gvnc, down_flag);
+		gvnc_buffered_write_u32(gvnc, key);
+		gvnc_buffered_write_u32(gvnc, scancode);
+	} else {
+		gvnc_buffered_write_u8(gvnc, 4);
+		gvnc_buffered_write_u8(gvnc, down_flag);
+		gvnc_buffered_write(gvnc, pad, 2);
+		gvnc_buffered_write_u32(gvnc, key);
+	}
+
+	gvnc_buffered_flush(gvnc);
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_pointer_event(struct gvnc *gvnc, guint8 button_mask,
+			    guint16 x, guint16 y)
+{
+	gvnc_buffered_write_u8(gvnc, 5);
+	gvnc_buffered_write_u8(gvnc, button_mask);
+	gvnc_buffered_write_u16(gvnc, x);
+	gvnc_buffered_write_u16(gvnc, y);
+	gvnc_buffered_flush(gvnc);
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_client_cut_text(struct gvnc *gvnc,
+			      const void *data, size_t length)
+{
+	guint8 pad[3] = {0};
+
+	gvnc_buffered_write_u8(gvnc, 6);
+	gvnc_buffered_write(gvnc, pad, 3);
+	gvnc_buffered_write_u32(gvnc, length);
+	gvnc_buffered_write(gvnc, data, length);
+	gvnc_buffered_flush(gvnc);
+	return !gvnc_has_error(gvnc);
+}
+
+static inline guint8 *gvnc_get_local(struct gvnc *gvnc, int x, int y)
+{
+	return gvnc->local.data +
+		(y * gvnc->local.linesize) +
+		(x * gvnc->local.bpp);
+}
+
+static guint8 gvnc_swap_img_8(struct gvnc *gvnc G_GNUC_UNUSED, guint8 pixel)
+{
+	return pixel;
+}
+
+static guint8 gvnc_swap_rfb_8(struct gvnc *gvnc G_GNUC_UNUSED, guint8 pixel)
+{
+	return pixel;
+}
+
+/* local host native format -> X server image format */
+static guint16 gvnc_swap_img_16(struct gvnc *gvnc, guint16 pixel)
+{
+	if (G_BYTE_ORDER != gvnc->local.byte_order)
+		return  (((pixel >> 8) & 0xFF) << 0) |
+			(((pixel >> 0) & 0xFF) << 8);
+	else
+		return pixel;
+}
+
+/* VNC server RFB  format ->  local host native format */
+static guint16 gvnc_swap_rfb_16(struct gvnc *gvnc, guint16 pixel)
+{
+	if (gvnc->fmt.byte_order != G_BYTE_ORDER)
+		return  (((pixel >> 8) & 0xFF) << 0) |
+			(((pixel >> 0) & 0xFF) << 8);
+	else
+		return pixel;
+}
+
+/* local host native format -> X server image format */
+static guint32 gvnc_swap_img_32(struct gvnc *gvnc, guint32 pixel)
+{
+	if (G_BYTE_ORDER != gvnc->local.byte_order)
+		return  (((pixel >> 24) & 0xFF) <<  0) |
+			(((pixel >> 16) & 0xFF) <<  8) |
+			(((pixel >>  8) & 0xFF) << 16) |
+			(((pixel >>  0) & 0xFF) << 24);
+	else
+		return pixel;
+}
+
+/* VNC server RFB  format ->  local host native format */
+static guint32 gvnc_swap_rfb_32(struct gvnc *gvnc, guint32 pixel)
+{
+	if (gvnc->fmt.byte_order != G_BYTE_ORDER)
+		return  (((pixel >> 24) & 0xFF) <<  0) |
+			(((pixel >> 16) & 0xFF) <<  8) |
+			(((pixel >>  8) & 0xFF) << 16) |
+			(((pixel >>  0) & 0xFF) << 24);
+	else
+		return pixel;
+}
+
+#define SPLICE_I(a, b) a ## b
+#define SPLICE(a, b) SPLICE_I(a, b)
+
+#define SRC 8
+#include "blt1.h"
+#undef SRC
+
+#define SRC 16
+#include "blt1.h"
+#undef SRC
+
+#define SRC 32
+#include "blt1.h"
+#undef SRC
+
+static gvnc_blt_func *gvnc_blt_table[3][3] = {
+	{  gvnc_blt_8x8,  gvnc_blt_8x16,  gvnc_blt_8x32 },
+	{ gvnc_blt_16x8, gvnc_blt_16x16, gvnc_blt_16x32 },
+	{ gvnc_blt_32x8, gvnc_blt_32x16, gvnc_blt_32x32 },
+};
+
+static gvnc_hextile_func *gvnc_hextile_table[3][3] = {
+	{ (gvnc_hextile_func *)gvnc_hextile_8x8,
+	  (gvnc_hextile_func *)gvnc_hextile_8x16,
+	  (gvnc_hextile_func *)gvnc_hextile_8x32 },
+	{ (gvnc_hextile_func *)gvnc_hextile_16x8,
+	  (gvnc_hextile_func *)gvnc_hextile_16x16,
+	  (gvnc_hextile_func *)gvnc_hextile_16x32 },
+	{ (gvnc_hextile_func *)gvnc_hextile_32x8,
+	  (gvnc_hextile_func *)gvnc_hextile_32x16,
+	  (gvnc_hextile_func *)gvnc_hextile_32x32 },
+};
+
+static gvnc_set_pixel_at_func *gvnc_set_pixel_at_table[3][3] = {
+	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x8,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x16,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_8x32 },
+	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x8,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x16,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_16x32 },
+	{ (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x8,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x16,
+	  (gvnc_set_pixel_at_func *)gvnc_set_pixel_at_32x32 },
+};
+
+static gvnc_fill_func *gvnc_fill_table[3][3] = {
+	{ (gvnc_fill_func *)gvnc_fill_8x8,
+	  (gvnc_fill_func *)gvnc_fill_8x16,
+	  (gvnc_fill_func *)gvnc_fill_8x32 },
+	{ (gvnc_fill_func *)gvnc_fill_16x8,
+	  (gvnc_fill_func *)gvnc_fill_16x16,
+	  (gvnc_fill_func *)gvnc_fill_16x32 },
+	{ (gvnc_fill_func *)gvnc_fill_32x8,
+	  (gvnc_fill_func *)gvnc_fill_32x16,
+	  (gvnc_fill_func *)gvnc_fill_32x32 },
+};
+
+static gvnc_rich_cursor_blt_func *gvnc_rich_cursor_blt_table[3] = {
+	gvnc_rich_cursor_blt_8x32,
+	gvnc_rich_cursor_blt_16x32,
+	gvnc_rich_cursor_blt_32x32,
+};
+
+static gvnc_rgb24_blt_func *gvnc_rgb24_blt_table[3] = {
+	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x8,
+	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x16,
+	(gvnc_rgb24_blt_func *)gvnc_rgb24_blt_32x32,
+};
+
+static gvnc_tight_compute_predicted_func *gvnc_tight_compute_predicted_table[3] = {
+	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_8x8,
+	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_16x16,
+	(gvnc_tight_compute_predicted_func *)gvnc_tight_compute_predicted_32x32,
+};
+
+static gvnc_tight_sum_pixel_func *gvnc_tight_sum_pixel_table[3] = {
+	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_8x8,
+	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_16x16,
+	(gvnc_tight_sum_pixel_func *)gvnc_tight_sum_pixel_32x32,
+};
+
+/* a fast blit for the perfect match scenario */
+static void gvnc_blt_fast(struct gvnc *gvnc, guint8 *src, int pitch,
+			  int x, int y, int width, int height)
+{
+	guint8 *dst = gvnc_get_local(gvnc, x, y);
+	int i;
+	for (i = 0; i < height; i++) {
+		memcpy(dst, src, width * gvnc->local.bpp);
+		dst += gvnc->local.linesize;
+		src += pitch;
+	}
+}
+
+static void gvnc_blt(struct gvnc *gvnc, guint8 *src, int pitch,
+		     int x, int y, int width, int height)
+{
+	gvnc->blt(gvnc, src, pitch, x, y, width, height);
+}
+
+static void gvnc_raw_update(struct gvnc *gvnc,
+			    guint16 x, guint16 y,
+			    guint16 width, guint16 height)
+{
+	guint8 *dst;
+	int i;
+
+	/* optimize for perfect match between server/client
+	   FWIW, in the local case, we ought to be doing a write
+	   directly from the source framebuffer and a read directly
+	   into the client framebuffer
+	 */
+	if (gvnc->perfect_match) {
+		dst = gvnc_get_local(gvnc, x, y);
+		for (i = 0; i < height; i++) {
+			gvnc_read(gvnc, dst, width * gvnc->local.bpp);
+			dst += gvnc->local.linesize;
+		}
+		return;
+	}
+
+	dst = g_malloc(width * (gvnc->fmt.bits_per_pixel / 8));
+	for (i = 0; i < height; i++) {
+		gvnc_read(gvnc, dst, width * (gvnc->fmt.bits_per_pixel / 8));
+		gvnc_blt(gvnc, dst, 0, x, y + i, width, 1);
+	}
+	g_free(dst);
+}
+
+static void gvnc_copyrect_update(struct gvnc *gvnc,
+				 guint16 dst_x, guint16 dst_y,
+				 guint16 width, guint16 height)
+{
+	int src_x, src_y;
+	guint8 *dst, *src;
+	int pitch = gvnc->local.linesize;
+	int i;
+
+	src_x = gvnc_read_u16(gvnc);
+	src_y = gvnc_read_u16(gvnc);
+
+	if (src_y < dst_y) {
+		pitch = -pitch;
+		src_y += (height - 1);
+		dst_y += (height - 1);
+	}
+
+	dst = gvnc_get_local(gvnc, dst_x, dst_y);
+	src = gvnc_get_local(gvnc, src_x, src_y);
+	for (i = 0; i < height; i++) {
+		memmove(dst, src, width * gvnc->local.bpp);
+		dst += pitch;
+		src += pitch;
+	}
+}
+
+static void gvnc_hextile_update(struct gvnc *gvnc,
+				guint16 x, guint16 y,
+				guint16 width, guint16 height)
+{
+	guint8 fg[4];
+	guint8 bg[4];
+
+	int j;
+	for (j = 0; j < height; j += 16) {
+		int i;
+		for (i = 0; i < width; i += 16) {
+			guint8 flags;
+			int w = MIN(16, width - i);
+			int h = MIN(16, height - j);
+
+			flags = gvnc_read_u8(gvnc);
+			gvnc->hextile(gvnc, flags, x + i, y + j, w, h, fg, bg);
+		}
+	}
+}
+
+static void gvnc_fill(struct gvnc *gvnc, guint8 *color,
+		      guint16 x, guint16 y, guint16 width, guint16 height)
+{
+	gvnc->fill(gvnc, color, x, y, width, height);
+}
+
+static void gvnc_set_pixel_at(struct gvnc *gvnc, int x, int y, guint8 *pixel)
+{
+	gvnc->set_pixel_at(gvnc, x, y, pixel);
+}
+
+static void gvnc_rre_update(struct gvnc *gvnc,
+			    guint16 x, guint16 y,
+			    guint16 width, guint16 height)
+{
+	guint8 bg[4];
+	guint32 num;
+	guint32 i;
+
+	num = gvnc_read_u32(gvnc);
+	gvnc_read_pixel(gvnc, bg);
+	gvnc_fill(gvnc, bg, x, y, width, height);
+
+	for (i = 0; i < num; i++) {
+		guint8 fg[4];
+		guint16 sub_x, sub_y, sub_w, sub_h;
+
+		gvnc_read_pixel(gvnc, fg);
+		sub_x = gvnc_read_u16(gvnc);
+		sub_y = gvnc_read_u16(gvnc);
+		sub_w = gvnc_read_u16(gvnc);
+		sub_h = gvnc_read_u16(gvnc);
+
+		gvnc_fill(gvnc, fg,
+			  x + sub_x, y + sub_y, sub_w, sub_h);
+	}
+}
+
+/* CPIXELs are optimized slightly.  32-bit pixel values are packed into 24-bit
+ * values. */
+static void gvnc_read_cpixel(struct gvnc *gvnc, guint8 *pixel)
+{
+	int bpp = gvnc_pixel_size(gvnc);
+
+	memset(pixel, 0, bpp);
+
+	if (bpp == 4 && gvnc->fmt.true_color_flag) {
+		int fitsInMSB = ((gvnc->fmt.red_shift > 7) &&
+				 (gvnc->fmt.green_shift > 7) &&
+				 (gvnc->fmt.blue_shift > 7));
+		int fitsInLSB = (((gvnc->fmt.red_max << gvnc->fmt.red_shift) < (1 << 24)) &&
+				 ((gvnc->fmt.green_max << gvnc->fmt.green_shift) < (1 << 24)) &&
+				 ((gvnc->fmt.blue_max << gvnc->fmt.blue_shift) < (1 << 24)));
+
+		/*
+		 * We need to analyse the shifts to see if they fit in 3 bytes,
+		 * rather than looking at the declared  'depth' for the format
+		 * because despite what the RFB spec says, this is what RealVNC
+		 * server actually does in practice.
+		 */
+		if (fitsInMSB || fitsInLSB) {
+			bpp = 3;
+			if (gvnc->fmt.depth == 24 &&
+			    gvnc->fmt.byte_order == G_BIG_ENDIAN)
+				pixel++;
+		}
+	}
+
+	gvnc_read(gvnc, pixel, bpp);
+}
+
+static void gvnc_zrle_update_tile_blit(struct gvnc *gvnc,
+				       guint16 x, guint16 y,
+				       guint16 width, guint16 height)
+{
+	guint8 blit_data[4 * 64 * 64];
+	int i, bpp;
+
+	bpp = gvnc_pixel_size(gvnc);
+
+	for (i = 0; i < width * height; i++)
+		gvnc_read_cpixel(gvnc, blit_data + (i * bpp));
+
+	gvnc_blt(gvnc, blit_data, width * bpp, x, y, width, height);
+}
+
+static guint8 gvnc_read_zrle_pi(struct gvnc *gvnc, int palette_size)
+{
+	guint8 pi = 0;
+
+	if (gvnc->zrle_pi_bits == 0) {
+		gvnc->zrle_pi = gvnc_read_u8(gvnc);
+		gvnc->zrle_pi_bits = 8;
+	}
+	if ( palette_size == 2) {
+		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 1)) & 1;
+		gvnc->zrle_pi_bits -= 1;
+	} else if ((palette_size == 3) || (palette_size == 4)) {
+		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 2)) & 3;
+		gvnc->zrle_pi_bits -= 2;
+	} else if ((palette_size >=5) && (palette_size <=16)){
+		pi = (gvnc->zrle_pi >> (gvnc->zrle_pi_bits - 4)) & 15;
+		gvnc->zrle_pi_bits -= 4;
+	}
+
+	return pi;
+}
+
+static void gvnc_zrle_update_tile_palette(struct gvnc *gvnc,
+					  guint8 palette_size,
+					  guint16 x, guint16 y,
+					  guint16 width, guint16 height)
+{
+	guint8 palette[128][4];
+	int i, j;
+
+	for (i = 0; i < palette_size; i++)
+		gvnc_read_cpixel(gvnc, palette[i]);
+
+	for (j = 0; j < height; j++) {
+		/* discard any padding bits */
+		gvnc->zrle_pi_bits = 0;
+
+		for (i = 0; i < width; i++) {
+			int ind = gvnc_read_zrle_pi(gvnc, palette_size);
+
+			gvnc_set_pixel_at(gvnc, x + i, y + j,
+					  palette[ind & 0x7F]);
+		}
+	}
+}
+
+static int gvnc_read_zrle_rl(struct gvnc *gvnc)
+{
+	int rl = 1;
+	guint8 b;
+
+	do {
+		b = gvnc_read_u8(gvnc);
+		rl += b;
+	} while (!gvnc_has_error(gvnc) && b == 255);
+
+	return rl;
+}
+
+static void gvnc_zrle_update_tile_rle(struct gvnc *gvnc,
+				      guint16 x, guint16 y,
+				      guint16 width, guint16 height)
+{
+	int i, j, rl = 0;
+	guint8 pixel[4];
+
+	for (j = 0; j < height; j++) {
+		for (i = 0; i < width; i++) {
+			if (rl == 0) {
+				gvnc_read_cpixel(gvnc, pixel);
+				rl = gvnc_read_zrle_rl(gvnc);
+			}
+			gvnc_set_pixel_at(gvnc, x + i, y + j, pixel);
+			rl -= 1;
+		}
+	}
+}
+
+static void gvnc_zrle_update_tile_prle(struct gvnc *gvnc,
+				       guint8 palette_size,
+				       guint16 x, guint16 y,
+				       guint16 width, guint16 height)
+{
+	int i, j, rl = 0;
+	guint8 palette[128][4];
+	guint8 pi = 0;
+
+	for (i = 0; i < palette_size; i++)
+		gvnc_read_cpixel(gvnc, palette[i]);
+
+	for (j = 0; j < height; j++) {
+		for (i = 0; i < width; i++) {
+			if (rl == 0) {
+				pi = gvnc_read_u8(gvnc);
+				if (pi & 0x80) {
+					rl = gvnc_read_zrle_rl(gvnc);
+					pi &= 0x7F;
+				} else
+					rl = 1;
+			}
+
+			gvnc_set_pixel_at(gvnc, x + i, y + j, palette[pi]);
+			rl -= 1;
+		}
+	}
+}
+
+static void gvnc_zrle_update_tile(struct gvnc *gvnc, guint16 x, guint16 y,
+				  guint16 width, guint16 height)
+{
+	guint8 subencoding = gvnc_read_u8(gvnc);
+	guint8 pixel[4];
+
+	if (subencoding == 0 ) {
+		/* Raw pixel data */
+		gvnc_zrle_update_tile_blit(gvnc, x, y, width, height);
+	} else if (subencoding == 1) {
+		/* Solid tile of a single color */
+		gvnc_read_cpixel(gvnc, pixel);
+		gvnc_fill(gvnc, pixel, x, y, width, height);
+	} else if ((subencoding >= 2) && (subencoding <= 16)) {
+		/* Packed palette types */
+		gvnc_zrle_update_tile_palette(gvnc, subencoding,
+					      x, y, width, height);
+	} else if ((subencoding >= 17) && (subencoding <= 127)) {
+		/* FIXME raise error? */
+	} else if (subencoding == 128) {
+		/* Plain RLE */
+		gvnc_zrle_update_tile_rle(gvnc, x, y, width, height);
+	} else if (subencoding == 129) {
+
+	} else if (subencoding >= 130) {
+		/* Palette RLE */
+		gvnc_zrle_update_tile_prle(gvnc, subencoding - 128,
+					   x, y, width, height);
+	}
+}
+
+static void gvnc_zrle_update(struct gvnc *gvnc,
+			     guint16 x, guint16 y,
+			     guint16 width, guint16 height)
+
+{
+	guint32 length;
+	guint32 offset;
+	guint16 i, j;
+	guint8 *zlib_data;
+
+	length = gvnc_read_u32(gvnc);
+	zlib_data = g_malloc(length);
+	gvnc_read(gvnc, zlib_data, length);
+
+	/* setup subsequent calls to gvnc_read*() to use the compressed data */
+	gvnc->uncompressed_length = 0;
+	gvnc->compressed_length = length;
+	gvnc->compressed_buffer = zlib_data;
+	gvnc->strm = &gvnc->streams[0];
+
+	offset = 0;
+	for (j = 0; j < height; j += 64) {
+		for (i = 0; i < width; i += 64) {
+			guint16 w, h;
+
+			w = MIN(width - i, 64);
+			h = MIN(height - j, 64);
+			gvnc_zrle_update_tile(gvnc, x + i, y + j, w, h);
+		}
+	}
+
+	gvnc->strm = NULL;
+	gvnc->uncompressed_length = 0;
+	gvnc->compressed_length = 0;
+	gvnc->compressed_buffer = NULL;
+
+	g_free(zlib_data);
+}
+
+static void gvnc_rgb24_blt(struct gvnc *gvnc, int x, int y,
+			   int width, int height, guint8 *data, int pitch)
+{
+	gvnc->rgb24_blt(gvnc, x, y, width, height, data, pitch);
+}
+
+static guint32 gvnc_read_cint(struct gvnc *gvnc)
+{
+	guint32 value = 0;
+	guint8 val;
+
+	val = gvnc_read_u8(gvnc);
+	value = (val & 0x7F);
+	if (!(val & 0x80))
+		return value;
+
+	val = gvnc_read_u8(gvnc);
+	value |= (val & 0x7F) << 7;
+
+	if (!(val & 0x80))
+		return value;
+
+	value |= gvnc_read_u8(gvnc) << 14;
+
+	return value;
+}
+
+static int gvnc_tpixel_size(struct gvnc *gvnc)
+{
+	if (gvnc->fmt.depth == 24)
+		return 3;
+	return gvnc->fmt.bits_per_pixel / 8;
+}
+
+static void gvnc_read_tpixel(struct gvnc *gvnc, guint8 *pixel)
+{
+	if (gvnc->fmt.depth == 24) {
+		guint32 val;
+		gvnc_read(gvnc, pixel, 3);
+		val = (pixel[0] << gvnc->fmt.red_shift)
+			| (pixel[1] << gvnc->fmt.green_shift)
+			| (pixel[2] << gvnc->fmt.blue_shift);
+
+		if (gvnc->fmt.byte_order != G_BYTE_ORDER)
+			val =   (((val >>  0) & 0xFF) << 24) |
+				(((val >>  8) & 0xFF) << 16) |
+				(((val >> 16) & 0xFF) << 8) |
+				(((val >> 24) & 0xFF) << 0);
+
+		memcpy(pixel, &val, 4);
+	} else
+		gvnc_read_pixel(gvnc, pixel);
+}
+
+static void gvnc_tight_update_copy(struct gvnc *gvnc,
+				   guint16 x, guint16 y,
+				   guint16 width, guint16 height)
+{
+	guint8 pixel[4];
+	int i, j;
+
+	for (j = 0; j < height; j++) {
+		for (i = 0; i < width; i++) {
+			gvnc_read_tpixel(gvnc, pixel);
+			gvnc_set_pixel_at(gvnc, x + i, y + j, pixel);
+		}
+	}
+}
+
+static int gvnc_tight_get_pi(struct gvnc *gvnc, guint8 *ra,
+			     int i, guint8 palette_size)
+{
+	if (palette_size == 2) {
+		if ((i % 8) == 0)
+			*ra = gvnc_read_u8(gvnc);
+		return (*ra >> (7 - (i % 8))) & 1;
+	}
+
+	return gvnc_read_u8(gvnc);
+}
+
+static void gvnc_tight_update_palette(struct gvnc *gvnc,
+				      int palette_size, guint8 *palette,
+				      guint16 x, guint16 y,
+				      guint16 width, guint16 height)
+{
+	int i, j;
+
+	for (j = 0; j < height; j++) {
+		guint8 ra = 0;
+
+		for (i = 0; i < width; i++) {
+			guint8 ind;
+
+			ind = gvnc_tight_get_pi(gvnc, &ra, i, palette_size);
+			gvnc_set_pixel_at(gvnc, x + i, y + j,
+					  &palette[ind * 4]);
+		}
+	}
+}
+
+static void gvnc_tight_compute_predicted(struct gvnc *gvnc, guint8 *ppixel,
+					  guint8 *lp, guint8 *cp,
+					  guint8 *llp)
+{
+	gvnc->tight_compute_predicted(gvnc, ppixel, lp, cp, llp);
+}
+
+static void gvnc_tight_sum_pixel(struct gvnc *gvnc,
+				 guint8 *lhs, guint8 *rhs)
+{
+	gvnc->tight_sum_pixel(gvnc, lhs, rhs);
+}
+
+static void gvnc_tight_update_gradient(struct gvnc *gvnc,
+				       guint16 x, guint16 y,
+				       guint16 width, guint16 height)
+{
+	int i, j;
+	guint8 zero_pixel[4];
+	guint8 *last_row, *row;
+	int bpp;
+
+	bpp = gvnc_pixel_size(gvnc);
+	last_row = g_malloc(width * bpp);
+	row = g_malloc(width * bpp);
+
+	memset(last_row, 0, width * bpp);
+	memset(zero_pixel, 0, 4);
+
+	for (j = 0; j < height; j++) {
+		guint8 *tmp_row;
+		guint8 *llp, *lp;
+
+		/* use zero pixels for the edge cases */
+		llp = zero_pixel;
+		lp = zero_pixel;
+
+		for (i = 0; i < width; i++) {
+			guint8 predicted_pixel[4];
+
+			/* compute predicted pixel value */
+			gvnc_tight_compute_predicted(gvnc, predicted_pixel,
+						     lp, last_row + i * bpp,
+						     llp);
+
+			/* read the difference pixel from the wire */
+			gvnc_read_tpixel(gvnc, row + i * bpp);
+
+			/* sum the predicted pixel and the difference to get
+			 * the original pixel value */
+			gvnc_tight_sum_pixel(gvnc, row + i * bpp,
+					     predicted_pixel);
+
+			llp = last_row + i * bpp;
+			lp = row + i * bpp;
+		}
+
+		/* write out row of pixel data */
+		gvnc_blt(gvnc, row, width * bpp, x, y + j, width, 1);
+
+		/* swap last row and current row */
+		tmp_row = last_row;
+		last_row = row;
+		row = tmp_row;
+	}
+
+	g_free(row);
+	g_free(last_row);
+}
+
+static void jpeg_draw(void *opaque, int x, int y, int w, int h,
+		      guint8 *data, int stride)
+{
+	struct gvnc *gvnc = opaque;
+
+	gvnc_rgb24_blt(gvnc, x, y, w, h, data, stride);
+}
+
+static void gvnc_tight_update_jpeg(struct gvnc *gvnc, guint16 x, guint16 y,
+				   guint16 width, guint16 height,
+				   guint8 *data, size_t length)
+{
+	if (gvnc->ops.render_jpeg == NULL)
+		return;
+
+	gvnc->ops.render_jpeg(gvnc->ops_data, jpeg_draw, gvnc,
+			      x, y, width, height, data, length);
+}
+
+static void gvnc_tight_update(struct gvnc *gvnc,
+			      guint16 x, guint16 y,
+			      guint16 width, guint16 height)
+{
+	guint8 ccontrol;
+	guint8 pixel[4];
+	int i;
+
+	ccontrol = gvnc_read_u8(gvnc);
+
+	for (i = 0; i < 4; i++) {
+		if (ccontrol & (1 << i)) {
+			inflateEnd(&gvnc->streams[i + 1]);
+			inflateInit(&gvnc->streams[i + 1]);
+		}
+	}
+
+	ccontrol >>= 4;
+	ccontrol &= 0x0F;
+
+	if (ccontrol <= 7) {
+		/* basic */
+		guint8 filter_id = 0;
+		guint32 data_size, zlib_length;
+		guint8 *zlib_data = NULL;
+		guint8 palette[256][4];
+		int palette_size = 0;
+
+		if (ccontrol & 0x04)
+			filter_id = gvnc_read_u8(gvnc);
+
+		gvnc->strm = &gvnc->streams[(ccontrol & 0x03) + 1];
+
+		if (filter_id == 1) {
+			palette_size = gvnc_read_u8(gvnc);
+			palette_size += 1;
+			for (i = 0; i < palette_size; i++)
+				gvnc_read_tpixel(gvnc, palette[i]);
+		}
+
+		if (filter_id == 1) {
+			if (palette_size == 2)
+				data_size = ((width + 7) / 8) * height;
+			else
+				data_size = width * height;
+		} else
+			data_size = width * height * gvnc_tpixel_size(gvnc);
+
+		if (data_size >= 12) {
+			zlib_length = gvnc_read_cint(gvnc);
+			zlib_data = g_malloc(zlib_length);
+
+			gvnc_read(gvnc, zlib_data, zlib_length);
+
+			gvnc->uncompressed_length = 0;
+			gvnc->compressed_length = zlib_length;
+			gvnc->compressed_buffer = zlib_data;
+		}
+
+		switch (filter_id) {
+		case 0: /* copy */
+			gvnc_tight_update_copy(gvnc, x, y, width, height);
+			break;
+		case 1: /* palette */
+			gvnc_tight_update_palette(gvnc, palette_size,
+						  (guint8 *)palette,
+						  x, y, width, height);
+			break;
+		case 2: /* gradient */
+			gvnc_tight_update_gradient(gvnc, x, y, width, height);
+			break;
+		default: /* error */
+			GVNC_DEBUG("Closing the connection: gvnc_tight_update() - filter_id unknown");
+			gvnc->has_error = TRUE;
+			break;
+		}
+
+		if (data_size >= 12) {
+			gvnc->uncompressed_length = 0;
+			gvnc->compressed_length = 0;
+			gvnc->compressed_buffer = NULL;
+
+			g_free(zlib_data);
+		}
+
+		gvnc->strm = NULL;
+	} else if (ccontrol == 8) {
+		/* fill */
+		/* FIXME check each width; endianness */
+		gvnc_read_tpixel(gvnc, pixel);
+		gvnc_fill(gvnc, pixel, x, y, width, height);
+	} else if (ccontrol == 9) {
+		/* jpeg */
+		guint32 length;
+		guint8 *jpeg_data;
+
+		length = gvnc_read_cint(gvnc);
+		jpeg_data = g_malloc(length);
+		gvnc_read(gvnc, jpeg_data, length);
+		gvnc_tight_update_jpeg(gvnc, x, y, width, height,
+				       jpeg_data, length);
+		g_free(jpeg_data);
+	} else {
+		/* error */
+		GVNC_DEBUG("Closing the connection: gvnc_tight_update() - ccontrol unknown");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_update(struct gvnc *gvnc, int x, int y, int width, int height)
+{
+	if (gvnc->has_error || !gvnc->ops.update)
+		return;
+	if (!gvnc->ops.update(gvnc->ops_data, x, y, width, height)) {
+		GVNC_DEBUG("Closing the connection: gvnc_update");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_set_color_map_entry(struct gvnc *gvnc, guint16 color,
+				     guint16 red, guint16 green,
+				     guint16 blue)
+{
+	if (gvnc->has_error || !gvnc->ops.set_color_map_entry)
+		return;
+	if (!gvnc->ops.set_color_map_entry(gvnc->ops_data, color,
+					    red, green, blue)) {
+		GVNC_DEBUG("Closing the connection: gvnc_set_color_map_entry");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_bell(struct gvnc *gvnc)
+{
+	if (gvnc->has_error || !gvnc->ops.bell)
+		return;
+
+	GVNC_DEBUG("Server beep");
+
+	if (!gvnc->ops.bell(gvnc->ops_data)) {
+		GVNC_DEBUG("Closing the connection: gvnc_bell");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_server_cut_text(struct gvnc *gvnc, const void *data,
+				 size_t len)
+{
+	if (gvnc->has_error || !gvnc->ops.server_cut_text)
+		return;
+
+	if (!gvnc->ops.server_cut_text(gvnc->ops_data, data, len)) {
+		GVNC_DEBUG("Closing the connection: gvnc_server_cut_text");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_resize(struct gvnc *gvnc, int width, int height)
+{
+	if (gvnc->has_error)
+		return;
+
+	gvnc->width = width;
+	gvnc->height = height;
+
+	if (!gvnc->ops.resize)
+		return;
+
+	if (!gvnc->ops.resize(gvnc->ops_data, width, height)) {
+		GVNC_DEBUG("Closing the connection: gvnc_resize");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_pixel_format(struct gvnc *gvnc)
+{
+        if (gvnc->has_error || !gvnc->ops.pixel_format)
+                return;
+        if (!gvnc->ops.pixel_format(gvnc->ops_data, &gvnc->fmt))
+                gvnc->has_error = TRUE;
+}
+
+static void gvnc_pointer_type_change(struct gvnc *gvnc, int absolute)
+{
+	if (gvnc->has_error || !gvnc->ops.pointer_type_change)
+		return;
+	if (!gvnc->ops.pointer_type_change(gvnc->ops_data, absolute)) {
+		GVNC_DEBUG("Closing the connection: gvnc_pointer_type_change");
+		gvnc->has_error = TRUE;
+	}
+}
+
+static void gvnc_rich_cursor_blt(struct gvnc *gvnc, guint8 *pixbuf,
+				 guint8 *image, guint8 *mask,
+				 int pitch, guint16 width, guint16 height)
+{
+	gvnc->rich_cursor_blt(gvnc, pixbuf, image, mask, pitch, width, height);
+}
+
+static void gvnc_rich_cursor(struct gvnc *gvnc, int x, int y, int width, int height)
+{
+	guint8 *pixbuf = NULL;
+
+	if (width && height) {
+		guint8 *image, *mask;
+		int imagelen, masklen;
+
+		imagelen = width * height * (gvnc->fmt.bits_per_pixel / 8);
+		masklen = ((width + 7)/8) * height;
+
+		image = g_malloc(imagelen);
+		mask = g_malloc(masklen);
+		pixbuf = g_malloc(width * height * 4); /* RGB-A 8bit */
+
+		gvnc_read(gvnc, image, imagelen);
+		gvnc_read(gvnc, mask, masklen);
+
+		gvnc_rich_cursor_blt(gvnc, pixbuf, image, mask,
+				     width * (gvnc->fmt.bits_per_pixel/8),
+				     width, height);
+
+		g_free(image);
+		g_free(mask);
+	}
+
+	if (gvnc->has_error || !gvnc->ops.local_cursor)
+		return;
+	if (!gvnc->ops.local_cursor(gvnc->ops_data, x, y, width, height, pixbuf)) {
+		GVNC_DEBUG("Closing the connection: gvnc_rich_cursor() - !ops.local_cursor()");
+		gvnc->has_error = TRUE;
+	}
+
+	g_free(pixbuf);
+}
+
+static void gvnc_xcursor(struct gvnc *gvnc, int x, int y, int width, int height)
+{
+	guint8 *pixbuf = NULL;
+
+	if (width && height) {
+		guint8 *data, *mask, *datap, *maskp;
+		guint32 *pixp;
+		int rowlen;
+		int x1, y1;
+		guint8 fgrgb[3], bgrgb[3];
+		guint32 fg, bg;
+		gvnc_read(gvnc, fgrgb, 3);
+		gvnc_read(gvnc, bgrgb, 3);
+		fg = (255 << 24) | (fgrgb[0] << 16) | (fgrgb[1] << 8) | fgrgb[2];
+		bg = (255 << 24) | (bgrgb[0] << 16) | (bgrgb[1] << 8) | bgrgb[2];
+
+		rowlen = ((width + 7)/8);
+		data = g_malloc(rowlen*height);
+		mask = g_malloc(rowlen*height);
+		pixbuf = g_malloc(width * height * 4); /* RGB-A 8bit */
+
+		gvnc_read(gvnc, data, rowlen*height);
+		gvnc_read(gvnc, mask, rowlen*height);
+		datap = data;
+		maskp = mask;
+		pixp = (guint32*)pixbuf;
+		for (y1 = 0; y1 < height; y1++) {
+			for (x1 = 0; x1 < width; x1++) {
+				*pixp++ = ((maskp[x1 / 8] >> (7-(x1 % 8))) & 1) ?
+					(((datap[x1 / 8] >> (7-(x1 % 8))) & 1) ? fg : bg) : 0;
+			}
+			datap += rowlen;
+			maskp += rowlen;
+		}
+		g_free(data);
+		g_free(mask);
+	}
+
+	if (gvnc->has_error || !gvnc->ops.local_cursor)
+		return;
+	if (!gvnc->ops.local_cursor(gvnc->ops_data, x, y, width, height, pixbuf)) {
+		GVNC_DEBUG("Closing the connection: gvnc_xcursor() - !ops.local_cursor()");
+		gvnc->has_error = TRUE;
+	}
+
+	g_free(pixbuf);
+}
+
+static void gvnc_ext_key_event(struct gvnc *gvnc)
+{
+	gvnc->has_ext_key_event = TRUE;
+	gvnc->keycode_map = x_keycode_to_pc_keycode_map();
+}
+
+static void gvnc_framebuffer_update(struct gvnc *gvnc, gint32 etype,
+				    guint16 x, guint16 y,
+				    guint16 width, guint16 height)
+{
+	GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)",
+		   etype, x, y, width, height);
+
+	switch (etype) {
+	case GVNC_ENCODING_RAW:
+		gvnc_raw_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_COPY_RECT:
+		gvnc_copyrect_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_RRE:
+		gvnc_rre_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_HEXTILE:
+		gvnc_hextile_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_ZRLE:
+		gvnc_zrle_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_TIGHT:
+		gvnc_tight_update(gvnc, x, y, width, height);
+		gvnc_update(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_DESKTOP_RESIZE:
+		gvnc_framebuffer_update_request (gvnc, 0, 0, 0, width, height);
+		gvnc_resize(gvnc, width, height);
+		break;
+	case GVNC_ENCODING_POINTER_CHANGE:
+		gvnc_pointer_type_change(gvnc, x);
+		break;
+        case GVNC_ENCODING_WMVi:
+                gvnc_read_pixel_format(gvnc, &gvnc->fmt);
+                gvnc_pixel_format(gvnc);
+                break;
+	case GVNC_ENCODING_RICH_CURSOR:
+		gvnc_rich_cursor(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_XCURSOR:
+		gvnc_xcursor(gvnc, x, y, width, height);
+		break;
+	case GVNC_ENCODING_EXT_KEY_EVENT:
+		gvnc_ext_key_event(gvnc);
+		break;
+	default:
+		GVNC_DEBUG("Received an unknown encoding type: %d", etype);
+		gvnc->has_error = TRUE;
+		break;
+	}
+}
+
+gboolean gvnc_server_message(struct gvnc *gvnc)
+{
+	guint8 msg;
+	int ret;
+
+	/* NB: make sure that all server message functions
+	   handle has_error appropriately */
+
+	do {
+		if (gvnc->xmit_buffer_size) {
+			gvnc_write(gvnc, gvnc->xmit_buffer, gvnc->xmit_buffer_size);
+			gvnc_flush(gvnc);
+			gvnc->xmit_buffer_size = 0;
+		}
+	} while ((ret = gvnc_read_u8_interruptable(gvnc, &msg)) == -EAGAIN);
+
+	if (ret < 0) {
+		GVNC_DEBUG("Aborting message processing on error");
+		return !gvnc_has_error(gvnc);
+	}
+
+	switch (msg) {
+	case 0: { /* FramebufferUpdate */
+		guint8 pad[1];
+		guint16 n_rects;
+		int i;
+
+		gvnc_read(gvnc, pad, 1);
+		n_rects = gvnc_read_u16(gvnc);
+		for (i = 0; i < n_rects; i++) {
+			guint16 x, y, w, h;
+			gint32 etype;
+
+			x = gvnc_read_u16(gvnc);
+			y = gvnc_read_u16(gvnc);
+			w = gvnc_read_u16(gvnc);
+			h = gvnc_read_u16(gvnc);
+			etype = gvnc_read_s32(gvnc);
+
+			gvnc_framebuffer_update(gvnc, etype, x, y, w, h);
+		}
+	}	break;
+	case 1: { /* SetColorMapEntries */
+		guint16 first_color;
+		guint16 n_colors;
+		guint8 pad[1];
+		int i;
+
+		gvnc_read(gvnc, pad, 1);
+		first_color = gvnc_read_u16(gvnc);
+		n_colors = gvnc_read_u16(gvnc);
+
+		for (i = 0; i < n_colors; i++) {
+			guint16 red, green, blue;
+
+			red = gvnc_read_u16(gvnc);
+			green = gvnc_read_u16(gvnc);
+			blue = gvnc_read_u16(gvnc);
+
+			gvnc_set_color_map_entry(gvnc,
+						 i + first_color,
+						 red, green, blue);
+		}
+	}	break;
+	case 2: /* Bell */
+		gvnc_bell(gvnc);
+		break;
+	case 3: { /* ServerCutText */
+		guint8 pad[3];
+		guint32 n_text;
+		char *data;
+
+		gvnc_read(gvnc, pad, 3);
+		n_text = gvnc_read_u32(gvnc);
+		if (n_text > (32 << 20)) {
+			GVNC_DEBUG("Closing the connection: gvnc_server_message() - cutText > allowed");
+			gvnc->has_error = TRUE;
+			break;
+		}
+
+		data = g_new(char, n_text + 1);
+		if (data == NULL) {
+			GVNC_DEBUG("Closing the connection: gvnc_server_message() - cutText - !data");
+			gvnc->has_error = TRUE;
+			break;
+		}
+
+		gvnc_read(gvnc, data, n_text);
+		data[n_text] = 0;
+
+		gvnc_server_cut_text(gvnc, data, n_text);
+		g_free(data);
+	}	break;
+	default:
+		GVNC_DEBUG("Received an unknown message: %u", msg);
+		gvnc->has_error = TRUE;
+		break;
+	}
+
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_wants_credential_password(struct gvnc *gvnc)
+{
+	return gvnc->want_cred_password;
+}
+
+gboolean gvnc_wants_credential_username(struct gvnc *gvnc)
+{
+	return gvnc->want_cred_username;
+}
+
+gboolean gvnc_wants_credential_x509(struct gvnc *gvnc)
+{
+	return gvnc->want_cred_x509;
+}
+
+static gboolean gvnc_has_credentials(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc_wants_credential_username(gvnc) && !gvnc->cred_username)
+		return FALSE;
+	if (gvnc_wants_credential_password(gvnc) && !gvnc->cred_password)
+		return FALSE;
+	/*
+	 * For x509 we require a minimum of the CA cert.
+	 * Anything else is a bonus - though the server
+	 * may reject auth if it decides it wants a client
+	 * cert. We can't express that based on auth type
+	 * alone though - we'll merely find out when TLS
+	 * negotiation takes place.
+	 */
+	if (gvnc_wants_credential_x509(gvnc) && !gvnc->cred_x509_cacert)
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean gvnc_gather_credentials(struct gvnc *gvnc)
+{
+	if (!gvnc_has_credentials(gvnc)) {
+		GVNC_DEBUG("Requesting missing credentials");
+		if (gvnc->has_error || !gvnc->ops.auth_cred) {
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+		if (!gvnc->ops.auth_cred(gvnc->ops_data))
+		    gvnc->has_error = TRUE;
+		if (gvnc->has_error)
+			return FALSE;
+		GVNC_DEBUG("Waiting for missing credentials");
+		g_condition_wait(gvnc_has_credentials, gvnc);
+		GVNC_DEBUG("Got all credentials");
+	}
+	return !gvnc_has_error(gvnc);
+}
+
+
+static gboolean gvnc_check_auth_result(struct gvnc *gvnc)
+{
+	guint32 result;
+	GVNC_DEBUG("Checking auth result");
+	result = gvnc_read_u32(gvnc);
+	if (!result) {
+		GVNC_DEBUG("Success");
+		return TRUE;
+	}
+
+	if (gvnc->minor >= 8) {
+		guint32 len;
+		char reason[1024];
+		len = gvnc_read_u32(gvnc);
+		if (len > (sizeof(reason)-1))
+			return FALSE;
+		gvnc_read(gvnc, reason, len);
+		reason[len] = '\0';
+		GVNC_DEBUG("Fail %s", reason);
+		if (!gvnc->has_error && gvnc->ops.auth_failure)
+			gvnc->ops.auth_failure(gvnc->ops_data, reason);
+	} else {
+		GVNC_DEBUG("Fail auth no result");
+		if (!gvnc->has_error && gvnc->ops.auth_failure)
+			gvnc->ops.auth_failure(gvnc->ops_data, NULL);
+	}
+	return FALSE;
+}
+
+static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc)
+{
+	guint8 challenge[16];
+	guint8 key[8];
+
+	GVNC_DEBUG("Do Challenge");
+	gvnc->want_cred_password = TRUE;
+	gvnc->want_cred_username = FALSE;
+	gvnc->want_cred_x509 = FALSE;
+	if (!gvnc_gather_credentials(gvnc))
+		return FALSE;
+
+	if (!gvnc->cred_password)
+		return FALSE;
+
+	gvnc_read(gvnc, challenge, 16);
+
+	memset(key, 0, 8);
+	strncpy((char*)key, (char*)gvnc->cred_password, 8);
+
+	deskey(key, EN0);
+	des(challenge, challenge);
+	des(challenge + 8, challenge + 8);
+
+	gvnc_write(gvnc, challenge, 16);
+	gvnc_flush(gvnc);
+	return gvnc_check_auth_result(gvnc);
+}
+
+/*
+ *   marscha 2006 - Martin Scharpf
+ *   Encrypt bytes[length] in memory using key.
+ *   Key has to be 8 bytes, length a multiple of 8 bytes.
+ */
+static void
+vncEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
+       int i, j;
+       deskey(key, EN0);
+       for (i = 0; i< 8; i++)
+               where[i] ^= key[i];
+       des(where, where);
+       for (i = 8; i < length; i += 8) {
+               for (j = 0; j < 8; j++)
+                       where[i + j] ^= where[i + j - 8];
+               des(where + i, where + i);
+       }
+}
+
+static gboolean gvnc_perform_auth_mslogon(struct gvnc *gvnc)
+{
+       struct gvnc_dh *dh;
+       guchar gen[8], mod[8], resp[8], pub[8], key[8];
+       gcry_mpi_t genmpi, modmpi, respmpi, pubmpi, keympi;
+       guchar username[256], password[64];
+       guint passwordLen, usernameLen;
+
+       GVNC_DEBUG("Do Challenge");
+       gvnc->want_cred_password = TRUE;
+       gvnc->want_cred_username = TRUE;
+       gvnc->want_cred_x509 = FALSE;
+       if (!gvnc_gather_credentials(gvnc))
+	       return FALSE;
+
+       gvnc_read(gvnc, gen, sizeof(gen));
+       gvnc_read(gvnc, mod, sizeof(mod));
+       gvnc_read(gvnc, resp, sizeof(resp));
+
+       genmpi = gvnc_bytes_to_mpi(gen);
+       modmpi = gvnc_bytes_to_mpi(mod);
+       respmpi = gvnc_bytes_to_mpi(resp);
+
+       dh = gvnc_dh_new(genmpi, modmpi);
+
+       pubmpi = gvnc_dh_gen_secret(dh);
+       gvnc_mpi_to_bytes(pubmpi, pub);
+
+       gvnc_write(gvnc, pub, sizeof(pub));
+
+       keympi = gvnc_dh_gen_key(dh, respmpi);
+       gvnc_mpi_to_bytes(keympi, key);
+
+       passwordLen = strlen(gvnc->cred_password);
+       usernameLen = strlen(gvnc->cred_username);
+       if (passwordLen > sizeof(password))
+               passwordLen = sizeof(password);
+       if (usernameLen > sizeof(username))
+               usernameLen = sizeof(username);
+
+       memset(password, 0, sizeof password);
+       memset(username, 0, sizeof username);
+       memcpy(password, gvnc->cred_password, passwordLen);
+       memcpy(username, gvnc->cred_username, usernameLen);
+
+       vncEncryptBytes2(username, sizeof(username), key);
+       vncEncryptBytes2(password, sizeof(password), key);
+
+       gvnc_write(gvnc, username, sizeof(username));
+       gvnc_write(gvnc, password, sizeof(password));
+       gvnc_flush(gvnc);
+
+       gcry_mpi_release(genmpi);
+       gcry_mpi_release(modmpi);
+       gcry_mpi_release(respmpi);
+       gvnc_dh_free (dh);
+
+       return gvnc_check_auth_result(gvnc);
+}
+
+#if HAVE_SASL
+/*
+ * NB, keep in sync with similar method in qemud/remote.c
+ */
+static char *gvnc_addr_to_string(struct sockaddr_storage *sa, socklen_t salen)
+{
+    char host[NI_MAXHOST], port[NI_MAXSERV];
+    char *addr;
+    int err;
+
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           port, sizeof(port),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+	    GVNC_DEBUG("Cannot resolve address %d: %s",
+		       err, gai_strerror(err));
+        return NULL;
+    }
+
+    addr = g_malloc0(strlen(host) + 1 + strlen(port) + 1);
+    strcpy(addr, host);
+    strcat(addr, ";");
+    strcat(addr, port);
+    return addr;
+}
+
+
+
+static gboolean
+gvnc_gather_sasl_credentials(struct gvnc *gvnc,
+			     sasl_interact_t *interact)
+{
+	int ninteract;
+
+	gvnc->want_cred_password = FALSE;
+	gvnc->want_cred_username = FALSE;
+	gvnc->want_cred_x509 = FALSE;
+
+	for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
+		switch (interact[ninteract].id) {
+		case SASL_CB_AUTHNAME:
+		case SASL_CB_USER:
+			gvnc->want_cred_username = TRUE;
+			break;
+
+		case SASL_CB_PASS:
+			gvnc->want_cred_password = TRUE;
+			break;
+
+		default:
+			GVNC_DEBUG("Unsupported credential %lu",
+				   interact[ninteract].id);
+			/* Unsupported */
+			return FALSE;
+		}
+	}
+
+	if ((gvnc->want_cred_password ||
+	     gvnc->want_cred_username) &&
+	    !gvnc_gather_credentials(gvnc)) {
+		GVNC_DEBUG("%s", "cannot gather sasl credentials");
+		return FALSE;
+	}
+
+	for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
+		switch (interact[ninteract].id) {
+		case SASL_CB_AUTHNAME:
+		case SASL_CB_USER:
+			interact[ninteract].result = gvnc->cred_username;
+			interact[ninteract].len = strlen(gvnc->cred_username);
+			GVNC_DEBUG("Gather Username %s", gvnc->cred_username);
+			break;
+
+		case SASL_CB_PASS:
+			interact[ninteract].result =  gvnc->cred_password;
+			interact[ninteract].len = strlen(gvnc->cred_password);
+			//GVNC_DEBUG("Gather Password %s", gvnc->cred_password);
+			break;
+		}
+	}
+
+	GVNC_DEBUG("%s", "Filled SASL interact");
+
+	return TRUE;
+}
+
+
+
+/*
+ *
+ * Init msg from server
+ *
+ *  u32 mechlist-length
+ *  u8-array mechlist-string
+ *
+ * Start msg to server
+ *
+ *  u32 mechname-length
+ *  u8-array mechname-string
+ *  u32 clientout-length
+ *  u8-array clientout-string
+ *
+ * Start msg from server
+ *
+ *  u32 serverin-length
+ *  u8-array serverin-string
+ *  u8 continue
+ *
+ * Step msg to server
+ *
+ *  u32 clientout-length
+ *  u8-array clientout-string
+ *
+ * Step msg from server
+ *
+ *  u32 serverin-length
+ *  u8-array serverin-string
+ *  u8 continue
+ */
+
+#define SASL_MAX_MECHLIST_LEN 300
+#define SASL_MAX_MECHNAME_LEN 100
+#define SASL_MAX_DATA_LEN (1024 * 1024)
+
+/* Perform the SASL authentication process
+ */
+static gboolean gvnc_perform_auth_sasl(struct gvnc *gvnc)
+{
+	sasl_conn_t *saslconn = NULL;
+	sasl_security_properties_t secprops;
+	const char *clientout;
+	char *serverin = NULL;
+	unsigned int clientoutlen, serverinlen;
+	int err, complete;
+	struct sockaddr_storage sa;
+	socklen_t salen;
+	char *localAddr = NULL, *remoteAddr = NULL;
+	const void *val;
+	sasl_ssf_t ssf;
+	sasl_callback_t saslcb[] = {
+		{ .id = SASL_CB_AUTHNAME },
+		//		{ .id = SASL_CB_USER },
+		{ .id = SASL_CB_PASS },
+		{ .id = 0 },
+	};
+	sasl_interact_t *interact = NULL;
+	guint32 mechlistlen;
+        char *mechlist;
+	const char *mechname;
+	gboolean ret;
+
+	/* Sets up the SASL library as a whole */
+	err = sasl_client_init(NULL);
+	GVNC_DEBUG("Client initialize SASL authentication %d", err);
+	if (err != SASL_OK) {
+		GVNC_DEBUG("failed to initialize SASL library: %d (%s)",
+			   err, sasl_errstring(err, NULL, NULL));
+		goto error;
+	}
+
+	/* Get local address in form  IPADDR:PORT */
+	salen = sizeof(sa);
+	if (getsockname(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) {
+		GVNC_DEBUG("failed to get sock address %d (%s)",
+			   errno, strerror(errno));
+		goto error;
+	}
+	if ((sa.ss_family == AF_INET ||
+	     sa.ss_family == AF_INET6) &&
+	    (localAddr = gvnc_addr_to_string(&sa, salen)) == NULL)
+		goto error;
+
+	/* Get remote address in form  IPADDR:PORT */
+	salen = sizeof(sa);
+	if (getpeername(gvnc->fd, (struct sockaddr*)&sa, &salen) < 0) {
+		GVNC_DEBUG("failed to get peer address %d (%s)",
+			   errno, strerror(errno));
+		g_free(localAddr);
+		goto error;
+	}
+	if ((sa.ss_family == AF_INET ||
+	     sa.ss_family == AF_INET6) &&
+	    (remoteAddr = gvnc_addr_to_string(&sa, salen)) == NULL) {
+		g_free(localAddr);
+		goto error;
+	}
+
+	GVNC_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'", gvnc->host, localAddr, remoteAddr);
+
+	/* Setup a handle for being a client */
+	err = sasl_client_new("vnc",
+			      gvnc->host,
+			      localAddr,
+			      remoteAddr,
+			      saslcb,
+			      SASL_SUCCESS_DATA,
+			      &saslconn);
+	g_free(localAddr);
+	g_free(remoteAddr);
+
+	if (err != SASL_OK) {
+		GVNC_DEBUG("Failed to create SASL client context: %d (%s)",
+			   err, sasl_errstring(err, NULL, NULL));
+		goto error;
+	}
+
+	/* Initialize some connection props we care about */
+	if (gvnc->tls_session) {
+		gnutls_cipher_algorithm_t cipher;
+
+		cipher = gnutls_cipher_get(gvnc->tls_session);
+		if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
+			GVNC_DEBUG("%s", "invalid cipher size for TLS session");
+			goto error;
+		}
+		ssf *= 8; /* key size is bytes, sasl wants bits */
+
+		GVNC_DEBUG("Setting external SSF %d", ssf);
+		err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
+		if (err != SASL_OK) {
+			GVNC_DEBUG("cannot set external SSF %d (%s)",
+				   err, sasl_errstring(err, NULL, NULL));
+			goto error;
+		}
+	}
+
+	memset (&secprops, 0, sizeof secprops);
+	/* If we've got TLS, we don't care about SSF */
+	secprops.min_ssf = gvnc->tls_session ? 0 : 56; /* Equiv to DES supported by all Kerberos */
+	secprops.max_ssf = gvnc->tls_session ? 0 : 100000; /* Very strong ! AES == 256 */
+	secprops.maxbufsize = 100000;
+	/* If we're not TLS, then forbid any anonymous or trivially crackable auth */
+	secprops.security_flags = gvnc->tls_session ? 0 :
+		SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
+
+	err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
+	if (err != SASL_OK) {
+		GVNC_DEBUG("cannot set security props %d (%s)",
+			   err, sasl_errstring(err, NULL, NULL));
+		goto error;
+	}
+
+	/* Get the supported mechanisms from the server */
+	mechlistlen = gvnc_read_u32(gvnc);
+	if (gvnc->has_error)
+		goto error;
+	if (mechlistlen > SASL_MAX_MECHLIST_LEN) {
+		GVNC_DEBUG("mechlistlen %d too long", mechlistlen);
+		goto error;
+	}
+
+	mechlist = g_malloc(mechlistlen+1);
+        gvnc_read(gvnc, mechlist, mechlistlen);
+	mechlist[mechlistlen] = '\0';
+	if (gvnc->has_error) {
+		g_free(mechlist);
+		mechlist = NULL;
+		goto error;
+	}
+
+#if 0
+	if (wantmech) {
+		if (strstr(mechlist, wantmech) == NULL) {
+			GVNC_DEBUG("SASL mechanism %s not supported by server",
+				   wantmech);
+			VIR_FREE(iret.mechlist);
+			goto error;
+		}
+		mechlist = wantmech;
+	}
+#endif
+
+ restart:
+	/* Start the auth negotiation on the client end first */
+	GVNC_DEBUG("Client start negotiation mechlist '%s'", mechlist);
+	err = sasl_client_start(saslconn,
+				mechlist,
+				&interact,
+				&clientout,
+				&clientoutlen,
+				&mechname);
+	if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
+		GVNC_DEBUG("Failed to start SASL negotiation: %d (%s)",
+			   err, sasl_errdetail(saslconn));
+		g_free(mechlist);
+		mechlist = NULL;
+		goto error;
+	}
+
+	/* Need to gather some credentials from the client */
+	if (err == SASL_INTERACT) {
+		if (!gvnc_gather_sasl_credentials(gvnc,
+						  interact)) {
+			GVNC_DEBUG("%s", "Failed to collect auth credentials");
+			goto error;
+		}
+		goto restart;
+	}
+
+	GVNC_DEBUG("Server start negotiation with mech %s. Data %d bytes %p '%s'",
+		   mechname, clientoutlen, clientout, clientout);
+
+	if (clientoutlen > SASL_MAX_DATA_LEN) {
+		GVNC_DEBUG("SASL negotiation data too long: %d bytes",
+			   clientoutlen);
+		goto error;
+	}
+
+	/* Send back the chosen mechname */
+	gvnc_write_u32(gvnc, strlen(mechname));
+	gvnc_write(gvnc, mechname, strlen(mechname));
+
+	/* NB, distinction of NULL vs "" is *critical* in SASL */
+	if (clientout) {
+		gvnc_write_u32(gvnc, clientoutlen + 1);
+		gvnc_write(gvnc, clientout, clientoutlen + 1);
+	} else {
+		gvnc_write_u32(gvnc, 0);
+	}
+	gvnc_flush(gvnc);
+	if (gvnc->has_error)
+		goto error;
+
+
+	GVNC_DEBUG("%s", "Getting sever start negotiation reply");
+	/* Read the 'START' message reply from server */
+	serverinlen = gvnc_read_u32(gvnc);
+	if (gvnc->has_error)
+		goto error;
+	if (serverinlen > SASL_MAX_DATA_LEN) {
+		GVNC_DEBUG("SASL negotiation data too long: %d bytes",
+			   clientoutlen);
+		goto error;
+	}
+
+	/* NB, distinction of NULL vs "" is *critical* in SASL */
+	if (serverinlen) {
+		serverin = g_malloc(serverinlen);
+		gvnc_read(gvnc, serverin, serverinlen);
+		serverin[serverinlen-1] = '\0';
+		serverinlen--;
+	} else {
+		serverin = NULL;
+	}
+	complete = gvnc_read_u8(gvnc);
+	if (gvnc->has_error)
+		goto error;
+
+	GVNC_DEBUG("Client start result complete: %d. Data %d bytes %p '%s'",
+		   complete, serverinlen, serverin, serverin);
+
+	/* Loop-the-loop...
+	 * Even if the server has completed, the client must *always* do at least one step
+	 * in this loop to verify the server isn't lying about something. Mutual auth */
+	for (;;) {
+	restep:
+		err = sasl_client_step(saslconn,
+				       serverin,
+				       serverinlen,
+				       &interact,
+				       &clientout,
+				       &clientoutlen);
+		if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
+			GVNC_DEBUG("Failed SASL step: %d (%s)",
+				   err, sasl_errdetail(saslconn));
+			goto error;
+		}
+
+		/* Need to gather some credentials from the client */
+		if (err == SASL_INTERACT) {
+			if (!gvnc_gather_sasl_credentials(gvnc,
+							  interact)) {
+				GVNC_DEBUG("%s", "Failed to collect auth credentials");
+				goto error;
+			}
+			goto restep;
+		}
+
+		if (serverin) {
+			g_free(serverin);
+			serverin = NULL;
+		}
+
+		GVNC_DEBUG("Client step result %d. Data %d bytes %p '%s'", err, clientoutlen, clientout, clientout);
+
+		/* Previous server call showed completion & we're now locally complete too */
+		if (complete && err == SASL_OK)
+			break;
+
+		/* Not done, prepare to talk with the server for another iteration */
+
+		/* NB, distinction of NULL vs "" is *critical* in SASL */
+		if (clientout) {
+			gvnc_write_u32(gvnc, clientoutlen + 1);
+			gvnc_write(gvnc, clientout, clientoutlen + 1);
+		} else {
+			gvnc_write_u32(gvnc, 0);
+		}
+		gvnc_flush(gvnc);
+		if (gvnc->has_error)
+			goto error;
+
+		GVNC_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
+
+		serverinlen = gvnc_read_u32(gvnc);
+		if (gvnc->has_error)
+			goto error;
+		if (serverinlen > SASL_MAX_DATA_LEN) {
+			GVNC_DEBUG("SASL negotiation data too long: %d bytes",
+				   clientoutlen);
+			goto error;
+		}
+
+		/* NB, distinction of NULL vs "" is *critical* in SASL */
+		if (serverinlen) {
+			serverin = g_malloc(serverinlen);
+			gvnc_read(gvnc, serverin, serverinlen);
+			serverin[serverinlen-1] = '\0';
+			serverinlen--;
+		} else {
+			serverin = NULL;
+		}
+		complete = gvnc_read_u8(gvnc);
+		if (gvnc->has_error)
+			goto error;
+
+		GVNC_DEBUG("Client step result complete: %d. Data %d bytes %p '%s'",
+			   complete, serverinlen, serverin, serverin);
+
+		/* This server call shows complete, and earlier client step was OK */
+		if (complete && err == SASL_OK) {
+			g_free(serverin);
+			serverin = NULL;
+			break;
+		}
+	}
+
+	/* Check for suitable SSF if non-TLS */
+	if (!gvnc->tls_session) {
+		err = sasl_getprop(saslconn, SASL_SSF, &val);
+		if (err != SASL_OK) {
+			GVNC_DEBUG("cannot query SASL ssf on connection %d (%s)",
+				   err, sasl_errstring(err, NULL, NULL));
+			goto error;
+		}
+		ssf = *(const int *)val;
+		GVNC_DEBUG("SASL SSF value %d", ssf);
+		if (ssf < 56) { /* 56 == DES level, good for Kerberos */
+			GVNC_DEBUG("negotiation SSF %d was not strong enough", ssf);
+			goto error;
+		}
+	}
+
+	GVNC_DEBUG("%s", "SASL authentication complete");
+	ret = gvnc_check_auth_result(gvnc);
+	/* This must come *after* check-auth-result, because the former
+	 * is defined to be sent unencrypted, and setting saslconn turns
+	 * on the SSF layer encryption processing */
+	gvnc->saslconn = saslconn;
+	return ret;
+
+ error:
+	gvnc->has_error = TRUE;
+	if (saslconn)
+		sasl_dispose(&saslconn);
+	return FALSE;
+}
+#endif /* HAVE_SASL */
+
+
+static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS)
+{
+	static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+	static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+	static const int kx_priority[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
+	static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
+	int ret;
+
+	GVNC_DEBUG("Do TLS handshake");
+	if (gvnc_tls_initialize() < 0) {
+		GVNC_DEBUG("Failed to init TLS");
+		gvnc->has_error = TRUE;
+		return FALSE;
+	}
+	if (gvnc->tls_session == NULL) {
+		if (gnutls_init(&gvnc->tls_session, GNUTLS_CLIENT) < 0) {
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+
+		if (gnutls_set_default_priority(gvnc->tls_session) < 0) {
+			gnutls_deinit(gvnc->tls_session);
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+
+		if (gnutls_kx_set_priority(gvnc->tls_session, anonTLS ? kx_anon : kx_priority) < 0) {
+			gnutls_deinit(gvnc->tls_session);
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+
+		if (gnutls_certificate_type_set_priority(gvnc->tls_session, cert_type_priority) < 0) {
+			gnutls_deinit(gvnc->tls_session);
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+
+		if (gnutls_protocol_set_priority(gvnc->tls_session, protocol_priority) < 0) {
+			gnutls_deinit(gvnc->tls_session);
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+
+		if (anonTLS) {
+			gnutls_anon_client_credentials anon_cred = gvnc_tls_initialize_anon_cred();
+			if (!anon_cred) {
+				gnutls_deinit(gvnc->tls_session);
+				gvnc->has_error = TRUE;
+				return FALSE;
+			}
+			if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
+				gnutls_deinit(gvnc->tls_session);
+				gvnc->has_error = TRUE;
+				return FALSE;
+			}
+		} else {
+			gvnc->want_cred_password = FALSE;
+			gvnc->want_cred_username = FALSE;
+			gvnc->want_cred_x509 = TRUE;
+			if (!gvnc_gather_credentials(gvnc))
+				return FALSE;
+
+			gnutls_certificate_credentials_t x509_cred = gvnc_tls_initialize_cert_cred(gvnc);
+			if (!x509_cred) {
+				gnutls_deinit(gvnc->tls_session);
+				gvnc->has_error = TRUE;
+				return FALSE;
+			}
+			if (gnutls_credentials_set(gvnc->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+				gnutls_deinit(gvnc->tls_session);
+				gvnc->has_error = TRUE;
+				return FALSE;
+			}
+		}
+
+		gnutls_transport_set_ptr(gvnc->tls_session, (gnutls_transport_ptr_t)gvnc);
+		gnutls_transport_set_push_function(gvnc->tls_session, gvnc_tls_push);
+		gnutls_transport_set_pull_function(gvnc->tls_session, gvnc_tls_pull);
+	}
+
+ retry:
+	if ((ret = gnutls_handshake(gvnc->tls_session)) < 0) {
+		if (!gnutls_error_is_fatal(ret)) {
+			GVNC_DEBUG("Handshake was blocking");
+			if (!gnutls_record_get_direction(gvnc->tls_session))
+				g_io_wait(gvnc->channel, G_IO_IN);
+			else
+				g_io_wait(gvnc->channel, G_IO_OUT);
+			goto retry;
+		}
+		GVNC_DEBUG("Handshake failed %s", gnutls_strerror(ret));
+		gnutls_deinit(gvnc->tls_session);
+		gvnc->tls_session = NULL;
+		gvnc->has_error = TRUE;
+		return FALSE;
+	}
+
+	GVNC_DEBUG("Handshake done");
+
+	if (anonTLS) {
+		return TRUE;
+	} else {
+		if (!gvnc_validate_certificate(gvnc)) {
+			GVNC_DEBUG("Certificate validation failed");
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+		return TRUE;
+	}
+}
+
+static gboolean gvnc_has_auth_subtype(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->auth_subtype == GVNC_AUTH_INVALID)
+		return FALSE;
+	return TRUE;
+}
+
+
+static gboolean gvnc_perform_auth_tls(struct gvnc *gvnc)
+{
+	unsigned int nauth, i;
+	unsigned int auth[20];
+
+	if (!gvnc_start_tls(gvnc, 1)) {
+		GVNC_DEBUG("Could not start TLS");
+		return FALSE;
+	}
+	GVNC_DEBUG("Completed TLS setup");
+
+	nauth = gvnc_read_u8(gvnc);
+	GVNC_DEBUG("Got %d subauths", nauth);
+	if (gvnc_has_error(gvnc))
+		return FALSE;
+
+	GVNC_DEBUG("Got %d subauths", nauth);
+	if (nauth == 0) {
+		GVNC_DEBUG("No sub-auth types requested");
+		return gvnc_check_auth_result(gvnc);
+	}
+
+	if (nauth > sizeof(auth)) {
+		GVNC_DEBUG("Too many (%d) auth types", nauth);
+		gvnc->has_error = TRUE;
+		return FALSE;
+	}
+	for (i = 0 ; i < nauth ; i++) {
+		auth[i] = gvnc_read_u8(gvnc);
+	}
+
+	for (i = 0 ; i < nauth ; i++) {
+		GVNC_DEBUG("Possible sub-auth %d", auth[i]);
+	}
+
+	if (gvnc->has_error || !gvnc->ops.auth_subtype)
+		return FALSE;
+
+	if (!gvnc->ops.auth_subtype(gvnc->ops_data, nauth, auth))
+		gvnc->has_error = TRUE;
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Waiting for auth subtype");
+	g_condition_wait(gvnc_has_auth_subtype, gvnc);
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Choose auth %d", gvnc->auth_subtype);
+
+	gvnc_write_u8(gvnc, gvnc->auth_subtype);
+	gvnc_flush(gvnc);
+
+	switch (gvnc->auth_subtype) {
+	case GVNC_AUTH_NONE:
+		if (gvnc->minor == 8)
+			return gvnc_check_auth_result(gvnc);
+		return TRUE;
+	case GVNC_AUTH_VNC:
+		return gvnc_perform_auth_vnc(gvnc);
+#if HAVE_SASL
+	case GVNC_AUTH_SASL:
+		return gvnc_perform_auth_sasl(gvnc);
+#endif
+	default:
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc)
+{
+	int major, minor, status, anonTLS;
+	unsigned int nauth, i;
+	unsigned int auth[20];
+
+	major = gvnc_read_u8(gvnc);
+	minor = gvnc_read_u8(gvnc);
+
+	if (major != 0 &&
+	    minor != 2) {
+		GVNC_DEBUG("Unsupported VeNCrypt version %d %d", major, minor);
+		return FALSE;
+	}
+
+	gvnc_write_u8(gvnc, major);
+	gvnc_write_u8(gvnc, minor);
+	gvnc_flush(gvnc);
+	status = gvnc_read_u8(gvnc);
+	if (status != 0) {
+		GVNC_DEBUG("Server refused VeNCrypt version %d %d", major, minor);
+		return FALSE;
+	}
+
+	nauth = gvnc_read_u8(gvnc);
+	if (nauth > (sizeof(auth)/sizeof(auth[0]))) {
+		GVNC_DEBUG("Too many (%d) auth types", nauth);
+		return FALSE;
+	}
+
+	for (i = 0 ; i < nauth ; i++) {
+		auth[i] = gvnc_read_u32(gvnc);
+	}
+
+	for (i = 0 ; i < nauth ; i++) {
+		GVNC_DEBUG("Possible auth %d", auth[i]);
+	}
+
+	if (gvnc->has_error || !gvnc->ops.auth_subtype)
+		return FALSE;
+
+	if (!gvnc->ops.auth_subtype(gvnc->ops_data, nauth, auth))
+		gvnc->has_error = TRUE;
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Waiting for auth subtype");
+	g_condition_wait(gvnc_has_auth_subtype, gvnc);
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Choose auth %d", gvnc->auth_subtype);
+
+	if (!gvnc_gather_credentials(gvnc))
+		return FALSE;
+
+#if !DEBUG
+	if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN) {
+		GVNC_DEBUG("Cowardly refusing to transmit plain text password");
+		return FALSE;
+	}
+#endif
+
+	gvnc_write_u32(gvnc, gvnc->auth_subtype);
+	gvnc_flush(gvnc);
+	status = gvnc_read_u8(gvnc);
+	if (status != 1) {
+		GVNC_DEBUG("Server refused VeNCrypt auth %d %d", gvnc->auth_subtype, status);
+		return FALSE;
+	}
+
+	switch (gvnc->auth_subtype) {
+	case GVNC_AUTH_VENCRYPT_TLSNONE:
+	case GVNC_AUTH_VENCRYPT_TLSPLAIN:
+	case GVNC_AUTH_VENCRYPT_TLSVNC:
+	case GVNC_AUTH_VENCRYPT_TLSSASL:
+		anonTLS = 1;
+		break;
+	default:
+		anonTLS = 0;
+	}
+
+	if (!gvnc_start_tls(gvnc, anonTLS)) {
+		GVNC_DEBUG("Could not start TLS");
+		return FALSE;
+	}
+	GVNC_DEBUG("Completed TLS setup, do subauth %d", gvnc->auth_subtype);
+
+	switch (gvnc->auth_subtype) {
+		/* Plain certificate based auth */
+	case GVNC_AUTH_VENCRYPT_TLSNONE:
+	case GVNC_AUTH_VENCRYPT_X509NONE:
+		GVNC_DEBUG("Completing auth");
+		return gvnc_check_auth_result(gvnc);
+
+		/* Regular VNC layered over TLS */
+	case GVNC_AUTH_VENCRYPT_TLSVNC:
+	case GVNC_AUTH_VENCRYPT_X509VNC:
+		GVNC_DEBUG("Handing off to VNC auth");
+		return gvnc_perform_auth_vnc(gvnc);
+
+#if HAVE_SASL
+		/* SASL layered over TLS */
+	case GVNC_AUTH_VENCRYPT_TLSSASL:
+	case GVNC_AUTH_VENCRYPT_X509SASL:
+		GVNC_DEBUG("Handing off to SASL auth");
+		return gvnc_perform_auth_sasl(gvnc);
+#endif
+
+	default:
+		GVNC_DEBUG("Unknown auth subtype %d", gvnc->auth_subtype);
+		return FALSE;
+	}
+}
+
+static gboolean gvnc_has_auth_type(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->auth_type == GVNC_AUTH_INVALID)
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean gvnc_perform_auth(struct gvnc *gvnc)
+{
+	unsigned int nauth, i;
+	unsigned int auth[10];
+
+	if (gvnc->minor <= 6) {
+		nauth = 1;
+		auth[0] = gvnc_read_u32(gvnc);
+	} else {
+		nauth = gvnc_read_u8(gvnc);
+		if (gvnc_has_error(gvnc))
+			return FALSE;
+
+		if (nauth == 0)
+			return gvnc_check_auth_result(gvnc);
+
+		if (nauth > sizeof(auth)) {
+			gvnc->has_error = TRUE;
+			return FALSE;
+		}
+		for (i = 0 ; i < nauth ; i++)
+			auth[i] = gvnc_read_u8(gvnc);
+	}
+
+	for (i = 0 ; i < nauth ; i++) {
+		GVNC_DEBUG("Possible auth %u", auth[i]);
+	}
+
+	if (gvnc->has_error || !gvnc->ops.auth_type)
+		return FALSE;
+
+	if (!gvnc->ops.auth_type(gvnc->ops_data, nauth, auth))
+		gvnc->has_error = TRUE;
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Waiting for auth type");
+	g_condition_wait(gvnc_has_auth_type, gvnc);
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Choose auth %u", gvnc->auth_type);
+	if (!gvnc_gather_credentials(gvnc))
+		return FALSE;
+
+	if (gvnc->minor > 6) {
+		gvnc_write_u8(gvnc, gvnc->auth_type);
+		gvnc_flush(gvnc);
+	}
+
+	switch (gvnc->auth_type) {
+	case GVNC_AUTH_NONE:
+		if (gvnc->minor == 8)
+			return gvnc_check_auth_result(gvnc);
+		return TRUE;
+	case GVNC_AUTH_VNC:
+		return gvnc_perform_auth_vnc(gvnc);
+
+	case GVNC_AUTH_TLS:
+		if (gvnc->minor < 7)
+			return FALSE;
+		return gvnc_perform_auth_tls(gvnc);
+
+	case GVNC_AUTH_VENCRYPT:
+		return gvnc_perform_auth_vencrypt(gvnc);
+
+#if HAVE_SASL
+	case GVNC_AUTH_SASL:
+ 		return gvnc_perform_auth_sasl(gvnc);
+#endif
+
+	case GVNC_AUTH_MSLOGON:
+		return gvnc_perform_auth_mslogon(gvnc);
+
+	default:
+		if (gvnc->ops.auth_unsupported)
+			gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type);
+		gvnc->has_error = TRUE;
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data)
+{
+	struct gvnc *gvnc = g_malloc0(sizeof(*gvnc));
+
+	gvnc->fd = -1;
+
+	memcpy(&gvnc->ops, ops, sizeof(*ops));
+	gvnc->ops_data = ops_data;
+	gvnc->auth_type = GVNC_AUTH_INVALID;
+	gvnc->auth_subtype = GVNC_AUTH_INVALID;
+
+	return gvnc;
+}
+
+void gvnc_free(struct gvnc *gvnc)
+{
+	if (!gvnc)
+		return;
+
+	if (gvnc_is_open(gvnc))
+		gvnc_close(gvnc);
+
+	g_free(gvnc);
+	gvnc = NULL;
+}
+
+void gvnc_close(struct gvnc *gvnc)
+{
+	int i;
+
+	if (gvnc->tls_session) {
+		gnutls_bye(gvnc->tls_session, GNUTLS_SHUT_RDWR);
+		gvnc->tls_session = NULL;
+	}
+#if HAVE_SASL
+	if (gvnc->saslconn)
+		sasl_dispose (&gvnc->saslconn);
+#endif
+
+	if (gvnc->channel) {
+		g_io_channel_unref(gvnc->channel);
+		gvnc->channel = NULL;
+	}
+	if (gvnc->fd != -1) {
+		close(gvnc->fd);
+		gvnc->fd = -1;
+	}
+
+	if (gvnc->host) {
+		g_free(gvnc->host);
+		gvnc->host = NULL;
+	}
+
+	if (gvnc->port) {
+		g_free(gvnc->port);
+		gvnc->port = NULL;
+	}
+
+	if (gvnc->name) {
+		g_free(gvnc->name);
+		gvnc->name = NULL;
+	}
+
+	g_free (gvnc->xmit_buffer);
+
+	if (gvnc->cred_username) {
+		g_free(gvnc->cred_username);
+		gvnc->cred_username = NULL;
+	}
+	if (gvnc->cred_password) {
+		g_free(gvnc->cred_password);
+		gvnc->cred_password = NULL;
+	}
+
+	if (gvnc->cred_x509_cacert) {
+		g_free(gvnc->cred_x509_cacert);
+		gvnc->cred_x509_cacert = NULL;
+	}
+	if (gvnc->cred_x509_cacrl) {
+		g_free(gvnc->cred_x509_cacrl);
+		gvnc->cred_x509_cacrl = NULL;
+	}
+	if (gvnc->cred_x509_cert) {
+		g_free(gvnc->cred_x509_cert);
+		gvnc->cred_x509_cert = NULL;
+	}
+	if (gvnc->cred_x509_key) {
+		g_free(gvnc->cred_x509_key);
+		gvnc->cred_x509_key = NULL;
+	}
+
+	for (i = 0; i < 5; i++)
+		inflateEnd(&gvnc->streams[i]);
+
+	gvnc->auth_type = GVNC_AUTH_INVALID;
+	gvnc->auth_subtype = GVNC_AUTH_INVALID;
+
+	gvnc->has_error = 0;
+}
+
+void gvnc_shutdown(struct gvnc *gvnc)
+{
+	close(gvnc->fd);
+	gvnc->fd = -1;
+	gvnc->has_error = 1;
+	GVNC_DEBUG("Waking up couroutine to shutdown gracefully");
+	g_io_wakeup(&gvnc->wait);
+}
+
+gboolean gvnc_is_open(struct gvnc *gvnc)
+{
+	if (!gvnc)
+		return FALSE;
+
+	if (gvnc->fd != -1)
+		return TRUE;
+	if (gvnc->host)
+		return TRUE;
+	return FALSE;
+}
+
+
+gboolean gvnc_is_initialized(struct gvnc *gvnc)
+{
+	if (!gvnc_is_open(gvnc))
+		return FALSE;
+	if (gvnc->name)
+		return TRUE;
+	return FALSE;
+}
+
+static gboolean gvnc_before_version (struct gvnc *gvnc, int major, int minor) {
+	return (gvnc->major < major) || (gvnc->major == major && gvnc->minor < minor);
+}
+static gboolean gvnc_after_version (struct gvnc *gvnc, int major, int minor) {
+	return !gvnc_before_version (gvnc, major, minor+1);
+}
+
+gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag)
+{
+	int ret, i;
+	char version[13];
+	guint32 n_name;
+
+	gvnc->absolute = 1;
+
+	gvnc_read(gvnc, version, 12);
+	version[12] = 0;
+
+ 	ret = sscanf(version, "RFB %03d.%03d\n", &gvnc->major, &gvnc->minor);
+	if (ret != 2) {
+		GVNC_DEBUG("Error while getting server version");
+		goto fail;
+	}
+
+	GVNC_DEBUG("Server version: %d.%d", gvnc->major, gvnc->minor);
+
+	if (gvnc_before_version(gvnc, 3, 3)) {
+		GVNC_DEBUG("Server version is not supported (%d.%d)", gvnc->major, gvnc->minor);
+		goto fail;
+	} else if (gvnc_before_version(gvnc, 3, 7)) {
+		gvnc->minor = 3;
+	} else if (gvnc_after_version(gvnc, 3, 8)) {
+		gvnc->major = 3;
+		gvnc->minor = 8;
+	}
+
+	snprintf(version, 12, "RFB %03d.%03d\n", gvnc->major, gvnc->minor);
+	gvnc_write(gvnc, version, 12);
+	gvnc_flush(gvnc);
+	GVNC_DEBUG("Using version: %d.%d", gvnc->major, gvnc->minor);
+
+	if (!gvnc_perform_auth(gvnc)) {
+		GVNC_DEBUG("Auth failed");
+		goto fail;
+	}
+
+	gvnc_write_u8(gvnc, shared_flag); /* shared flag */
+	gvnc_flush(gvnc);
+	gvnc->width = gvnc_read_u16(gvnc);
+	gvnc->height = gvnc_read_u16(gvnc);
+
+	if (gvnc_has_error(gvnc))
+		return FALSE;
+
+	gvnc_read_pixel_format(gvnc, &gvnc->fmt);
+
+	n_name = gvnc_read_u32(gvnc);
+	if (n_name > 4096)
+		goto fail;
+
+	gvnc->name = g_new(char, n_name + 1);
+
+	gvnc_read(gvnc, gvnc->name, n_name);
+	gvnc->name[n_name] = 0;
+	GVNC_DEBUG("Display name '%s'", gvnc->name);
+
+	if (gvnc_has_error(gvnc))
+		return FALSE;
+
+	if (!gvnc->ops.get_preferred_pixel_format)
+		goto fail;
+	if (gvnc->ops.get_preferred_pixel_format(gvnc->ops_data, &gvnc->fmt))
+		gvnc_set_pixel_format(gvnc, &gvnc->fmt);
+	else
+		goto fail;
+	memset(&gvnc->strm, 0, sizeof(gvnc->strm));
+	/* FIXME what level? */
+	for (i = 0; i < 5; i++)
+		inflateInit(&gvnc->streams[i]);
+	gvnc->strm = NULL;
+
+	gvnc_resize(gvnc, gvnc->width, gvnc->height);
+	return !gvnc_has_error(gvnc);
+
+ fail:
+	gvnc->has_error = 1;
+	return !gvnc_has_error(gvnc);
+}
+
+static gboolean gvnc_set_nonblock(int fd)
+{
+#ifndef WIN32
+	int flags;
+	if ((flags = fcntl(fd, F_GETFL)) < 0) {
+		GVNC_DEBUG ("Failed to fcntl()");
+		return FALSE;
+	}
+	flags |= O_NONBLOCK;
+	if (fcntl(fd, F_SETFL, flags) < 0) {
+		GVNC_DEBUG ("Failed to fcntl()");
+		return FALSE;
+	}
+
+#else /* WIN32 */
+	unsigned long flag = 1;
+
+	/* This is actually Gnulib's replacement rpl_ioctl function.
+	 * We can't call ioctlsocket directly in any case.
+	 */
+	if (ioctl (fd, FIONBIO, (void *) &flag) == -1) {
+		GVNC_DEBUG ("Failed to set nonblocking flag, winsock error = %d",
+			    WSAGetLastError ());
+		return FALSE;
+	}
+#endif /* WIN32 */
+
+	return TRUE;
+}
+
+gboolean gvnc_open_fd(struct gvnc *gvnc, int fd)
+{
+	if (gvnc_is_open(gvnc)) {
+		GVNC_DEBUG ("Error: already connected?");
+		return FALSE;
+	}
+
+	GVNC_DEBUG("Connecting to FD %d", fd);
+
+	if (!gvnc_set_nonblock(fd))
+		return FALSE;
+
+	if (!(gvnc->channel =
+#ifdef WIN32
+	      g_io_channel_win32_new_socket(_get_osfhandle(fd))
+#else
+	      g_io_channel_unix_new(fd)
+#endif
+	      )) {
+		GVNC_DEBUG ("Failed to g_io_channel_unix_new()");
+		return FALSE;
+	}
+	gvnc->fd = fd;
+
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_open_host(struct gvnc *gvnc, const char *host, const char *port)
+{
+        struct addrinfo *ai, *runp, hints;
+        int ret;
+	if (gvnc_is_open(gvnc))
+		return FALSE;
+
+	gvnc->host = g_strdup(host);
+	gvnc->port = g_strdup(port);
+
+        GVNC_DEBUG("Resolving host %s %s", host, port);
+        memset (&hints, '\0', sizeof (hints));
+        hints.ai_flags = AI_ADDRCONFIG;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = IPPROTO_TCP;
+
+        if ((ret = getaddrinfo(host, port, &hints, &ai)) != 0) {
+		GVNC_DEBUG ("Failed to resolve hostname");
+		return FALSE;
+	}
+
+        runp = ai;
+        while (runp != NULL) {
+                int fd;
+                GIOChannel *chan;
+
+		if ((fd = socket(runp->ai_family, runp->ai_socktype,
+			runp->ai_protocol)) < 0) {
+			GVNC_DEBUG ("Failed to socket()");
+			break;
+		}
+
+                GVNC_DEBUG("Trying socket %d", fd);
+		if (!gvnc_set_nonblock(fd))
+			break;
+
+                if (!(chan =
+#ifdef WIN32
+		      g_io_channel_win32_new_socket(_get_osfhandle(fd))
+#else
+		      g_io_channel_unix_new(fd)
+#endif
+		      )) {
+                        close(fd);
+                        GVNC_DEBUG ("Failed to g_io_channel_unix_new()");
+                        break;
+                }
+
+        reconnect:
+                /* FIXME: Better handle EINPROGRESS/EISCONN return values,
+                   as explained in connect(2) man page */
+                if ((connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) ||
+		    errno == EISCONN) {
+                        gvnc->channel = chan;
+                        gvnc->fd = fd;
+                        freeaddrinfo(ai);
+                        return !gvnc_has_error(gvnc);
+                }
+                if (errno == EINPROGRESS ||
+                    errno == EWOULDBLOCK) {
+                        g_io_wait(chan, G_IO_OUT|G_IO_ERR|G_IO_HUP);
+                        goto reconnect;
+                } else if (errno != ECONNREFUSED &&
+                           errno != EHOSTUNREACH) {
+                        g_io_channel_unref(chan);
+                        close(fd);
+                        GVNC_DEBUG ("Failed with errno = %d", errno);
+                        break;
+                }
+                close(fd);
+                g_io_channel_unref(chan);
+                runp = runp->ai_next;
+        }
+        freeaddrinfo (ai);
+	return FALSE;
+}
+
+
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type)
+{
+        GVNC_DEBUG("Thinking about auth type %u", type);
+        if (gvnc->auth_type != GVNC_AUTH_INVALID) {
+                gvnc->has_error = TRUE;
+                return !gvnc_has_error(gvnc);
+        }
+        if (type != GVNC_AUTH_NONE &&
+            type != GVNC_AUTH_VNC &&
+            type != GVNC_AUTH_MSLOGON &&
+            type != GVNC_AUTH_TLS &&
+            type != GVNC_AUTH_VENCRYPT &&
+            type != GVNC_AUTH_SASL) {
+		GVNC_DEBUG("Unsupported auth type %u", type);
+            	if (gvnc->ops.auth_unsupported)
+			gvnc->ops.auth_unsupported (gvnc->ops_data, type);
+
+                gvnc->has_error = TRUE;
+                return !gvnc_has_error(gvnc);
+        }
+        GVNC_DEBUG("Decided on auth type %u", type);
+        gvnc->auth_type = type;
+        gvnc->auth_subtype = GVNC_AUTH_INVALID;
+
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type)
+{
+        GVNC_DEBUG("Requested auth subtype %d", type);
+        if (gvnc->auth_type != GVNC_AUTH_VENCRYPT &&
+	    gvnc->auth_type != GVNC_AUTH_TLS) {
+                gvnc->has_error = TRUE;
+		return !gvnc_has_error(gvnc);
+        }
+        if (gvnc->auth_subtype != GVNC_AUTH_INVALID) {
+                gvnc->has_error = TRUE;
+		return !gvnc_has_error(gvnc);
+        }
+        gvnc->auth_subtype = type;
+
+	return !gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password)
+{
+        GVNC_DEBUG("Set password credential %s", password);
+        if (gvnc->cred_password)
+                g_free(gvnc->cred_password);
+        if (!(gvnc->cred_password = g_strdup(password))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username)
+{
+        GVNC_DEBUG("Set username credential %s", username);
+        if (gvnc->cred_username)
+                g_free(gvnc->cred_username);
+        if (!(gvnc->cred_username = g_strdup(username))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cacert %s", file);
+        if (gvnc->cred_x509_cacert)
+                g_free(gvnc->cred_x509_cacert);
+        if (!(gvnc->cred_x509_cacert = g_strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cacrl %s", file);
+        if (gvnc->cred_x509_cacrl)
+                g_free(gvnc->cred_x509_cacrl);
+        if (!(gvnc->cred_x509_cacrl = g_strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 key %s", file);
+        if (gvnc->cred_x509_key)
+                g_free(gvnc->cred_x509_key);
+        if (!(gvnc->cred_x509_key = g_strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file)
+{
+        GVNC_DEBUG("Set x509 cert %s", file);
+        if (gvnc->cred_x509_cert)
+                g_free(gvnc->cred_x509_cert);
+        if (!(gvnc->cred_x509_cert = g_strdup(file))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+
+gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb)
+{
+	int i, j, n;
+	int depth;
+
+	memcpy(&gvnc->local, fb, sizeof(*fb));
+
+	if (fb->bpp == (gvnc->fmt.bits_per_pixel / 8) &&
+	    fb->red_mask == gvnc->fmt.red_max &&
+	    fb->green_mask == gvnc->fmt.green_max &&
+	    fb->blue_mask == gvnc->fmt.blue_max &&
+	    fb->red_shift == gvnc->fmt.red_shift &&
+	    fb->green_shift == gvnc->fmt.green_shift &&
+	    fb->blue_shift == gvnc->fmt.blue_shift &&
+	    fb->byte_order == G_BYTE_ORDER &&
+	    gvnc->fmt.byte_order == G_BYTE_ORDER)
+		gvnc->perfect_match = TRUE;
+	else
+		gvnc->perfect_match = FALSE;
+
+	depth = gvnc->fmt.depth;
+	if (depth == 32)
+		depth = 24;
+
+	gvnc->rm = gvnc->local.red_mask & gvnc->fmt.red_max;
+	gvnc->gm = gvnc->local.green_mask & gvnc->fmt.green_max;
+	gvnc->bm = gvnc->local.blue_mask & gvnc->fmt.blue_max;
+	GVNC_DEBUG("Mask local: %3d %3d %3d\n"
+		   "    remote: %3d %3d %3d\n"
+		   "    merged: %3d %3d %3d",
+		   gvnc->local.red_mask, gvnc->local.green_mask, gvnc->local.blue_mask,
+		   gvnc->fmt.red_max, gvnc->fmt.green_max, gvnc->fmt.blue_max,
+		   gvnc->rm, gvnc->gm, gvnc->bm);
+
+	/* Setup shifts assuming matched bpp (but not necessarily match rgb order)*/
+	gvnc->rrs = gvnc->fmt.red_shift;
+	gvnc->grs = gvnc->fmt.green_shift;
+	gvnc->brs = gvnc->fmt.blue_shift;
+
+	gvnc->rls = gvnc->local.red_shift;
+	gvnc->gls = gvnc->local.green_shift;
+	gvnc->bls = gvnc->local.blue_shift;
+
+	/* This adjusts for remote having more bpp than local */
+	for (n = gvnc->fmt.red_max; n > gvnc->local.red_mask ; n>>= 1)
+		gvnc->rrs++;
+	for (n = gvnc->fmt.green_max; n > gvnc->local.green_mask ; n>>= 1)
+		gvnc->grs++;
+	for (n = gvnc->fmt.blue_max; n > gvnc->local.blue_mask ; n>>= 1)
+		gvnc->brs++;
+
+	/* This adjusts for remote having less bpp than remote */
+	for (n = gvnc->local.red_mask ; n > gvnc->fmt.red_max ; n>>= 1)
+		gvnc->rls++;
+	for (n = gvnc->local.green_mask ; n > gvnc->fmt.green_max ; n>>= 1)
+		gvnc->gls++;
+	for (n = gvnc->local.blue_mask ; n > gvnc->fmt.blue_max ; n>>= 1)
+		gvnc->bls++;
+	GVNC_DEBUG("Pixel shifts\n   right: %3d %3d %3d\n    left: %3d %3d %3d",
+		   gvnc->rrs, gvnc->grs, gvnc->brs,
+		   gvnc->rls, gvnc->gls, gvnc->bls);
+
+	i = gvnc->fmt.bits_per_pixel / 8;
+	j = gvnc->local.bpp;
+
+	if (i == 4) i = 3;
+	if (j == 4) j = 3;
+
+	gvnc->blt = gvnc_blt_table[i - 1][j - 1];
+	gvnc->fill = gvnc_fill_table[i - 1][j - 1];
+	gvnc->set_pixel_at = gvnc_set_pixel_at_table[i - 1][j - 1];
+	gvnc->hextile = gvnc_hextile_table[i - 1][j - 1];
+	gvnc->rich_cursor_blt = gvnc_rich_cursor_blt_table[i - 1];
+	gvnc->rgb24_blt = gvnc_rgb24_blt_table[i - 1];
+	gvnc->tight_compute_predicted = gvnc_tight_compute_predicted_table[i - 1];
+	gvnc->tight_sum_pixel = gvnc_tight_sum_pixel_table[i - 1];
+
+	if (gvnc->perfect_match)
+		gvnc->blt = gvnc_blt_fast;
+
+	return !gvnc_has_error(gvnc);
+}
+
+const char *gvnc_get_name(struct gvnc *gvnc)
+{
+	return gvnc->name;
+}
+
+int gvnc_get_width(struct gvnc *gvnc)
+{
+	return gvnc->width;
+}
+
+int gvnc_get_height(struct gvnc *gvnc)
+{
+	return gvnc->height;
+}
+
+gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc)
+{
+	return gvnc->has_ext_key_event;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/vncconnection.h b/src/vncconnection.h
new file mode 100644
index 0000000..86e69e6
--- /dev/null
+++ b/src/vncconnection.h
@@ -0,0 +1,217 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef _GVNC_H_
+#define _GVNC_H_
+
+#include <glib.h>
+#include <stdint.h>
+
+struct gvnc;
+
+struct gvnc_pixel_format;
+
+typedef void (rgb24_render_func)(void *, int, int, int, int, guint8 *, int);
+
+struct gvnc_ops
+{
+	gboolean (*auth_cred)(void *);
+	gboolean (*auth_type)(void *, unsigned int, unsigned int *);
+	gboolean (*auth_subtype)(void *, unsigned int, unsigned int *);
+	gboolean (*auth_failure)(void *, const char *);
+	gboolean (*update)(void *, int, int, int, int);
+	gboolean (*set_color_map_entry)(void *, int, int, int, int);
+	gboolean (*bell)(void *);
+	gboolean (*server_cut_text)(void *, const void *, size_t);
+	gboolean (*resize)(void *, int, int);
+        gboolean (*pixel_format)(void *, struct gvnc_pixel_format *);
+	gboolean (*pointer_type_change)(void *, int);
+	gboolean (*local_cursor)(void *, int, int, int, int, guint8 *);
+	gboolean (*auth_unsupported)(void *, unsigned int);
+	gboolean (*render_jpeg)(void *, rgb24_render_func *render, void *,
+				int, int, int, int, guint8 *, int);
+	gboolean (*get_preferred_pixel_format)(void *, struct gvnc_pixel_format *);
+};
+
+struct gvnc_pixel_format
+{
+	guint8 bits_per_pixel;
+	guint8 depth;
+	guint16 byte_order;
+	guint8 true_color_flag;
+	guint16 red_max;
+	guint16 green_max;
+	guint16 blue_max;
+	guint8 red_shift;
+	guint8 green_shift;
+	guint8 blue_shift;
+};
+
+struct gvnc_framebuffer
+{
+	guint8 *data;
+
+	int width;
+	int height;
+
+	int linesize;
+
+	guint16 byte_order;
+	int depth;
+	int bpp;
+
+	int red_mask;
+	int green_mask;
+	int blue_mask;
+
+	int red_shift;
+	int blue_shift;
+	int green_shift;
+};
+
+typedef enum {
+	GVNC_ENCODING_RAW = 0,
+	GVNC_ENCODING_COPY_RECT = 1,
+	GVNC_ENCODING_RRE = 2,
+	GVNC_ENCODING_CORRE = 4,
+	GVNC_ENCODING_HEXTILE = 5,
+	GVNC_ENCODING_TIGHT = 7,
+	GVNC_ENCODING_ZRLE = 16,
+
+	/* Tight JPEG quality levels */
+	GVNC_ENCODING_TIGHT_JPEG0 = -32,
+	GVNC_ENCODING_TIGHT_JPEG1 = -31,
+	GVNC_ENCODING_TIGHT_JPEG2 = -30,
+	GVNC_ENCODING_TIGHT_JPEG3 = -29,
+	GVNC_ENCODING_TIGHT_JPEG4 = -28,
+	GVNC_ENCODING_TIGHT_JPEG5 = -27,
+	GVNC_ENCODING_TIGHT_JPEG6 = -26,
+	GVNC_ENCODING_TIGHT_JPEG7 = -25,
+	GVNC_ENCODING_TIGHT_JPEG8 = -24,
+	GVNC_ENCODING_TIGHT_JPEG9 = -23,
+
+	/* Pseudo encodings */
+	GVNC_ENCODING_DESKTOP_RESIZE = -223,
+        GVNC_ENCODING_WMVi = 0x574D5669,
+
+	GVNC_ENCODING_CURSOR_POS = -232,
+	GVNC_ENCODING_RICH_CURSOR = -239,
+	GVNC_ENCODING_XCURSOR = -240,
+
+	GVNC_ENCODING_POINTER_CHANGE = -257,
+	GVNC_ENCODING_EXT_KEY_EVENT = -258,
+} gvnc_encoding;
+
+typedef enum {
+	GVNC_AUTH_INVALID = 0,
+	GVNC_AUTH_NONE = 1,
+	GVNC_AUTH_VNC = 2,
+	GVNC_AUTH_RA2 = 5,
+	GVNC_AUTH_RA2NE = 6,
+	GVNC_AUTH_TIGHT = 16,
+	GVNC_AUTH_ULTRA = 17,
+	GVNC_AUTH_TLS = 18,  /* Used by VINO */
+	GVNC_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */
+ 	GVNC_AUTH_SASL = 20, /* SASL type used by VINO and QEMU */
+	GVNC_AUTH_MSLOGON = 0xfffffffa, /* Used by UltraVNC */
+} gvnc_auth;
+
+typedef enum {
+	GVNC_AUTH_VENCRYPT_PLAIN = 256,
+	GVNC_AUTH_VENCRYPT_TLSNONE = 257,
+	GVNC_AUTH_VENCRYPT_TLSVNC = 258,
+	GVNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+	GVNC_AUTH_VENCRYPT_X509NONE = 260,
+	GVNC_AUTH_VENCRYPT_X509VNC = 261,
+	GVNC_AUTH_VENCRYPT_X509PLAIN = 262,
+	GVNC_AUTH_VENCRYPT_X509SASL = 263,
+	GVNC_AUTH_VENCRYPT_TLSSASL = 264,
+} gvnc_auth_vencrypt;
+
+
+struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data);
+void gvnc_free(struct gvnc *gvnc);
+
+void gvnc_close(struct gvnc *gvnc);
+void gvnc_shutdown(struct gvnc *gvnc);
+
+gboolean gvnc_open_fd(struct gvnc *gvnc, int fd);
+gboolean gvnc_open_host(struct gvnc *gvnc, const char *host, const char *port);
+gboolean gvnc_is_open(struct gvnc *gvnc);
+
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type);
+gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type);
+
+gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password);
+gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username);
+gboolean gvnc_set_credential_x509_cacert(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_cacrl(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_key(struct gvnc *gvnc, const char *file);
+gboolean gvnc_set_credential_x509_cert(struct gvnc *gvnc, const char *file);
+
+gboolean gvnc_wants_credential_password(struct gvnc *gvnc);
+gboolean gvnc_wants_credential_username(struct gvnc *gvnc);
+gboolean gvnc_wants_credential_x509(struct gvnc *gvnc);
+
+gboolean gvnc_initialize(struct gvnc *gvnc, gboolean shared_flag);
+gboolean gvnc_is_initialized(struct gvnc *gvnc);
+
+gboolean gvnc_server_message(struct gvnc *gvnc);
+
+gboolean gvnc_client_cut_text(struct gvnc *gvnc,
+			      const void *data, size_t length);
+
+gboolean gvnc_pointer_event(struct gvnc *gvnc, guint8 button_mask,
+			    guint16 x, guint16 y);
+
+gboolean gvnc_key_event(struct gvnc *gvnc, guint8 down_flag,
+			guint32 key, guint16 scancode);
+
+gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
+					 guint8 incremental,
+					 guint16 x, guint16 y,
+					 guint16 width, guint16 height);
+
+gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, gint32 *encoding);
+
+gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
+			       const struct gvnc_pixel_format *fmt);
+
+gboolean gvnc_has_error(struct gvnc *gvnc);
+
+gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb);
+
+gboolean gvnc_shared_memory_enabled(struct gvnc *gvnc);
+
+const char *gvnc_get_name(struct gvnc *gvnc);
+int gvnc_get_width(struct gvnc *gvnc);
+int gvnc_get_height(struct gvnc *gvnc);
+
+/* HACK this is temporary */
+gboolean gvnc_using_raw_keycodes(struct gvnc *gvnc);
+
+#endif
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 46d3c0f..82cbfe5 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -23,7 +23,7 @@
 
 #include "vncdisplay.h"
 #include "coroutine.h"
-#include "gvnc.h"
+#include "vncconnection.h"
 #include "utils.h"
 #include "vncmarshal.h"
 #include "config.h"
-- 
1.6.5.2



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]