diff --git a/.gitignore b/.gitignore
index 27a84a4..a9c89fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2
+SOURCES/tigervnc-1.3.1.tar.gz
diff --git a/.tigervnc.metadata b/.tigervnc.metadata
index afeeeab..a4c986b 100644
--- a/.tigervnc.metadata
+++ b/.tigervnc.metadata
@@ -1 +1 @@
-581d9ec01dee4602c554ef1d2ae8434d9ea53774 SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2
+2253b5460bd5a450b10b1c42eb97b4215c3efd99 SOURCES/tigervnc-1.3.1.tar.gz
diff --git a/SOURCES/tigervnc-1.3.0-xserver-1.15.patch b/SOURCES/tigervnc-1.3.0-xserver-1.15.patch
deleted file mode 100644
index d070a70..0000000
--- a/SOURCES/tigervnc-1.3.0-xserver-1.15.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff -up tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h
---- tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx	2013-07-01 08:41:24.000000000 -0400
-+++ tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h	2013-11-07 11:39:49.749992669 -0500
-@@ -44,8 +44,10 @@
- #define XORG 113
- #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (14 * 100000) + (99 * 1000))
- #define XORG 114
-+#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (15 * 100000) + (99 * 1000))
-+#define XORG 115
- #else
--#error "X.Org newer than 1.14 is not supported"
-+#error "X.Org newer than 1.15 is not supported"
- #endif
- 
- #endif
diff --git a/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch b/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch
new file mode 100644
index 0000000..9267c8c
--- /dev/null
+++ b/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch
@@ -0,0 +1,74 @@
+diff --git a/unix/x0vncserver/Image.cxx b/unix/x0vncserver/Image.cxx
+index f998c6a..d113f17 100644
+--- a/unix/x0vncserver/Image.cxx
++++ b/unix/x0vncserver/Image.cxx
+@@ -80,6 +80,14 @@ void Image::Init(int width, int height)
+   xim = XCreateImage(dpy, vis, DefaultDepth(dpy, DefaultScreen(dpy)),
+                      ZPixmap, 0, 0, width, height, BitmapPad(dpy), 0);
+
++  if (xim->bytes_per_line <= 0 ||
++      xim->height <= 0 ||
++      xim->height >= INT_MAX / xim->bytes_per_line) {
++    vlog.error("Invalid display size");
++    XDestroyImage(xim);
++    exit(1);
++  }
++
+   xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
+   if (xim->data == NULL) {
+     vlog.error("malloc() failed");
+@@ -256,6 +264,17 @@ void ShmImage::Init(int width, int height, const XVisualInfo *vinfo)
+     return;
+   }
+
++  if (xim->bytes_per_line <= 0 ||
++      xim->height <= 0 ||
++      xim->height >= INT_MAX / xim->bytes_per_line) {
++    vlog.error("Invalid display size");
++    XDestroyImage(xim);
++    xim = NULL;
++    delete shminfo;
++    shminfo = NULL;
++    return;
++  }
++
+   shminfo->shmid = shmget(IPC_PRIVATE,
+                           xim->bytes_per_line * xim->height,
+                           IPC_CREAT|0777);
+diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx
+index bd0610c..2c493c9 100644
+--- a/vncviewer/X11PixelBuffer.cxx
++++ b/vncviewer/X11PixelBuffer.cxx
+@@ -105,6 +105,15 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) :
+                        ZPixmap, 0, 0, width, height, BitmapPad(fl_display), 0);
+     assert(xim);
+
++    if (xim->bytes_per_line <= 0 ||
++	xim->height <= 0 ||
++	xim->height >= INT_MAX / xim->bytes_per_line) {
++      if (xim)
++	XDestroyImage(xim);
++      xim = NULL;
++      throw rfb::Exception("Invalid display size");
++    }
++
+     xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
+     assert(xim->data);
+   }
+@@ -169,6 +178,16 @@ int PlatformPixelBuffer::setupShm()
+   if (!xim)
+     goto free_shminfo;
+
++  if (xim->bytes_per_line <= 0 ||
++      xim->height <= 0 ||
++      xim->height >= INT_MAX / xim->bytes_per_line) {
++    XDestroyImage(xim);
++    xim = NULL;
++    delete shminfo;
++    shminfo = NULL;
++    throw rfb::Exception("Invalid display size");
++  }
++
+   shminfo->shmid = shmget(IPC_PRIVATE,
+                           xim->bytes_per_line * xim->height,
+                           IPC_CREAT|0777);
diff --git a/SOURCES/tigervnc-1.3.1-xserver-1.16.patch b/SOURCES/tigervnc-1.3.1-xserver-1.16.patch
new file mode 100644
index 0000000..eb6a9c8
--- /dev/null
+++ b/SOURCES/tigervnc-1.3.1-xserver-1.16.patch
@@ -0,0 +1,286 @@
+diff -up tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h
+--- tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx	2013-07-01 08:41:24.000000000 -0400
++++ tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h	2013-11-07 11:39:49.749992669 -0500
+@@ -44,8 +44,12 @@
+ #define XORG 113
+ #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (14 * 100000) + (99 * 1000))
+ #define XORG 114
++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (15 * 100000) + (99 * 1000))
++#define XORG 115
++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (16 * 100000) + (99 * 1000))
++#define XORG 116
+ #else
+-#error "X.Org newer than 1.14 is not supported"
++#error "X.Org newer than 1.16 is not supported"
+ #endif
+ 
+ #endif
+
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc.116	2013-05-30 16:53:40.000000000 +0200
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc	2014-04-28 16:55:02.591440218 +0200
+@@ -262,7 +262,7 @@ static int pointerProc(DeviceIntPtr pDev
+ 	return Success;
+ }
+ 
+-static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl,
++static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl,
+ 			 int class_)
+ {
+ 	if (percent > 0)
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc.116	2014-04-28 16:55:02.530441812 +0200
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc	2014-04-28 16:55:02.592440192 +0200
+@@ -48,7 +48,7 @@ extern "C" {
+ #define public c_public
+ #define class c_class
+ 
+-extern char *display;
++extern const char *display;
+ 
+ #include "colormapst.h"
+ #ifdef RANDR
+@@ -174,7 +174,7 @@ void XserverDesktop::serverReset(ScreenP
+ {
+   pScreen = pScreen_;
+   int i;
+-  pointer retval;
++  void * retval;
+ 
+ #if XORG >= 17
+ #define dixLookupResource dixLookupResourceByType
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc.116	2014-04-28 16:55:02.524441969 +0200
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc	2014-04-28 16:55:02.592440192 +0200
+@@ -65,18 +65,18 @@ extern "C" {
+ 
+   extern void vncExtensionInit();
+   static void vncResetProc(ExtensionEntry* extEntry);
+-  static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask);
+-  static void vncWakeupHandler(pointer data, int nfds, pointer readmask);
++  static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
++  static void vncWakeupHandler(void * data, int nfds, void * readmask);
+   void vncWriteBlockHandler(fd_set *fds);
+   void vncWriteWakeupHandler(int nfds, fd_set *fds);
+-  static void vncClientStateChange(CallbackListPtr*, pointer, pointer);
++  static void vncClientStateChange(CallbackListPtr*, void *, void *);
+   static void SendSelectionChangeEvent(Atom selection);
+   static int ProcVncExtDispatch(ClientPtr client);
+   static int SProcVncExtDispatch(ClientPtr client);
+-  static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data,
+-				   pointer args);
++  static void vncSelectionCallback(CallbackListPtr *callbacks, void * data,
++				   void * args);
+ 
+-  extern char *display;
++  extern const char *display;
+   extern char *listenaddr;
+ }
+ 
+@@ -284,7 +284,7 @@ static void vncResetProc(ExtensionEntry*
+ {
+ }
+ 
+-static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args)
++static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args)
+ {
+   SelectionInfoRec *info = (SelectionInfoRec *) args;
+   Selection *selection = info->selection;
+@@ -301,7 +301,7 @@ static void vncWriteWakeupHandlerFallbac
+ // selections have changed, and if so, notify any interested X clients.
+ //
+ 
+-static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask)
++static void vncBlockHandler(void * data, OSTimePtr timeout, void * readmask)
+ {
+   fd_set* fds = (fd_set*)readmask;
+ 
+@@ -312,7 +312,7 @@ static void vncBlockHandler(pointer data
+       desktop[scr]->blockHandler(fds, timeout);
+ }
+ 
+-static void vncWakeupHandler(pointer data, int nfds, pointer readmask)
++static void vncWakeupHandler(void * data, int nfds, void * readmask)
+ {
+   fd_set* fds = (fd_set*)readmask;
+ 
+@@ -402,7 +402,7 @@ static void vncWriteWakeupHandlerFallbac
+   vncWriteWakeupHandler(ret, &fallbackFds);
+ }
+ 
+-static void vncClientStateChange(CallbackListPtr*, pointer, pointer p)
++static void vncClientStateChange(CallbackListPtr*, void *, void * p)
+ {
+   ClientPtr client = ((NewClientInfoRec*)p)->client;
+   if (client->clientState == ClientStateGone) {
+@@ -468,7 +468,7 @@ void vncClientCutText(const char* str, i
+ 
+ 
+ static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
+-                                        CARD32 now, pointer arg)
++                                        CARD32 now, void * arg)
+ {
+   if (queryConnectTimeout)
+     queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc.116	2013-05-22 14:57:16.000000000 +0200
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc	2014-04-28 16:55:02.593440166 +0200
+@@ -91,8 +91,8 @@ typedef struct {
+ } vncHooksScreenRec, *vncHooksScreenPtr;
+ 
+ typedef struct {
+-    GCFuncs *wrappedFuncs;
+-    GCOps *wrappedOps;
++    const GCFuncs *wrappedFuncs;
++    const GCOps *wrappedOps;
+ } vncHooksGCRec, *vncHooksGCPtr;
+ 
+ #if XORG == 15
+@@ -141,11 +141,11 @@ static Bool vncHooksDisplayCursor(
+ #endif
+ 				  ScreenPtr pScreen, CursorPtr cursor);
+ #if XORG < 112
+-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+-                                 pointer pReadmask);
++static void vncHooksBlockHandler(int i, void * blockData, void * pTimeout,
++                                 void * pReadmask);
+ #else
+-static void vncHooksBlockHandler(ScreenPtr pScreen, pointer pTimeout,
+-                                 pointer pReadmask);
++static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
++                                 void * pReadmask);
+ #endif
+ #ifdef RENDER
+ static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 
+@@ -174,7 +174,7 @@ static void vncHooksValidateGC(GCPtr pGC
+ static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
+ static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
+ static void vncHooksDestroyGC(GCPtr pGC);
+-static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects);
++static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue,int nrects);
+ static void vncHooksDestroyClip(GCPtr pGC);
+ static void vncHooksCopyClip(GCPtr dst, GCPtr src);
+ 
+@@ -226,10 +226,10 @@ static void vncHooksImageText16(Drawable
+                                 int count, unsigned short *chars);
+ static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                   int y, unsigned int nglyph,
+-                                  CharInfoPtr *ppci, pointer pglyphBase);
++                                  CharInfoPtr *ppci, void * pglyphBase);
+ static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                  int y, unsigned int nglyph,
+-                                 CharInfoPtr *ppci, pointer pglyphBase);
++                                 CharInfoPtr *ppci, void * pglyphBase);
+ static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
+                                DrawablePtr pDrawable, int w, int h, int x,
+                                int y);
+@@ -575,11 +575,11 @@ static Bool vncHooksDisplayCursor(
+ // these are just drawing the cursor.
+ 
+ #if XORG < 112
+-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+-                                 pointer pReadmask)
++static void vncHooksBlockHandler(int i, void * blockData, void * pTimeout,
++                                 void * pReadmask)
+ #else
+-static void vncHooksBlockHandler(ScreenPtr pScreen_, pointer pTimeout,
+-                                 pointer pReadmask)
++static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
++                                 void * pReadmask)
+ #endif
+ {
+ #if XORG < 112
+@@ -914,7 +914,7 @@ static void vncHooksDestroyGC(GCPtr pGC)
+   GCFuncUnwrapper u(pGC);
+   (*pGC->funcs->DestroyGC) (pGC);
+ }
+-static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects)
++static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects)
+ {
+   GCFuncUnwrapper u(pGC);
+   (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
+@@ -954,7 +954,7 @@ public:
+   }
+   GCPtr pGC;
+   vncHooksGCPtr vncHooksGC;
+-  GCFuncs* oldFuncs;
++  const GCFuncs* oldFuncs;
+   ScreenPtr pScreen;
+ };
+ 
+@@ -1793,7 +1793,7 @@ static void vncHooksImageText16(Drawable
+ 
+ static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                   int y, unsigned int nglyph,
+-                                  CharInfoPtr *ppci, pointer pglyphBase)
++                                  CharInfoPtr *ppci, void * pglyphBase)
+ {
+   GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
+ 
+@@ -1819,7 +1819,7 @@ static void vncHooksImageGlyphBlt(Drawab
+ 
+ static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                  int y, unsigned int nglyph,
+-                                 CharInfoPtr *ppci, pointer pglyphBase)
++                                 CharInfoPtr *ppci, void * pglyphBase)
+ {
+   GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
+ 
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc.116	2013-03-14 18:52:53.000000000 +0100
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc	2014-04-28 16:55:02.593440166 +0200
+@@ -81,11 +81,11 @@ static XF86ModuleVersionInfo vncVersRec
+ 
+ _X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL };
+ 
+-static pointer
+-vncSetup(pointer module, pointer opts, int *errmaj, int *errmin) {
+-    LoadExtension(&vncExt, FALSE);
++static void *
++vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
++    LoadExtensionList(&vncExt, 1, FALSE);
+     /* Need a non-NULL return value to indicate success */
+-    return (pointer)1;
++    return (void *)1;
+ }
+ 
+ static void vncExtensionInitWithParams(INITARGS)
+diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc
+--- tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc.116	2014-03-19 13:11:09.000000000 +0100
++++ tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc	2014-04-28 16:53:12.580314921 +0200
+@@ -103,7 +103,7 @@ extern "C" {
+                        "See http://www.tigervnc.org for information on TigerVNC.\n")
+ 
+ 
+-extern char *display;
++extern const char *display;
+ extern int monitorResolution;
+ 
+ #define VFB_DEFAULT_WIDTH  1024
+@@ -762,7 +762,7 @@ vfbUninstallColormap(ColormapPtr pmap)
+ 	    curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+ 						   RT_COLORMAP);
+ #else
+-	    dixLookupResourceByType((pointer *) &curpmap, pmap->pScreen->defColormap,
++	    dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
+ 				    RT_COLORMAP, serverClient, DixUnknownAccess);
+ #endif
+ 	    (*pmap->pScreen->InstallColormap)(curpmap);
+@@ -1597,7 +1597,7 @@ vfbScreenInit(ScreenPtr pScreen, int arg
+ } /* end vfbScreenInit */
+ 
+ 
+-static void vfbClientStateChange(CallbackListPtr*, pointer, pointer) {
++static void vfbClientStateChange(CallbackListPtr*, void *, void *) {
+   dispatchException &= ~DE_RESET;
+ }
+  
+@@ -1625,7 +1625,7 @@ InitOutput(ScreenInfo *screenInfo, int a
+ #if XORG >= 113
+ #ifdef GLXEXT
+     if (serverGeneration == 1)
+-        LoadExtension(&glxExt, TRUE);
++        LoadExtensionList(&glxExt, 1, TRUE);
+ #endif
+ #endif
+ 
diff --git a/SOURCES/tigervnc-1.3.1-xserver-1.17.patch b/SOURCES/tigervnc-1.3.1-xserver-1.17.patch
new file mode 100644
index 0000000..77f813b
--- /dev/null
+++ b/SOURCES/tigervnc-1.3.1-xserver-1.17.patch
@@ -0,0 +1,44 @@
+diff -up tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h.xserver117 tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h
+--- tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h.xserver117	2015-01-23 23:37:23.000000000 +0000
++++ tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h	2015-02-13 17:35:29.847294663 +0000
+@@ -48,8 +48,10 @@
+ #define XORG 115
+ #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (16 * 100000) + (99 * 1000))
+ #define XORG 116
++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (17 * 100000) + (99 * 1000))
++#define XORG 117
+ #else
+-#error "X.Org newer than 1.16 is not supported"
++#error "X.Org newer than 1.17 is not supported"
+ #endif
+ 
+ #endif
+diff -up tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc.xserver117 tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc
+--- tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc.xserver117	2015-01-23 23:37:23.000000000 +0000
++++ tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc	2015-02-13 17:35:27.963265774 +0000
+@@ -717,9 +717,9 @@ vfbInstallColormap(ColormapPtr pmap)
+ 	entries = pmap->pVisual->ColormapEntries;
+ 	pVisual = pmap->pVisual;
+ 
+-	ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
+-	prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
+-	defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
++	ppix = (Pixel *)calloc(entries, sizeof(Pixel));
++	prgb = (xrgb *)calloc(entries, sizeof(xrgb));
++	defs = (xColorItem *)calloc(entries, sizeof(xColorItem));
+ 
+ 	for (i = 0; i < entries; i++)  ppix[i] = i;
+ 	/* XXX truecolor */
+@@ -738,9 +738,9 @@ vfbInstallColormap(ColormapPtr pmap)
+ 	}
+ 	(*pmap->pScreen->StoreColors)(pmap, entries, defs);
+ 	
+-	xfree(ppix);
+-	xfree(prgb);
+-	xfree(defs);
++	free(ppix);
++	free(prgb);
++	free(defs);
+     }
+ }
+ 
diff --git a/SOURCES/tigervnc-CVE-2014-0011.patch b/SOURCES/tigervnc-CVE-2014-0011.patch
deleted file mode 100644
index 0075720..0000000
--- a/SOURCES/tigervnc-CVE-2014-0011.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-diff -up tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011 tigervnc-1.3.0/common/CMakeLists.txt
---- tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011	2013-07-01 13:42:01.000000000 +0100
-+++ tigervnc-1.3.0/common/CMakeLists.txt	2014-02-04 16:59:10.840037314 +0000
-@@ -23,3 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_S
-     set_target_properties(zlib PROPERTIES COMPILE_FLAGS -fPIC)
-   endif()
- endif()
-+
-+# Turn asserts on.
-+set_target_properties(rdr rfb PROPERTIES COMPILE_FLAGS -UNDEBUG)
-diff -up tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011 tigervnc-1.3.0/common/rfb/zrleDecode.h
---- tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011	2013-07-01 13:41:59.000000000 +0100
-+++ tigervnc-1.3.0/common/rfb/zrleDecode.h	2014-02-04 16:17:00.881565540 +0000
-@@ -25,9 +25,10 @@
- // FILL_RECT          - fill a rectangle with a single colour
- // IMAGE_RECT         - draw a rectangle of pixel data from a buffer
- 
-+#include <stdio.h>
- #include <rdr/InStream.h>
- #include <rdr/ZlibInStream.h>
--#include <assert.h>
-+#include <rfb/Exception.h>
- 
- namespace rfb {
- 
-@@ -143,7 +144,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In
-               len += b;
-             } while (b == 255);
- 
--            assert(len <= end - ptr);
-+	    if (end - ptr < len) {
-+	      fprintf (stderr, "ZRLE decode error\n");
-+	      throw Exception ("ZRLE decode error");
-+	    }
- 
- #ifdef FAVOUR_FILL_RECT
-             int i = ptr - buf;
-@@ -193,7 +197,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In
-                 len += b;
-               } while (b == 255);
- 
--              assert(len <= end - ptr);
-+	      if (end - ptr < len) {
-+		fprintf (stderr, "ZRLE decode error\n");
-+		throw Exception ("ZRLE decode error");
-+	      }
-             }
- 
-             index &= 127;
diff --git a/SOURCES/tigervnc-CVE-2014-8241.patch b/SOURCES/tigervnc-CVE-2014-8241.patch
new file mode 100644
index 0000000..56216cc
--- /dev/null
+++ b/SOURCES/tigervnc-CVE-2014-8241.patch
@@ -0,0 +1,101 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 0e325e2..1d4e1bf 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -67,6 +67,14 @@ add_definitions(-D__BUILD__="${BUILD}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -UNDEBUG")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -UNDEBUG")
+
++# We want to keep our asserts even in release builds so remove NDEBUG
++set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -UNDEBUG")
++set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG")
++set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -UNDEBUG")
++set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -UNDEBUG")
++set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG")
++set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG")
++
+ if(NOT DEFINED BUILD_WINVNC)
+   set(BUILD_WINVNC 1)
+ endif()
+diff --git a/common/Xregion/Region.c b/common/Xregion/Region.c
+index 604ecde..4bb52ea 100644
+--- a/common/Xregion/Region.c
++++ b/common/Xregion/Region.c
+@@ -1083,6 +1083,8 @@ miRegionOp(newReg, reg1, reg2, overlapFunc,  nonOverlap1Func, nonOverlap2Func)
+ 	    newReg->size = 1;
+ 	    Xfree((char *) newReg->rects);
+ 	    newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec));
++	    if (! newReg->rects)
++	      newReg->size = 0;
+ 	}
+     }
+     Xfree ((char *) oldRects);
+diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
+index ff5532b..c2e6d3c 100644
+--- a/unix/vncconfig/vncExt.c
++++ b/unix/vncconfig/vncExt.c
+@@ -109,6 +109,10 @@ Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len)
+   if (rep.success) {
+     *len = rep.valueLen;
+     *value = (char*) Xmalloc (*len+1);
++    if (!*value) {
++      _XEatData(dpy, (*len+1)&~1);
++      return False;
++    }
+     _XReadPad(dpy, *value, *len);
+     (*value)[*len] = 0;
+   }
+@@ -141,6 +145,10 @@ char* XVncExtGetParamDesc(Display* dpy, const char* param)
+   }
+   if (rep.success) {
+     desc = (char*)Xmalloc(rep.descLen+1);
++    if (!*desc) {
++      _XEatData(dpy, (rep.descLen+1)&~1);
++      return False;
++    }
+     _XReadPad(dpy, desc, rep.descLen);
+     desc[rep.descLen] = 0;
+   }
+@@ -243,6 +251,10 @@ Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len)
+   SyncHandle();
+   *len = rep.textLen;
+   *str = (char*) Xmalloc (*len+1);
++  if (!*str) {
++    _XEatData(dpy, (*len+1)&~1);
++    return False;
++  }
+   _XReadPad(dpy, *str, *len);
+   (*str)[*len] = 0;
+   return True;
+@@ -312,9 +324,15 @@ Bool XVncExtGetQueryConnect(Display* dpy, char** addr, char** user,
+   SyncHandle();
+
+   *addr = Xmalloc(rep.addrLen+1);
++  *user = Xmalloc(rep.userLen+1);
++  if (!*addr || !*user) {
++    Xfree(*addr);
++    Xfree(*user);
++    _XEatData(dpy, (rep.addrLen+1)&~1 + (rep.userLen+1)&~1);
++    return False;
++  }
+   _XReadPad(dpy, *addr, rep.addrLen);
+   (*addr)[rep.addrLen] = 0;
+-  *user = Xmalloc(rep.userLen+1);
+   _XReadPad(dpy, *user, rep.userLen);
+   (*user)[rep.userLen] = 0;
+   *timeout = rep.timeout;
+diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
+index f70cc71..bffdfbe 100644
+--- a/unix/vncconfig/vncconfig.cxx
++++ b/unix/vncconfig/vncconfig.cxx
+@@ -215,6 +215,10 @@ public:
+       if (cutText)
+         XFree(cutText);
+       cutText = (char*)malloc(nitems); // assuming XFree() same as free()
++      if (!cutText) {
++        vlog.error("unable to allocate selection buffer");
++        return;
++      }
+       memcpy(cutText, data, nitems);
+       cutTextLen = nitems;
+       vlog.debug("sending %s selection as server cut text: '%.*s%s'",
diff --git a/SOURCES/tigervnc-check-return-value-from-xshmattach.patch b/SOURCES/tigervnc-check-return-value-from-xshmattach.patch
new file mode 100644
index 0000000..a3b011a
--- /dev/null
+++ b/SOURCES/tigervnc-check-return-value-from-xshmattach.patch
@@ -0,0 +1,17 @@
+diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx
+index 548591e..bd0610c 100644
+--- a/vncviewer/X11PixelBuffer.cxx
++++ b/vncviewer/X11PixelBuffer.cxx
+@@ -186,7 +186,11 @@ int PlatformPixelBuffer::setupShm()
+   caughtError = false;
+   old_handler = XSetErrorHandler(XShmAttachErrorHandler);
+ 
+-  XShmAttach(fl_display, shminfo);
++  if (!XShmAttach(fl_display, shminfo)) {
++    XSetErrorHandler(old_handler);
++    goto free_shmaddr;
++  }
++
+   XSync(fl_display, False);
+ 
+   XSetErrorHandler(old_handler);
diff --git a/SOURCES/tigervnc-input.patch b/SOURCES/tigervnc-input.patch
deleted file mode 100644
index e1e7b0b..0000000
--- a/SOURCES/tigervnc-input.patch
+++ /dev/null
@@ -1,2569 +0,0 @@
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input	2012-08-29 09:56:37.000000000 +0100
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc	2014-01-17 16:01:13.140109450 +0000
-@@ -1,5 +1,6 @@
- /* Copyright (C) 2009 TightVNC Team
-  * Copyright (C) 2009 Red Hat, Inc.
-+ * Copyright 2013 Pierre Ossman for Cendio AB
-  *
-  * This is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -34,16 +35,6 @@ extern "C" {
- #include "inpututils.h"
- #endif
- #include "mi.h"
--#ifndef XKB_IN_SERVER
--#define XKB_IN_SERVER
--#endif
--#ifdef XKB
--/*
-- * This include is needed to use XkbConvertCase instead of XConvertCase even if
-- * we don't use XKB extension.
-- */
--#include <xkbsrv.h>
--#endif
- #if XORG >= 16
- #include "exevents.h"
- #endif
-@@ -58,6 +49,7 @@ CopyKeyClass(DeviceIntPtr device, Device
- extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
- #endif
- #include <X11/keysym.h>
-+#include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #undef public
- #undef class
-@@ -72,12 +64,9 @@ using namespace rfb;
- 
- static LogWriter vlog("Input");
- 
--#define BUTTONS 7
--static int pointerProc(DeviceIntPtr pDevice, int onoff);
-+rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true);
- 
--static int keyboardProc(DeviceIntPtr pDevice, int onoff);
--static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col);
--static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col);
-+#define BUTTONS 7
- 
- /* Event queue is shared between all devices. */
- #if XORG == 15
-@@ -128,26 +117,16 @@ static void enqueueEvents(DeviceIntPtr d
- #endif /* XORG < 111 */
- 
- InputDevice::InputDevice(rfb::VNCServerST *_server)
--	: server(_server), oldButtonMask(0)
-+	: server(_server), initialized(false), oldButtonMask(0)
- {
--#if XORG < 17
--	pointerDev = AddInputDevice(
--#if XORG >= 16
--				    serverClient,
--#endif
--				    pointerProc, TRUE);
--	RegisterPointerDevice(pointerDev);
-+	int i;
- 
--	keyboardDev = AddInputDevice(
--#if XORG >= 16
--				     serverClient,
--#endif
--				     keyboardProc, TRUE);
--	RegisterKeyboardDevice(keyboardDev);
--#endif
- #if XORG < 111
- 	initEventq();
- #endif
-+
-+	for (i = 0;i < 256;i++)
-+		pressedKeys[i] = NoSymbol;
- }
- 
- void InputDevice::PointerButtonAction(int buttonMask)
-@@ -160,8 +139,6 @@ void InputDevice::PointerButtonAction(in
- 	ValuatorMask mask;
- #endif
- 
--	initInputDevice();
--
- 	for (i = 0; i < BUTTONS; i++) {
- 		if ((buttonMask ^ oldButtonMask) & (1 << i)) {
- 			int action = (buttonMask & (1<<i)) ?
-@@ -199,8 +176,6 @@ void InputDevice::PointerMove(const rfb:
- 	if (pos.equals(cursorPos))
- 		return;
- 
--	initInputDevice();
--
- 	valuators[0] = pos.x;
- 	valuators[1] = pos.y;
- #if XORG < 110
-@@ -287,16 +262,78 @@ static int pointerProc(DeviceIntPtr pDev
- 	return Success;
- }
- 
--void InputDevice::initInputDevice(void)
-+static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl,
-+			 int class_)
- {
-+	if (percent > 0)
-+		vncBell();
-+}
-+
-+extern void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
-+
-+static int keyboardProc(DeviceIntPtr pDevice, int onoff)
-+{
-+#if XORG < 17
-+	KeySymsRec keySyms;
-+	CARD8 modMap[MAP_LENGTH];
-+#endif
-+	DevicePtr pDev = (DevicePtr)pDevice;
-+
-+	switch (onoff) {
-+	case DEVICE_INIT:
-+#if XORG < 17
-+		GetInitKeyboardMap(&keySyms, modMap);
-+#endif
-+		InitKeyboardDeviceStruct(
- #if XORG >= 17
--	int ret;
--	static int initialized = 0;
-+					 pDevice, NULL,
-+#else
-+					 pDev, &keySyms, modMap,
-+#endif
-+					 keyboardBell, (KbdCtrlProcPtr)NoopDDA);
-+		break;
-+	case DEVICE_ON:
-+		pDev->on = TRUE;
-+		break;
-+	case DEVICE_OFF:
-+		pDev->on = FALSE;
-+		break;
-+	}
- 
--	if (initialized != 0)
-+	return Success;
-+}
-+
-+void InputDevice::InitInputDevice(void)
-+{
-+	if (initialized)
- 		return;
- 
--	initialized = 1;
-+	initialized = true;
-+
-+#if XORG < 17
-+	pointerDev = AddInputDevice(
-+#if XORG >= 16
-+				    serverClient,
-+#endif
-+				    pointerProc, TRUE);
-+	RegisterPointerDevice(pointerDev);
-+
-+	keyboardDev = AddInputDevice(
-+#if XORG >= 16
-+				     serverClient,
-+#endif
-+				     keyboardProc, TRUE);
-+	RegisterKeyboardDevice(keyboardDev);
-+
-+	if (ActivateDevice(pointerDev) != Success ||
-+	    ActivateDevice(keyboardDev) != Success)
-+		FatalError("Failed to activate TigerVNC devices\n");
-+
-+	if (!EnableDevice(pointerDev) ||
-+	    !EnableDevice(keyboardDev))
-+		FatalError("Failed to enable TigerVNC devices\n");
-+#else /* < 17 */
-+	int ret;
- 
- 	ret = AllocDevicePair(serverClient, "TigerVNC", &pointerDev,
- 			      &keyboardDev, pointerProc, keyboardProc,
-@@ -312,7 +349,9 @@ void InputDevice::initInputDevice(void)
- 	if (!EnableDevice(pointerDev, TRUE) ||
- 	    !EnableDevice(keyboardDev, TRUE))
- 		FatalError("Failed to activate TigerVNC devices\n");
--#endif
-+#endif /* 17 */
-+
-+	PrepareInputDevices();
- }
- 
- static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg)
-@@ -334,143 +373,6 @@ static inline void pressKey(DeviceIntPtr
- #endif
- }
- 
--#define IS_PRESSED(keyc, keycode) \
--	((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
--
--/*
-- * ModifierState is a class which helps simplify generating a "fake" press or
-- * release of shift, ctrl, alt, etc.  An instance of the class is created for
-- * every modifier which may need to be pressed or released.  Then either
-- * press() or release() may be called to make sure that the corresponding keys
-- * are in the right state.  The destructor of the class automatically reverts
-- * to the previous state.  Each modifier may have multiple keys associated with
-- * it, so in the case of a fake release, this may involve releasing more than
-- * one key.
-- */
--
--class ModifierState {
--public:
--	ModifierState(DeviceIntPtr _dev, int _modIndex)
--		: modIndex(_modIndex), nKeys(0), keys(0), pressed(false),
--		  dev(_dev) {}
--
--	~ModifierState()
--	{
--		for (int i = 0; i < nKeys; i++)
--			pressKey(dev, keys[i], !pressed, "fake keycode");
--		delete [] keys;
--	}
--
--	void press()
--	{
--		int state, maxKeysPerMod, keycode;
--#if XORG >= 17
--		KeyCode *modmap = NULL;
--#if XORG >= 111
--		state = XkbStateFieldFromRec(&dev->master->key->xkbInfo->state);
--#else /* XORG >= 111 */
--		state = XkbStateFieldFromRec(&dev->u.master->key->xkbInfo->state);
--#endif /* XORG >= 111 */
--#else
--		KeyClassPtr keyc = dev->key;
--		state = keyc->state;
--#endif
--		if ((state & (1 << modIndex)) != 0)
--			return;
--
--#if XORG >= 17
--		if (generate_modkeymap(serverClient, dev, &modmap,
--				       &maxKeysPerMod) != Success) {
--			vlog.error("generate_modkeymap failed");
--			return;
--		}
--
--		if (maxKeysPerMod == 0) {
--			vlog.debug("Keyboard has no modifiers");
--			xfree(modmap);
--			return;
--		}
--
--		keycode = modmap[modIndex * maxKeysPerMod];
--		xfree(modmap);
--#else
--		maxKeysPerMod = keyc->maxKeysPerModifier;
--		keycode = keyc->modifierKeyMap[modIndex * maxKeysPerMod];
--#endif
--		tempKeyEvent(keycode, true, maxKeysPerMod);
--		pressed = true;
--	}
--
--	void release()
--	{
--		int state, maxKeysPerMod;
--		KeyClassPtr keyc;
--#if XORG >= 17
--		KeyCode *modmap = NULL;
--
--#if XORG >= 111
--		keyc = dev->master->key;
--#else /* XORG >= 111 */
--		keyc = dev->u.master->key;
--#endif /* XORG >= 111 */
--		state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
--#else
--		keyc = dev->key;
--		state = keyc->state;
--#endif
--		if ((state & (1 << modIndex)) == 0)
--			return;
--
--#if XORG >= 17
--		if (generate_modkeymap(serverClient, dev, &modmap,
--				       &maxKeysPerMod) != Success) {
--			vlog.error("generate_modkeymap failed");
--			return;
--		}
--
--		if (maxKeysPerMod == 0) {
--			vlog.debug("Keyboard has no modifiers");
--			xfree(modmap);
--			return;
--		}
--#else
--		maxKeysPerMod = keyc->maxKeysPerModifier;
--#endif
--
--		for (int k = 0; k < maxKeysPerMod; k++) {
--			int keycode;
--			int index = modIndex * maxKeysPerMod + k;
--#if XORG >= 17
--			keycode = modmap[index];
--#else
--			keycode = keyc->modifierKeyMap[index];
--#endif
--			if (keycode && IS_PRESSED(keyc, keycode))
--				tempKeyEvent(keycode, false, maxKeysPerMod);
--		}
--#if XORG >= 17
--		xfree(modmap);
--#endif
--	}
--
--private:
--	void tempKeyEvent(int keycode, bool down, int maxKeysPerMod)
--	{
--		if (keycode) {
--			if (!keys) keys = new int[maxKeysPerMod];
--			keys[nKeys++] = keycode;
--			pressKey(dev, keycode, down, "fake keycode");
--		}
--	}
--
--	int modIndex;
--	int nKeys;
--	int *keys;
--	bool pressed;
--	DeviceIntPtr dev;
--};
--
--
- /* altKeysym is a table of alternative keysyms which have the same meaning. */
- 
- static struct altKeysym_t {
-@@ -517,102 +419,48 @@ static struct altKeysym_t {
- 	{ XK_KP_7,		XK_7 },
- 	{ XK_KP_8,		XK_8 },
- 	{ XK_KP_9,		XK_9 },
-+	{ XK_ISO_Level3_Shift,	XK_Mode_switch },
- };
- 
- /*
-  * keyEvent() - work out the best keycode corresponding to the keysym sent by
-- * the viewer.  This is non-trivial because we can't assume much about the
-- * local keyboard layout.  We must also find out which column of the keyboard
-- * mapping the keysym is in, and alter the shift state appropriately.  Column 0
-- * means both shift and "mode_switch" (AltGr) must be released, column 1 means
-- * shift must be pressed and mode_switch released, column 2 means shift must be
-- * released and mode_switch pressed, and column 3 means both shift and
-- * mode_switch must be pressed.
-- *
-- * Magic, which dynamically adds keysym<->keycode mapping depends on X.Org
-- * version. Quick explanation of that "magic":
-- * 
-- * 1.5
-- * - has only one core keyboard so we have to keep core keyboard mapping
-- *   synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard()
-- *
-- * 1.6 (aka MPX - Multi pointer X)
-- * - multiple master devices (= core devices) exists, keep vncKeyboardDevice
-- *   synchronized with proper master device
-- */
--
--#if XORG >= 17
--#define FREE_MAPS \
--	do { \
--	        xfree(modmap); \
--	        xfree(keymap->map); \
--	        xfree(keymap); \
--	} while (0);
--#else
--#define FREE_MAPS
--#endif
--
--#if XORG >= 17
--/*
-- * Modifier keysyms must be handled differently. Instead of finding
-- * the right row and collumn in the keymap, directly press/release
-- * the keycode which is mapped as modifier with the same keysym.
-- *
-- * This will avoid issues when there are multiple modifier keysyms
-- * in the keymap but only some of them are mapped as modifiers in
-- * the modmap.
-- *
-- * Returns keycode of the modifier key.
-+ * the viewer. This is basically impossible in the general case, but we make
-+ * a best effort by assuming that all useful keysyms can be reached using
-+ * just the Shift and Level 3 (AltGr) modifiers. For core keyboards this is
-+ * basically always true, and should be true for most sane, western XKB
-+ * layouts.
-  */
--
--static inline int isModifier(KeySymsPtr keymap, KeyCode *modmap,
--			      int maxKeysPerMod, rdr::U32 keysym)
-+void InputDevice::keyEvent(rdr::U32 keysym, bool down)
- {
--	KeySym *map = keymap->map;
--	KeyCode minKeyCode = keymap->minKeyCode;
--	int mapWidth = keymap->mapWidth;
--	int i, j, k;
--
--	/* Find modifier index in the modmap */
--	for (i = 0; i < 8; i++) {
--		for (k = 0; k < maxKeysPerMod; k++) {
--			int index = i * maxKeysPerMod + k;
--			int keycode = modmap[index];
-+	int i;
-+	unsigned state, new_state;
-+	KeyCode keycode;
- 
--			if (keycode == 0)
--				continue;
-+	unsigned level_three_mask;
-+	KeyCode shift_press, level_three_press;
-+	std::list<KeyCode> shift_release, level_three_release;
- 
--			for (j = 0; j < mapWidth; j++) {
--				if (map[(keycode - minKeyCode) * mapWidth + j]
--				    == keysym) {
--					return keycode;
--				}
-+	/*
-+	 * Release events must match the press event, so look up what
-+	 * keycode we sent for the press.
-+	 */
-+	if (!down) {
-+		for (i = 0;i < 256;i++) {
-+			if (pressedKeys[i] == keysym) {
-+				pressedKeys[i] = NoSymbol;
-+				pressKey(keyboardDev, i, false, "keycode");
-+				mieqProcessInputEvents();
-+				return;
- 			}
- 		}
--	}
--
--	return -1; /* Not a modifier */
--}
--#endif
- 
--void InputDevice::keyEvent(rdr::U32 keysym, bool down)
--{
--#if XORG < 17
--	DeviceIntPtr master;
--#endif
--	KeyClassPtr keyc;
--	KeySymsPtr keymap = NULL;
--	KeySym *map = NULL;
--	KeyCode minKeyCode, maxKeyCode;
--	KeyCode *modmap = NULL;
--	int mapWidth;
--	unsigned int i;
--	int j, k, state, maxKeysPerMod;
--#if XORG >= 17
--	KeybdCtrl ctrl;
--#endif
--
--	initInputDevice();
-+		/*
-+		 * This can happen quite often as we ignore some
-+		 * key presses.
-+		 */
-+		vlog.debug("Unexpected release of keysym 0x%x", keysym);
-+		return;
-+	}
- 
- 	/* 
- 	 * Since we are checking the current state to determine if we need
-@@ -622,543 +470,214 @@ void InputDevice::keyEvent(rdr::U32 keys
- 	 */ 
- 	mieqProcessInputEvents();
- 
--	if (keysym == XK_Caps_Lock) {
--		vlog.debug("Ignoring caps lock");
--		return;
--	}
-+	state = getKeyboardState();
- 
--#if XORG >= 17
--#if XORG >= 111
--	keyc = keyboardDev->master->key;
--#else /* XORG >= 111 */
--	keyc = keyboardDev->u.master->key;
--#endif /* XORG >= 111 */
--
--	keymap = XkbGetCoreMap(keyboardDev);
--	if (!keymap) {
--		vlog.error("VNC keyboard device has no map");
--		return;
--	}
-+	keycode = keysymToKeycode(keysym, state, &new_state);
- 
--	if (generate_modkeymap(serverClient, keyboardDev, &modmap,
--	    		       &maxKeysPerMod) != Success) {
--		vlog.error("generate_modkeymap failed");
--		xfree(keymap->map);
--		xfree(keymap);
--		return;
--	}
--
--	if (maxKeysPerMod == 0)
--		vlog.debug("Keyboard has no modifiers");
--
--	state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
--#else
--	keyc = keyboardDev->key;
--	state = keyc->state;
--	maxKeysPerMod = keyc->maxKeysPerModifier;
--	keymap = &keyc->curKeySyms;
--	modmap = keyc->modifierKeyMap;
--#endif
--	map = keymap->map;
--	minKeyCode = keymap->minKeyCode;
--	maxKeyCode = keymap->maxKeyCode;
--	mapWidth = keymap->mapWidth;
--
--#if XORG >= 17
--	/*
--	 * No server-side key repeating, please. Some clients won't work well,
--	 * check https://bugzilla.redhat.com/show_bug.cgi?id=607866.
--	 */
--	ctrl = keyboardDev->kbdfeed->ctrl;
--	if (ctrl.autoRepeat != FALSE) {
--		ctrl.autoRepeat = FALSE;
--		XkbSetRepeatKeys(keyboardDev, -1, ctrl.autoRepeat);
--	}
--#endif
--
--	/* find which modifier Mode_switch is on. */
--	int modeSwitchMapIndex = 0;
--	for (i = 3; i < 8; i++) {
--		for (k = 0; k < maxKeysPerMod; k++) {
--			int index = i * maxKeysPerMod + k;
--			int keycode = modmap[index];
--
--			if (keycode == 0)
-+	/* Try some equivalent keysyms if we couldn't find a perfect match */
-+	if (keycode == 0) {
-+		for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
-+			KeySym altsym;
-+
-+			if (altKeysym[i].a == keysym)
-+				altsym = altKeysym[i].b;
-+			else if (altKeysym[i].b == keysym)
-+				altsym = altKeysym[i].a;
-+			else
- 				continue;
- 
--			for (j = 0; j < mapWidth; j++) {
--				if (map[(keycode - minKeyCode) * mapWidth + j]
--				    == XK_Mode_switch) {
--					modeSwitchMapIndex = i;
--					goto ModeSwitchFound;
--				}
--			}
-+			keycode = keysymToKeycode(altsym, state, &new_state);
-+			if (keycode != 0)
-+				break;
- 		}
- 	}
--ModeSwitchFound:
- 
--	int kc;
--	int col = 0;
-+	/* We don't have lock synchronisation... */
-+	if (isLockModifier(keycode, new_state)) {
-+		vlog.debug("Ignoring lock key (e.g. caps lock)");
-+		return;
-+	}
- 
--#if XORG >= 17
--	if ((kc = isModifier(keymap, modmap, maxKeysPerMod, keysym)) != -1) {
--		/*
--		 * It is a modifier key event.
--		 *
--		 * Don't do any auto-repeat because the X server will translate
--		 * each press into a release followed by a press.
--		 */
--		if (IS_PRESSED(keyc, kc) && down) {
--			FREE_MAPS;
-+	/* No matches. Will have to add a new entry... */
-+	if (keycode == 0) {
-+		keycode = addKeysym(keysym, state);
-+		if (keycode == 0) {
-+			vlog.error("Failure adding new keysym 0x%x", keysym);
- 			return;
- 		}
- 
--		goto press;
--	}
--#endif
--
--	if (maxKeysPerMod != 0) {
--		if ((state & (1 << ShiftMapIndex)) != 0)
--			col |= 1;
--		if (modeSwitchMapIndex != 0 &&
--		    ((state & (1 << modeSwitchMapIndex))) != 0)
--			col |= 2;
--	}
--
--	kc = KeysymToKeycode(keymap, keysym, &col);
-+		vlog.info("Added unknown keysym 0x%x to keycode %d",
-+			  keysym, keycode);
- 
--	/*
--	 * Sort out the "shifted Tab" mess.  If we are sent a shifted Tab,
--	 * generate a local shifted Tab regardless of what the "shifted Tab"
--	 * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or
--	 * HP's private BackTab keysym, and quite possibly some others too).
--	 * We never get ISO_Left_Tab here because it's already been translated
--	 * in VNCSConnectionST.
--	 */
--	if (maxKeysPerMod != 0 && keysym == XK_Tab &&
--	    ((state & (1 << ShiftMapIndex))) != 0)
--		col |= 1;
--
--	if (kc == 0) {
- 		/*
--		 * Not a direct match in the local keyboard mapping.  Check for
--		 * alternative keysyms with the same meaning.
-+		 * The state given to addKeysym() is just a hint and
-+		 * the actual result might still require some state
-+		 * changes.
- 		 */
--		for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) {
--			if (keysym == altKeysym[i].a)
--				kc = KeysymToKeycode(keymap, altKeysym[i].b,
--						     &col);
--			else if (keysym == altKeysym[i].b)
--				kc = KeysymToKeycode(keymap, altKeysym[i].a,
--						     &col);
--			if (kc)
--				break;
-+		keycode = keysymToKeycode(keysym, state, &new_state);
-+		if (keycode == 0) {
-+			vlog.error("Newly added keysym 0x%x cannot be generated", keysym);
-+			return;
- 		}
- 	}
- 
--	if (kc == 0) {
--		/* Dynamically add a new key to the keyboard mapping. */
--		for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
--			if (map[(kc - minKeyCode) * mapWidth] != 0)
-+	/*
-+	 * X11 generally lets shift toggle the keys on the numeric pad
-+	 * the same way NumLock does. This is however not the case on
-+	 * other systems like Windows. As a result, some applications
-+	 * get confused when we do a fake shift to get the same effect
-+	 * that having NumLock active would produce.
-+	 *
-+	 * Until we have proper NumLock synchronisation (so we can
-+	 * avoid faking shift), we try to avoid the fake shifts if we
-+	 * can use an alternative keysym.
-+	 */
-+	if (((state & ShiftMask) != (new_state & ShiftMask)) &&
-+	    avoidShiftNumLock && isAffectedByNumLock(keycode)) {
-+	    	KeyCode keycode2;
-+	    	unsigned new_state2;
-+
-+		vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
-+
-+		for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
-+			KeySym altsym;
-+
-+			if (altKeysym[i].a == keysym)
-+				altsym = altKeysym[i].b;
-+			else if (altKeysym[i].b == keysym)
-+				altsym = altKeysym[i].a;
-+			else
- 				continue;
- 
--			map[(kc - minKeyCode) * mapWidth] = keysym;
--			col = 0;
-+			keycode2 = keysymToKeycode(altsym, state, &new_state2);
-+			if (keycode2 == 0)
-+				continue;
- 
--			vlog.info("Added unknown keysym 0x%x to keycode %d",
--				  keysym, kc);
-+			if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
-+			    isAffectedByNumLock(keycode2))
-+				continue;
- 
--#if XORG < 17
--#if XORG == 15
--			master = inputInfo.keyboard;
--#else
--			master = keyboardDev->u.master;
--#endif
--			void *slave = dixLookupPrivate(&master->devPrivates,
--						       CoreDevicePrivateKey);
--			if (keyboardDev == slave) {
--				dixSetPrivate(&master->devPrivates,
--					      CoreDevicePrivateKey, NULL);
--#if XORG == 15
--				SwitchCoreKeyboard(keyboardDev);
--#else
--				CopyKeyClass(keyboardDev, master);
--#endif
--			}
--#else /* XORG < 17 */
--			XkbApplyMappingChange(keyboardDev, keymap, minKeyCode,
--					      maxKeyCode - minKeyCode + 1,
--					      NULL, serverClient);
--#if XORG >= 111
--			XkbCopyDeviceKeymap(keyboardDev->master, keyboardDev);
--#else
--			XkbCopyDeviceKeymap(keyboardDev->u.master, keyboardDev);
--#endif
--#endif /* XORG < 17 */
- 			break;
- 		}
--	}
- 
--	if (kc < minKeyCode) {
--		vlog.info("Keyboard mapping full - ignoring unknown keysym "
--			  "0x%x",keysym);
--		FREE_MAPS;
--		return;
--	}
--
--#if XORG < 17
--	/*
--	 * See if it's a modifier key.  If so, then don't do any auto-repeat,
--	 * because the X server will translate each press into a release
--	 * followed by a press.
--	 */
--	for (i = 0; i < 8; i++) {
--		for (k = 0; k < maxKeysPerMod; k++) {
--			int index = i * maxKeysPerMod + k;
--			if (kc == modmap[index] && IS_PRESSED(keyc,kc) && down) {
--				FREE_MAPS;
--				return;
--			}	
-+		if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
-+			vlog.debug("No alternative keysym found");
-+		else {
-+			keycode = keycode2;
-+			new_state = new_state2;
- 		}
- 	}
--#else
-+
- 	/*
--	 * If you would like to press a key which is already pressed then
--	 * viewer didn't send the "release" event. In this case release it
--	 * before the press.
-+	 * "Shifted Tab" is a bit of a mess. Some systems have varying,
-+	 * special keysyms for this symbol. VNC mandates that clients
-+	 * should always send the plain XK_Tab keysym and the server
-+	 * should deduce the meaning based on current Shift state.
-+	 * To comply with this, we will find the keycode that sends
-+	 * XK_Tab, and make sure that Shift isn't cleared. This can
-+	 * possibly result in a different keysym than XK_Tab, but that
-+	 * is the desired behaviour.
-+	 *
-+	 * Note: We never get ISO_Left_Tab here because it's already
-+	 *       been translated in VNCSConnectionST.
- 	 */
--	if (IS_PRESSED(keyc, kc) && down) {
--		vlog.debug("KeyRelease for %d wasn't sent, releasing", kc);
--		pressKey(keyboardDev, kc, false, "fixing keycode");
--	}
--#endif
-+	if (keysym == XK_Tab && (state & ShiftMask))
-+		new_state |= ShiftMask;
- 
--	if (maxKeysPerMod != 0) {
--		ModifierState shift(keyboardDev, ShiftMapIndex);
--		ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex);
--		if (down) {
--			if (col & 1)
--				shift.press();
--			else
--				shift.release();
--			if (modeSwitchMapIndex) {
--				if (col & 2)
--					modeSwitch.press();
--				else
--					modeSwitch.release();
--			}
--		}
--		/*
--		 * Ensure ModifierState objects are not destroyed before
--		 * pressKey call, otherwise fake modifier keypress can be lost.
--		 */
--		pressKey(keyboardDev, kc, down, "keycode");
--	} else {
--press:
--		pressKey(keyboardDev, kc, down, "keycode");
--	}
--
--
--        FREE_MAPS;
--	
- 	/*
--	 * When faking a modifier we are putting a keycode (which can
--	 * currently activate the desired modifier) on the input
--	 * queue. A future modmap change can change the mapping so
--	 * that this keycode means something else entirely. Guard
--	 * against this by processing the queue now.
-+	 * We need a bigger state change than just shift,
-+	 * so we need to know what the mask is for level 3 shifts.
- 	 */
--	mieqProcessInputEvents();
--}
--
--static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
--{
--	int per = keymap->mapWidth;
--	KeySym *syms;
--	KeySym lsym, usym;
--
--	if ((col < 0) || ((col >= per) && (col > 3)) ||
--	    (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode))
--		return NoSymbol;
--
--	syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
--	if (col >= 4)
--		return syms[col];
--
--	if (col > 1) {
--		while ((per > 2) && (syms[per - 1] == NoSymbol))
--			per--;
--		if (per < 3)
--			col -= 2;
--	}
--
--	if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
--		XkbConvertCase
--			    (syms[col&~1], &lsym, &usym);
--		if (!(col & 1))
--			return lsym;
--		/*
--		 * I'm commenting out this logic because it's incorrect even
--		 * though it was copied from the Xlib sources.  The X protocol
--		 * book quite clearly states that where a group consists of
--		 * element 1 being a non-alphabetic keysym and element 2 being
--		 * NoSymbol that you treat the second element as being the
--		 * same as the first.  This also tallies with the behaviour
--		 * produced by the installed Xlib on my linux box (I believe
--		 * this is because it uses some XKB code rather than the
--		 * original Xlib code - compare XKBBind.c with KeyBind.c in
--		 * lib/X11).
--		 */
--#if 0
--		else if (usym == lsym)
--			return NoSymbol;
--#endif
--		else
--			return usym;
--	}
--
--	return syms[col];
--}
-+	if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
-+		level_three_mask = getLevelThreeMask();
-+	else
-+		level_three_mask = 0;
-+
-+	shift_press = level_three_press = 0;
-+
-+	/* Need a fake press or release of shift? */
-+	if (!(state & ShiftMask) && (new_state & ShiftMask)) {
-+		shift_press = pressShift();
-+		if (shift_press == 0) {
-+			vlog.error("Unable to find a modifier key for Shift");
-+			return;
-+		}
- 
--/*
-- * KeysymToKeycode() - find the keycode and column corresponding to the given
-- * keysym.  The value of col passed in should be the column determined from the
-- * current shift state.  If the keysym can be found in that column we prefer
-- * that to finding it in a different column (which would require fake events to
-- * alter the shift state).
-- */
--static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col)
--{
--	int i, j;
-+		pressKey(keyboardDev, shift_press, true, "temp shift");
-+	} else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
-+		std::list<KeyCode>::const_iterator iter;
-+
-+		shift_release = releaseShift();
-+		if (shift_release.empty()) {
-+			vlog.error("Unable to find the modifier key(s) for releasing Shift");
-+			return;
-+		}
- 
--	j = *col;
--	for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
--		if (KeyCodetoKeySym(keymap, i, j) == ks)
--			return i;
-+		for (iter = shift_release.begin();iter != shift_release.end();++iter)
-+			pressKey(keyboardDev, *iter, false, "temp shift");
- 	}
- 
--	for (j = 0; j < keymap->mapWidth; j++) {
--		for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
--			if (KeyCodetoKeySym(keymap, i, j) == ks) {
--				*col = j;
--				return i;
--			}
-+	/* Need a fake press or release of level three shift? */
-+	if (!(state & level_three_mask) && (new_state & level_three_mask)) {
-+		level_three_press = pressLevelThree();
-+		if (level_three_press == 0) {
-+			vlog.error("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
-+			return;
- 		}
--	}
- 
--	return 0;
--}
--
--#if XORG < 17
--/* Fairly standard US PC Keyboard */
--
--#define MIN_KEY 8
--#define MAX_KEY 255
--#define MAP_LEN (MAX_KEY - MIN_KEY + 1)
--#define KEYSYMS_PER_KEY 2
--KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
--	NoSymbol, NoSymbol,
--	XK_Escape, NoSymbol,
--	XK_1, XK_exclam,
--	XK_2, XK_at,
--	XK_3, XK_numbersign,
--	XK_4, XK_dollar,
--	XK_5, XK_percent,
--	XK_6, XK_asciicircum,
--	XK_7, XK_ampersand,
--	XK_8, XK_asterisk,
--	XK_9, XK_parenleft,
--	XK_0, XK_parenright,
--	XK_minus, XK_underscore,
--	XK_equal, XK_plus,
--	XK_BackSpace, NoSymbol,
--	XK_Tab, NoSymbol,
--	XK_q, XK_Q,
--	XK_w, XK_W,
--	XK_e, XK_E,
--	XK_r, XK_R,
--	XK_t, XK_T,
--	XK_y, XK_Y,
--	XK_u, XK_U,
--	XK_i, XK_I,
--	XK_o, XK_O,
--	XK_p, XK_P,
--	XK_bracketleft, XK_braceleft,
--	XK_bracketright, XK_braceright,
--	XK_Return, NoSymbol,
--	XK_Control_L, NoSymbol,
--	XK_a, XK_A,
--	XK_s, XK_S,
--	XK_d, XK_D,
--	XK_f, XK_F,
--	XK_g, XK_G,
--	XK_h, XK_H,
--	XK_j, XK_J,
--	XK_k, XK_K,
--	XK_l, XK_L,
--	XK_semicolon, XK_colon,
--	XK_apostrophe, XK_quotedbl,
--	XK_grave, XK_asciitilde,
--	XK_Shift_L, NoSymbol,
--	XK_backslash, XK_bar,
--	XK_z, XK_Z,
--	XK_x, XK_X,
--	XK_c, XK_C,
--	XK_v, XK_V,
--	XK_b, XK_B,
--	XK_n, XK_N,
--	XK_m, XK_M,
--	XK_comma, XK_less,
--	XK_period, XK_greater,
--	XK_slash, XK_question,
--	XK_Shift_R, NoSymbol,
--	XK_KP_Multiply, NoSymbol,
--	XK_Alt_L, XK_Meta_L,
--	XK_space, NoSymbol,
--	XK_Caps_Lock, NoSymbol,
--	XK_F1, NoSymbol,
--	XK_F2, NoSymbol,
--	XK_F3, NoSymbol,
--	XK_F4, NoSymbol,
--	XK_F5, NoSymbol,
--	XK_F6, NoSymbol,
--	XK_F7, NoSymbol,
--	XK_F8, NoSymbol,
--	XK_F9, NoSymbol,
--	XK_F10, NoSymbol,
--	XK_Num_Lock, XK_Pointer_EnableKeys,
--	XK_Scroll_Lock, NoSymbol,
--	XK_KP_Home, XK_KP_7,
--	XK_KP_Up, XK_KP_8,
--	XK_KP_Prior, XK_KP_9,
--	XK_KP_Subtract, NoSymbol,
--	XK_KP_Left, XK_KP_4,
--	XK_KP_Begin, XK_KP_5,
--	XK_KP_Right, XK_KP_6,
--	XK_KP_Add, NoSymbol,
--	XK_KP_End, XK_KP_1,
--	XK_KP_Down, XK_KP_2,
--	XK_KP_Next, XK_KP_3,
--	XK_KP_Insert, XK_KP_0,
--	XK_KP_Delete, XK_KP_Decimal,
--	NoSymbol, NoSymbol,
--	NoSymbol, NoSymbol,
--	NoSymbol, NoSymbol,
--	XK_F11, NoSymbol,
--	XK_F12, NoSymbol,
--	XK_Home, NoSymbol,
--	XK_Up, NoSymbol,
--	XK_Prior, NoSymbol,
--	XK_Left, NoSymbol,
--	NoSymbol, NoSymbol,
--	XK_Right, NoSymbol,
--	XK_End, NoSymbol,
--	XK_Down, NoSymbol,
--	XK_Next, NoSymbol,
--	XK_Insert, NoSymbol,
--	XK_Delete, NoSymbol,
--	XK_KP_Enter, NoSymbol,
--	XK_Control_R, NoSymbol,
--	XK_Pause, XK_Break,
--	XK_Print, XK_Execute,
--	XK_KP_Divide, NoSymbol,
--	XK_Alt_R, XK_Meta_R,
--	NoSymbol, NoSymbol,
--	XK_Super_L, NoSymbol,
--	XK_Super_R, NoSymbol,
--	XK_Menu, NoSymbol,
--};
-+		pressKey(keyboardDev, level_three_press, true, "temp level 3 shift");
-+	} else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
-+		std::list<KeyCode>::const_iterator iter;
-+
-+		level_three_release = releaseLevelThree();
-+		if (level_three_release.empty()) {
-+			vlog.error("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
-+			return;
-+		}
- 
--static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap)
--{
--	int i;
-+		for (iter = level_three_release.begin();iter != level_three_release.end();++iter)
-+			pressKey(keyboardDev, *iter, false, "temp level 3 shift");
-+	}
- 
--	for (i = 0; i < MAP_LENGTH; i++)
--		pModMap[i] = NoSymbol;
-+	/* Now press the actual key */
-+	pressKey(keyboardDev, keycode, true, "keycode");
- 
--	for (i = 0; i < MAP_LEN; i++) {
--		switch (keyboardMap[i * KEYSYMS_PER_KEY]) {
--		case XK_Shift_L:
--		case XK_Shift_R:
--			pModMap[i + MIN_KEY] = ShiftMask;
--			break;
--		case XK_Caps_Lock:
--			pModMap[i + MIN_KEY] = LockMask;
--			break;
--		case XK_Control_L:
--		case XK_Control_R:
--			pModMap[i + MIN_KEY] = ControlMask;
--			break;
--		case XK_Alt_L:
--		case XK_Alt_R:
--			pModMap[i + MIN_KEY] = Mod1Mask;
--			break;
--		case XK_Num_Lock:
--			pModMap[i + MIN_KEY] = Mod2Mask;
--			break;
--			/* No defaults for Mod3Mask yet */
--		case XK_Super_L:
--		case XK_Super_R:
--		case XK_Hyper_L:
--		case XK_Hyper_R:
--			pModMap[i + MIN_KEY] = Mod4Mask;
--			break;
--		case XK_ISO_Level3_Shift:
--		case XK_Mode_switch:
--			pModMap[i + MIN_KEY] = Mod5Mask;
--			break;
-+	/* And store the mapping so that we can do a proper release later */
-+	for (i = 0;i < 256;i++) {
-+		if (i == keycode)
-+			continue;
-+		if (pressedKeys[i] == keysym) {
-+			vlog.error("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
-+			pressedKeys[i] = NoSymbol;
- 		}
- 	}
- 
--	pKeySyms->minKeyCode = MIN_KEY;
--	pKeySyms->maxKeyCode = MAX_KEY;
--	pKeySyms->mapWidth = KEYSYMS_PER_KEY;
--	pKeySyms->map = keyboardMap;
-+	pressedKeys[keycode] = keysym;
- 
--	return TRUE;
--}
--#endif
--
--static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl,
--			 int class_)
--{
--	if (percent > 0)
--		vncBell();
--}
--
--static int keyboardProc(DeviceIntPtr pDevice, int onoff)
--{
--#if XORG < 17
--	KeySymsRec keySyms;
--	CARD8 modMap[MAP_LENGTH];
--#endif
--	DevicePtr pDev = (DevicePtr)pDevice;
-+	/* Undo any fake level three shift */
-+	if (level_three_press != 0)
-+		pressKey(keyboardDev, level_three_press, false, "temp level 3 shift");
-+	else if (!level_three_release.empty()) {
-+		std::list<KeyCode>::const_iterator iter;
-+		for (iter = level_three_release.begin();iter != level_three_release.end();++iter)
-+			pressKey(keyboardDev, *iter, true, "temp level 3 shift");
-+	}
- 
--	switch (onoff) {
--	case DEVICE_INIT:
--#if XORG < 17
--		GetMappings(&keySyms, modMap);
--#endif
--		InitKeyboardDeviceStruct(
--#if XORG >= 17
--					 pDevice, NULL,
--#else
--					 pDev, &keySyms, modMap,
--#endif
--					 keyboardBell, (KbdCtrlProcPtr)NoopDDA);
--		break;
--	case DEVICE_ON:
--		pDev->on = TRUE;
--		break;
--	case DEVICE_OFF:
--		pDev->on = FALSE;
--		break;
--#if 0
--	case DEVICE_CLOSE:
--		break;
--#endif
-+	/* Undo any fake shift */
-+	if (shift_press != 0)
-+		pressKey(keyboardDev, shift_press, false, "temp shift");
-+	else if (!shift_release.empty()) {
-+		std::list<KeyCode>::const_iterator iter;
-+		for (iter = shift_release.begin();iter != shift_release.end();++iter)
-+			pressKey(keyboardDev, *iter, true, "temp shift");
- 	}
- 
--	return Success;
-+	/*
-+	 * When faking a modifier we are putting a keycode (which can
-+	 * currently activate the desired modifier) on the input
-+	 * queue. A future modmap change can change the mapping so
-+	 * that this keycode means something else entirely. Guard
-+	 * against this by processing the queue now.
-+	 */
-+	mieqProcessInputEvents();
- }
--
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input	2014-01-17 16:01:13.141109454 +0000
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc	2014-01-17 16:01:13.141109454 +0000
-@@ -0,0 +1,594 @@
-+/* Copyright (C) 2009 TightVNC Team
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ * Copyright 2013 Pierre Ossman for Cendio AB
-+ *
-+ * This is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ * 
-+ * This software is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ * 
-+ * You should have received a copy of the GNU General Public License
-+ * along with this software; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
-+ * USA.
-+ */
-+
-+#ifdef HAVE_DIX_CONFIG_H
-+#include <dix-config.h>
-+#endif
-+
-+#include "Input.h"
-+#include "xorg-version.h"
-+
-+extern "C" {
-+#define public c_public
-+#define class c_class
-+#include "inputstr.h"
-+#ifndef XKB_IN_SERVER
-+#define XKB_IN_SERVER
-+#endif
-+#ifdef XKB
-+/*
-+ * This include is needed to use XkbConvertCase instead of XConvertCase even if
-+ * we don't use XKB extension.
-+ */
-+#include <xkbsrv.h>
-+#endif
-+/* These defines give us access to all keysyms we need */
-+#define XK_PUBLISHING
-+#define XK_TECHNICAL
-+#include <X11/keysym.h>
-+#include <X11/XF86keysym.h>
-+#include <X11/Xlib.h>
-+#include <X11/Xutil.h>
-+#undef public
-+#undef class
-+}
-+
-+#if XORG < 17
-+
-+#define IS_PRESSED(dev, keycode) \
-+	((dev)->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
-+
-+/* Fairly standard US PC Keyboard */
-+
-+#define MIN_KEY 8
-+#define MAX_KEY 255
-+#define MAP_LEN (MAX_KEY - MIN_KEY + 1)
-+#define KEYSYMS_PER_KEY 2
-+KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
-+	NoSymbol, NoSymbol,
-+	XK_Escape, NoSymbol,
-+	XK_1, XK_exclam,
-+	XK_2, XK_at,
-+	XK_3, XK_numbersign,
-+	XK_4, XK_dollar,
-+	XK_5, XK_percent,
-+	XK_6, XK_asciicircum,
-+	XK_7, XK_ampersand,
-+	XK_8, XK_asterisk,
-+	XK_9, XK_parenleft,
-+	XK_0, XK_parenright,
-+	XK_minus, XK_underscore,
-+	XK_equal, XK_plus,
-+	XK_BackSpace, NoSymbol,
-+	XK_Tab, NoSymbol,
-+	XK_q, XK_Q,
-+	XK_w, XK_W,
-+	XK_e, XK_E,
-+	XK_r, XK_R,
-+	XK_t, XK_T,
-+	XK_y, XK_Y,
-+	XK_u, XK_U,
-+	XK_i, XK_I,
-+	XK_o, XK_O,
-+	XK_p, XK_P,
-+	XK_bracketleft, XK_braceleft,
-+	XK_bracketright, XK_braceright,
-+	XK_Return, NoSymbol,
-+	XK_Control_L, NoSymbol,
-+	XK_a, XK_A,
-+	XK_s, XK_S,
-+	XK_d, XK_D,
-+	XK_f, XK_F,
-+	XK_g, XK_G,
-+	XK_h, XK_H,
-+	XK_j, XK_J,
-+	XK_k, XK_K,
-+	XK_l, XK_L,
-+	XK_semicolon, XK_colon,
-+	XK_apostrophe, XK_quotedbl,
-+	XK_grave, XK_asciitilde,
-+	XK_Shift_L, NoSymbol,
-+	XK_backslash, XK_bar,
-+	XK_z, XK_Z,
-+	XK_x, XK_X,
-+	XK_c, XK_C,
-+	XK_v, XK_V,
-+	XK_b, XK_B,
-+	XK_n, XK_N,
-+	XK_m, XK_M,
-+	XK_comma, XK_less,
-+	XK_period, XK_greater,
-+	XK_slash, XK_question,
-+	XK_Shift_R, NoSymbol,
-+	XK_KP_Multiply, NoSymbol,
-+	XK_Alt_L, XK_Meta_L,
-+	XK_space, NoSymbol,
-+	XK_Caps_Lock, NoSymbol,
-+	XK_F1, NoSymbol,
-+	XK_F2, NoSymbol,
-+	XK_F3, NoSymbol,
-+	XK_F4, NoSymbol,
-+	XK_F5, NoSymbol,
-+	XK_F6, NoSymbol,
-+	XK_F7, NoSymbol,
-+	XK_F8, NoSymbol,
-+	XK_F9, NoSymbol,
-+	XK_F10, NoSymbol,
-+	XK_Num_Lock, XK_Pointer_EnableKeys,
-+	XK_Scroll_Lock, NoSymbol,
-+	XK_KP_Home, XK_KP_7,
-+	XK_KP_Up, XK_KP_8,
-+	XK_KP_Prior, XK_KP_9,
-+	XK_KP_Subtract, NoSymbol,
-+	XK_KP_Left, XK_KP_4,
-+	XK_KP_Begin, XK_KP_5,
-+	XK_KP_Right, XK_KP_6,
-+	XK_KP_Add, NoSymbol,
-+	XK_KP_End, XK_KP_1,
-+	XK_KP_Down, XK_KP_2,
-+	XK_KP_Next, XK_KP_3,
-+	XK_KP_Insert, XK_KP_0,
-+	XK_KP_Delete, XK_KP_Decimal,
-+	NoSymbol, NoSymbol,
-+	NoSymbol, NoSymbol,
-+	NoSymbol, NoSymbol,
-+	XK_F11, NoSymbol,
-+	XK_F12, NoSymbol,
-+	XK_Home, NoSymbol,
-+	XK_Up, NoSymbol,
-+	XK_Prior, NoSymbol,
-+	XK_Left, NoSymbol,
-+	NoSymbol, NoSymbol,
-+	XK_Right, NoSymbol,
-+	XK_End, NoSymbol,
-+	XK_Down, NoSymbol,
-+	XK_Next, NoSymbol,
-+	XK_Insert, NoSymbol,
-+	XK_Delete, NoSymbol,
-+	XK_KP_Enter, NoSymbol,
-+	XK_Control_R, NoSymbol,
-+	XK_Pause, XK_Break,
-+	XK_Print, XK_Execute,
-+	XK_KP_Divide, NoSymbol,
-+	XK_Alt_R, XK_Meta_R,
-+	NoSymbol, NoSymbol,
-+	XK_Super_L, NoSymbol,
-+	XK_Super_R, NoSymbol,
-+	XK_Menu, NoSymbol,
-+};
-+
-+void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
-+{
-+	int i;
-+
-+	for (i = 0; i < MAP_LENGTH; i++)
-+		modmap[i] = NoSymbol;
-+
-+	for (i = 0; i < MAP_LEN; i++) {
-+		switch (keyboardMap[i * KEYSYMS_PER_KEY]) {
-+		case XK_Shift_L:
-+		case XK_Shift_R:
-+			modmap[i + MIN_KEY] = ShiftMask;
-+			break;
-+		case XK_Caps_Lock:
-+			modmap[i + MIN_KEY] = LockMask;
-+			break;
-+		case XK_Control_L:
-+		case XK_Control_R:
-+			modmap[i + MIN_KEY] = ControlMask;
-+			break;
-+		case XK_Alt_L:
-+		case XK_Alt_R:
-+			modmap[i + MIN_KEY] = Mod1Mask;
-+			break;
-+		case XK_Num_Lock:
-+			modmap[i + MIN_KEY] = Mod2Mask;
-+			break;
-+			/* No defaults for Mod3Mask yet */
-+		case XK_Super_L:
-+		case XK_Super_R:
-+		case XK_Hyper_L:
-+		case XK_Hyper_R:
-+			modmap[i + MIN_KEY] = Mod4Mask;
-+			break;
-+		case XK_ISO_Level3_Shift:
-+		case XK_Mode_switch:
-+			modmap[i + MIN_KEY] = Mod5Mask;
-+			break;
-+		}
-+	}
-+
-+	keysyms->minKeyCode = MIN_KEY;
-+	keysyms->maxKeyCode = MAX_KEY;
-+	keysyms->mapWidth = KEYSYMS_PER_KEY;
-+	keysyms->map = keyboardMap;
-+}
-+
-+void InputDevice::PrepareInputDevices(void)
-+{
-+	/* Don't need to do anything here */
-+}
-+
-+unsigned InputDevice::getKeyboardState(void)
-+{
-+	return keyboardDev->key->state;
-+}
-+
-+unsigned InputDevice::getLevelThreeMask(void)
-+{
-+	int i, j, k;
-+
-+	int minKeyCode, mapWidth;
-+	KeySym *map;
-+
-+	int maxKeysPerMod;
-+	CARD8 *modmap;
-+
-+	minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
-+	mapWidth = keyboardDev->key->curKeySyms.mapWidth;
-+	map = keyboardDev->key->curKeySyms.map;
-+
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	modmap = keyboardDev->key->modifierKeyMap;
-+
-+	for (i = 3; i < 8; i++) {
-+		for (k = 0; k < maxKeysPerMod; k++) {
-+			int index = i * maxKeysPerMod + k;
-+			int keycode = modmap[index];
-+
-+			if (keycode == 0)
-+				continue;
-+
-+			for (j = 0; j < mapWidth; j++) {
-+				KeySym keysym;
-+				keysym = map[(keycode - minKeyCode) * mapWidth + j];
-+				if (keysym == XK_Mode_switch)
-+					return 1 << i;
-+			}
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+KeyCode InputDevice::pressShift(void)
-+{
-+	int maxKeysPerMod;
-+
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	return keyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
-+}
-+
-+std::list<KeyCode> InputDevice::releaseShift(void)
-+{
-+	std::list<KeyCode> keys;
-+
-+	int maxKeysPerMod;
-+
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	for (int k = 0; k < maxKeysPerMod; k++) {
-+		int keycode;
-+		int index;
-+
-+		index = ShiftMapIndex * maxKeysPerMod + k;
-+
-+		keycode = keyboardDev->key->modifierKeyMap[index];
-+		if (keycode == 0)
-+			continue;
-+
-+		if (!IS_PRESSED(keyboardDev, keycode))
-+			continue;
-+
-+		keys.push_back(keycode);
-+	}
-+
-+	return keys;
-+}
-+
-+KeyCode InputDevice::pressLevelThree(void)
-+{
-+	unsigned mask, index;
-+	int maxKeysPerMod;
-+
-+	mask = getLevelThreeMask();
-+	if (mask == 0)
-+		return 0;
-+
-+	index = ffs(mask) - 1;
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	return keyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
-+}
-+
-+std::list<KeyCode> InputDevice::releaseLevelThree(void)
-+{
-+	std::list<KeyCode> keys;
-+
-+	unsigned mask, msindex;
-+	int maxKeysPerMod;
-+
-+	mask = getLevelThreeMask();
-+	if (mask == 0)
-+		return keys;
-+
-+	msindex = ffs(mask) - 1;
-+
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	for (int k = 0; k < maxKeysPerMod; k++) {
-+		int keycode;
-+		int index;
-+
-+		index = msindex * maxKeysPerMod + k;
-+
-+		keycode = keyboardDev->key->modifierKeyMap[index];
-+		if (keycode == 0)
-+			continue;
-+
-+		if (!IS_PRESSED(keyboardDev, keycode))
-+			continue;
-+
-+		keys.push_back(keycode);
-+	}
-+
-+	return keys;
-+}
-+
-+static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
-+{
-+	int per = keymap->mapWidth;
-+	KeySym *syms;
-+	KeySym lsym, usym;
-+
-+	if ((col < 0) || ((col >= per) && (col > 3)) ||
-+	    (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode))
-+		return NoSymbol;
-+
-+	syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
-+	if (col >= 4)
-+		return syms[col];
-+
-+	if (col > 1) {
-+		while ((per > 2) && (syms[per - 1] == NoSymbol))
-+			per--;
-+		if (per < 3)
-+			col -= 2;
-+	}
-+
-+	if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
-+		XkbConvertCase(syms[col&~1], &lsym, &usym);
-+		if (!(col & 1))
-+			return lsym;
-+		/*
-+		 * I'm commenting out this logic because it's incorrect even
-+		 * though it was copied from the Xlib sources.  The X protocol
-+		 * book quite clearly states that where a group consists of
-+		 * element 1 being a non-alphabetic keysym and element 2 being
-+		 * NoSymbol that you treat the second element as being the
-+		 * same as the first.  This also tallies with the behaviour
-+		 * produced by the installed Xlib on my linux box (I believe
-+		 * this is because it uses some XKB code rather than the
-+		 * original Xlib code - compare XKBBind.c with KeyBind.c in
-+		 * lib/X11).
-+		 */
-+#if 0
-+		else if (usym == lsym)
-+			return NoSymbol;
-+#endif
-+		else
-+			return usym;
-+	}
-+
-+	return syms[col];
-+}
-+
-+KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
-+{
-+	int i, j;
-+	unsigned mask;
-+
-+	KeySymsPtr keymap;
-+	int mapWidth;
-+
-+	mask = getLevelThreeMask();
-+
-+	keymap = &keyboardDev->key->curKeySyms;
-+
-+	/*
-+	 * Column 0 means both shift and "mode_switch" (AltGr) must be released,
-+	 * column 1 means shift must be pressed and mode_switch released,
-+	 * column 2 means shift must be released and mode_switch pressed, and
-+	 * column 3 means both shift and mode_switch must be pressed.
-+	 */
-+	j = 0;
-+	if (state & ShiftMask)
-+		j |= 0x1;
-+	if (state & mask)
-+		j |= 0x2;
-+
-+	*new_state = state;
-+	for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
-+		if (KeyCodetoKeySym(keymap, i, j) == keysym)
-+			return i;
-+	}
-+
-+	/* Only the first four columns have well-defined meaning */
-+	mapWidth = keymap->mapWidth;
-+	if (mapWidth > 4)
-+		mapWidth = 4;
-+
-+	for (j = 0; j < mapWidth; j++) {
-+		for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
-+			if (KeyCodetoKeySym(keymap, i, j) == keysym) {
-+				*new_state = state & ~(ShiftMask|mask);
-+				if (j & 0x1)
-+					*new_state |= ShiftMask;
-+				if (j & 0x2)
-+					*new_state |= mask;
-+
-+				return i;
-+			}
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
-+{
-+	int i, j, k;
-+
-+	int minKeyCode, mapWidth;
-+	KeySym *map;
-+
-+	int maxKeysPerMod;
-+	CARD8 *modmap;
-+
-+	int num_lock_index;
-+
-+	minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
-+	mapWidth = keyboardDev->key->curKeySyms.mapWidth;
-+	map = keyboardDev->key->curKeySyms.map;
-+
-+	maxKeysPerMod = keyboardDev->key->maxKeysPerModifier;
-+	modmap = keyboardDev->key->modifierKeyMap;
-+
-+	/* Caps Lock is fairly easy as it has a dedicated modmap entry */
-+	for (k = 0; k < maxKeysPerMod; k++) {
-+		int index;
-+
-+		index = LockMapIndex * maxKeysPerMod + k;
-+		if (keycode == modmap[index])
-+			return true;
-+	}
-+
-+	/* For Num Lock we need to find the correct modmap entry */
-+	num_lock_index = i;
-+	for (i = 3; i < 8; i++) {
-+		for (k = 0; k < maxKeysPerMod; k++) {
-+			int index = i * maxKeysPerMod + k;
-+			int keycode = modmap[index];
-+
-+			if (keycode == 0)
-+				continue;
-+
-+			for (j = 0; j < mapWidth; j++) {
-+				KeySym keysym;
-+				keysym = map[(keycode - minKeyCode) * mapWidth + j];
-+				if (keysym == XK_Num_Lock) {
-+					num_lock_index = i;
-+					goto done;
-+				}
-+			}
-+		}
-+	}
-+done:
-+
-+	if (num_lock_index == 0)
-+		return false;
-+
-+	/* Now we can look in the modmap */ 
-+	for (k = 0; k < maxKeysPerMod; k++) {
-+		int index;
-+
-+		index = num_lock_index * maxKeysPerMod + k;
-+		if (keycode == modmap[index])
-+			return true;
-+	}
-+
-+	return false;
-+}
-+
-+bool InputDevice::isAffectedByNumLock(KeyCode keycode)
-+{
-+	KeySymsPtr keymap;
-+	int i, per;
-+	KeySym *syms;
-+
-+	keymap = &keyboardDev->key->curKeySyms;
-+	per = keymap->mapWidth;
-+	syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
-+
-+	for (i = 0;i < per;i++) {
-+		if (IsKeypadKey(syms[i]))
-+			return true;
-+		if (IsPrivateKeypadKey(syms[i]))
-+			return true;
-+	}
-+
-+	return false;
-+}
-+
-+KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
-+{
-+	KeyCode kc;
-+
-+	int minKeyCode, maxKeyCode, mapWidth;
-+	KeySym *map;
-+
-+	minKeyCode = keyboardDev->key->curKeySyms.minKeyCode;
-+	maxKeyCode = keyboardDev->key->curKeySyms.maxKeyCode;
-+	mapWidth = keyboardDev->key->curKeySyms.mapWidth;
-+	map = keyboardDev->key->curKeySyms.map;
-+
-+	/*
-+	 * Magic, which dynamically adds keysym<->keycode mapping
-+	 * depends on X.Org version. Quick explanation of that "magic":
-+	 * 
-+	 * 1.5
-+	 * - has only one core keyboard so we have to keep core
-+	 *   keyboard mapping synchronized with vncKeyboardDevice. Do
-+	 *   it via SwitchCoreKeyboard()
-+	 *
-+	 * 1.6 (aka MPX - Multi pointer X)
-+	 * - multiple master devices (= core devices) exists, keep
-+	 *   vncKeyboardDevice synchronized with proper master device
-+	 */
-+	for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
-+		DeviceIntPtr master;
-+
-+		if (map[(kc - minKeyCode) * mapWidth] != 0)
-+			continue;
-+
-+		map[(kc - minKeyCode) * mapWidth] = keysym;
-+
-+#if XORG == 15
-+		master = inputInfo.keyboard;
-+#else
-+		master = keyboardDev->u.master;
-+#endif
-+		void *slave = dixLookupPrivate(&master->devPrivates,
-+					       CoreDevicePrivateKey);
-+		if (keyboardDev == slave) {
-+			dixSetPrivate(&master->devPrivates,
-+				      CoreDevicePrivateKey, NULL);
-+#if XORG == 15
-+			SwitchCoreKeyboard(keyboardDev);
-+#else
-+			CopyKeyClass(keyboardDev, master);
-+#endif
-+		}
-+
-+		return kc;
-+	}
-+
-+	return 0;
-+}
-+
-+#endif
-+
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input	2010-04-14 10:24:06.000000000 +0100
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h	2014-01-17 16:01:13.141109454 +0000
-@@ -1,6 +1,7 @@
- /* Copyright (C) 2009 TightVNC Team
-  * Copyright (C) 2009, 2010 Red Hat, Inc.
-  * Copyright (C) 2009, 2010 TigerVNC Team
-+ * Copyright 2013 Pierre Ossman for Cendio AB
-  *
-  * This is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -26,12 +27,16 @@
- #include <dix-config.h>
- #endif
- 
-+#include <list>
-+
- #include <rfb/VNCServerST.h>
- 
- extern "C" {
- #include "input.h"
- };
- 
-+#include "xorg-version.h"
-+
- /* Represents input device (keyboard + pointer) */
- class InputDevice {
- public:
-@@ -55,24 +60,58 @@ public:
- 
- 	void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); }
- 	void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); }
--private:
-+
- 	/*
- 	 * Init input device. This cannot be done in the constructor
- 	 * because constructor is called during X server extensions
- 	 * initialization. Devices must be initialized after core
- 	 * pointer/keyboard initialization which is actually after extesions
- 	 * initialization. Check InitExtensions(), InitCoreDevices() and
--	 * InitInput() calls in dix/main.c
-+	 * InitInput() calls in dix/main.c. Instead it is called from
-+	 * XserverDesktop at an appropriate time.
- 	 */
--	void initInputDevice(void);
-+	void InitInputDevice(void);
- 
-+private:
- 	void keyEvent(rdr::U32 keysym, bool down);
- 
-+	/* Backend dependent functions below here */
-+	void PrepareInputDevices(void);
-+
-+	unsigned getKeyboardState(void);
-+	unsigned getLevelThreeMask(void);
-+
-+	KeyCode pressShift(void);
-+	std::list<KeyCode> releaseShift(void);
-+
-+	KeyCode pressLevelThree(void);
-+	std::list<KeyCode> releaseLevelThree(void);
-+
-+	KeyCode keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
-+
-+	bool isLockModifier(KeyCode keycode, unsigned state);
-+
-+	bool isAffectedByNumLock(KeyCode keycode);
-+
-+	KeyCode addKeysym(KeySym keysym, unsigned state);
-+
-+private:
-+#if XORG >= 17
-+	static void vncXkbProcessDeviceEvent(int screenNum,
-+	                                     InternalEvent *event,
-+	                                     DeviceIntPtr dev);
-+#endif
-+
-+private:
- 	rfb::VNCServerST *server;
-+	bool initialized;
- 	DeviceIntPtr keyboardDev;
- 	DeviceIntPtr pointerDev;
-+
- 	int oldButtonMask;
- 	rfb::Point cursorPos, oldCursorPos;
-+
-+	KeySym pressedKeys[256];
- };
- 
- #endif
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input	2014-01-17 16:01:13.141109454 +0000
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc	2014-01-17 16:01:13.141109454 +0000
-@@ -0,0 +1,669 @@
-+/* Copyright (C) 2009 TightVNC Team
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ * Copyright 2013 Pierre Ossman for Cendio AB
-+ *
-+ * This is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ * 
-+ * This software is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ * 
-+ * You should have received a copy of the GNU General Public License
-+ * along with this software; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
-+ * USA.
-+ */
-+
-+#ifdef HAVE_DIX_CONFIG_H
-+#include <dix-config.h>
-+#endif
-+
-+#include "Input.h"
-+#include "xorg-version.h"
-+
-+#if XORG >= 17
-+
-+extern "C" {
-+#define public c_public
-+#define class c_class
-+#include "xkbsrv.h"
-+#include "xkbstr.h"
-+#include "eventstr.h"
-+#include "scrnintstr.h"
-+#include "mi.h"
-+#include <X11/keysym.h>
-+#include <X11/Xlib.h>
-+#include <X11/Xutil.h>
-+#undef public
-+#undef class
-+}
-+
-+#if XORG < 19
-+static int vncXkbScreenPrivateKeyIndex;
-+static DevPrivateKey vncXkbScreenPrivateKey = &vncXkbScreenPrivateKeyIndex;
-+#else
-+static DevPrivateKeyRec vncXkbPrivateKeyRec;
-+#define vncXkbScreenPrivateKey (&vncXkbPrivateKeyRec)
-+#endif
-+
-+#define vncXkbScreenPrivate(pScreen) \
-+	(*(InputDevice**) dixLookupPrivate(&(pScreen)->devPrivates, \
-+	                                   vncXkbScreenPrivateKey))
-+
-+#ifndef KEYBOARD_OR_FLOAT
-+#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
-+#endif
-+
-+/* Stolen from libX11 */
-+static Bool
-+XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
-+                    register unsigned int mods, unsigned int *mods_rtrn,
-+                    KeySym *keysym_rtrn)
-+{
-+	XkbKeyTypeRec *type;
-+	int col,nKeyGroups;
-+	unsigned preserve,effectiveGroup;
-+	KeySym *syms;
-+
-+	if (mods_rtrn!=NULL)
-+		*mods_rtrn = 0;
-+
-+	nKeyGroups= XkbKeyNumGroups(xkb,key);
-+	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
-+		if (keysym_rtrn!=NULL)
-+			*keysym_rtrn = NoSymbol;
-+		return False;
-+	}
-+
-+	syms = XkbKeySymsPtr(xkb,key);
-+
-+	/* find the offset of the effective group */
-+	col = 0;
-+	effectiveGroup= XkbGroupForCoreState(mods);
-+	if ( effectiveGroup>=nKeyGroups ) {
-+		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-+		switch (XkbOutOfRangeGroupAction(groupInfo)) {
-+		default:
-+			effectiveGroup %= nKeyGroups;
-+			break;
-+		case XkbClampIntoRange:
-+			effectiveGroup = nKeyGroups-1;
-+			break;
-+		case XkbRedirectIntoRange:
-+			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-+			if (effectiveGroup>=nKeyGroups)
-+				effectiveGroup= 0;
-+			break;
-+		}
-+	}
-+	col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
-+	type = XkbKeyKeyType(xkb,key,effectiveGroup);
-+
-+	preserve= 0;
-+	if (type->map) { /* find the column (shift level) within the group */
-+		register int i;
-+		register XkbKTMapEntryPtr entry;
-+		for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
-+			if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
-+				col+= entry->level;
-+				if (type->preserve)
-+					preserve= type->preserve[i].mask;
-+				break;
-+			}
-+		}
-+	}
-+
-+	if (keysym_rtrn!=NULL)
-+		*keysym_rtrn= syms[col];
-+	if (mods_rtrn)
-+		*mods_rtrn= type->mods.mask&(~preserve);
-+
-+	return (syms[col]!=NoSymbol);
-+}
-+
-+static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-+{
-+	XkbKeyTypeRec *type;
-+	int col,nKeyGroups;
-+	unsigned effectiveGroup;
-+	XkbAction *acts;
-+
-+	if (!XkbKeyHasActions(xkb, key))
-+		return NULL;
-+
-+	nKeyGroups= XkbKeyNumGroups(xkb,key);
-+	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
-+		return NULL;
-+
-+	acts = XkbKeyActionsPtr(xkb,key);
-+
-+	/* find the offset of the effective group */
-+	col = 0;
-+	effectiveGroup= XkbGroupForCoreState(mods);
-+	if ( effectiveGroup>=nKeyGroups ) {
-+		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-+		switch (XkbOutOfRangeGroupAction(groupInfo)) {
-+		default:
-+			effectiveGroup %= nKeyGroups;
-+			break;
-+		case XkbClampIntoRange:
-+			effectiveGroup = nKeyGroups-1;
-+			break;
-+		case XkbRedirectIntoRange:
-+			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-+			if (effectiveGroup>=nKeyGroups)
-+				effectiveGroup= 0;
-+			break;
-+		}
-+	}
-+	col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
-+	type = XkbKeyKeyType(xkb,key,effectiveGroup);
-+
-+	if (type->map) { /* find the column (shift level) within the group */
-+		register int i;
-+		register XkbKTMapEntryPtr entry;
-+		for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
-+			if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
-+				col+= entry->level;
-+				break;
-+			}
-+		}
-+	}
-+
-+	return &acts[col];
-+}
-+
-+static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-+{
-+	int nKeyGroups;
-+	unsigned effectiveGroup;
-+
-+	nKeyGroups= XkbKeyNumGroups(xkb,key);
-+	if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
-+		return 0;
-+
-+	effectiveGroup= XkbGroupForCoreState(mods);
-+	if ( effectiveGroup>=nKeyGroups ) {
-+		unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-+		switch (XkbOutOfRangeGroupAction(groupInfo)) {
-+		default:
-+			effectiveGroup %= nKeyGroups;
-+			break;
-+		case XkbClampIntoRange:
-+			effectiveGroup = nKeyGroups-1;
-+			break;
-+		case XkbRedirectIntoRange:
-+			effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-+			if (effectiveGroup>=nKeyGroups)
-+				effectiveGroup= 0;
-+			break;
-+		}
-+	}
-+
-+	return effectiveGroup;
-+}
-+
-+void InputDevice::PrepareInputDevices(void)
-+{
-+#if XORG < 19
-+	if (!dixRequestPrivate(vncXkbScreenPrivateKey, sizeof(InputDevice*)))
-+		FatalError("Failed to register TigerVNC XKB screen key\n");
-+#else
-+	if (!dixRegisterPrivateKey(vncXkbScreenPrivateKey, PRIVATE_SCREEN,
-+	                           sizeof(InputDevice*)))
-+		FatalError("Failed to register TigerVNC XKB screen key\n");
-+#endif
-+
-+	for (int scr = 0; scr < screenInfo.numScreens; scr++)
-+		vncXkbScreenPrivate(screenInfo.screens[scr]) = this;
-+
-+	/*
-+	 * Not ideal since these callbacks do not stack, but it's the only
-+	 * decent way we can reliably catch events for both the slave and
-+	 * master device.
-+	 */
-+	mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
-+	mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
-+}
-+
-+unsigned InputDevice::getKeyboardState(void)
-+{
-+	return XkbStateFieldFromRec(&keyboardDev->master->key->xkbInfo->state);
-+}
-+
-+unsigned InputDevice::getLevelThreeMask(void)
-+{
-+	unsigned state;
-+	KeyCode keycode;
-+	XkbDescPtr xkb;
-+	XkbAction *act;
-+
-+	/* Group state is still important */
-+	state = getKeyboardState();
-+	state &= ~0xff;
-+
-+	keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
-+	if (keycode == 0) {
-+		keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
-+		if (keycode == 0)
-+			return 0;
-+	}
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+
-+	act = XkbKeyActionPtr(xkb, keycode, state);
-+	if (act == NULL)
-+		return 0;
-+	if (act->type != XkbSA_SetMods)
-+		return 0;
-+
-+	if (act->mods.flags & XkbSA_UseModMapMods)
-+		return xkb->map->modmap[keycode];
-+	else
-+		return act->mods.mask;
-+}
-+
-+KeyCode InputDevice::pressShift(void)
-+{
-+	unsigned state;
-+
-+	XkbDescPtr xkb;
-+	unsigned int key;
-+
-+	state = getKeyboardState();
-+	if (state & ShiftMask)
-+		return 0;
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-+		XkbAction *act;
-+		unsigned char mask;
-+
-+		act = XkbKeyActionPtr(xkb, key, state);
-+		if (act == NULL)
-+			continue;
-+
-+		if (act->type != XkbSA_SetMods)
-+			continue;
-+
-+		if (act->mods.flags & XkbSA_UseModMapMods)
-+			mask = xkb->map->modmap[key];
-+		else
-+			mask = act->mods.mask;
-+
-+		if ((mask & ShiftMask) == ShiftMask)
-+			return key;
-+	}
-+
-+	return 0;
-+}
-+
-+std::list<KeyCode> InputDevice::releaseShift(void)
-+{
-+	unsigned state;
-+	std::list<KeyCode> keys;
-+
-+	DeviceIntPtr master;
-+	XkbDescPtr xkb;
-+	unsigned int key;
-+
-+	state = getKeyboardState();
-+	if (!(state & ShiftMask))
-+		return keys;
-+
-+	master = keyboardDev->master;
-+	xkb = master->key->xkbInfo->desc;
-+	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-+		XkbAction *act;
-+		unsigned char mask;
-+
-+		if (!key_is_down(master, key, KEY_PROCESSED))
-+			continue;
-+
-+		act = XkbKeyActionPtr(xkb, key, state);
-+		if (act == NULL)
-+			continue;
-+
-+		if (act->type != XkbSA_SetMods)
-+			continue;
-+
-+		if (act->mods.flags & XkbSA_UseModMapMods)
-+			mask = xkb->map->modmap[key];
-+		else
-+			mask = act->mods.mask;
-+
-+		if (!(mask & ShiftMask))
-+			continue;
-+
-+		keys.push_back(key);
-+	}
-+
-+	return keys;
-+}
-+
-+KeyCode InputDevice::pressLevelThree(void)
-+{
-+	unsigned state, mask;
-+
-+	KeyCode keycode;
-+	XkbDescPtr xkb;
-+	XkbAction *act;
-+
-+	mask = getLevelThreeMask();
-+	if (mask == 0)
-+		return 0;
-+
-+	state = getKeyboardState();
-+	if (state & mask)
-+		return 0;
-+
-+	keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
-+	if (keycode == 0) {
-+		keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
-+		if (keycode == 0)
-+			return 0;
-+	}
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+
-+	act = XkbKeyActionPtr(xkb, keycode, state);
-+	if (act == NULL)
-+		return 0;
-+	if (act->type != XkbSA_SetMods)
-+		return 0;
-+
-+	return keycode;
-+}
-+
-+std::list<KeyCode> InputDevice::releaseLevelThree(void)
-+{
-+	unsigned state, mask;
-+	std::list<KeyCode> keys;
-+
-+	DeviceIntPtr master;
-+	XkbDescPtr xkb;
-+	unsigned int key;
-+
-+	mask = getLevelThreeMask();
-+	if (mask == 0)
-+		return keys;
-+
-+	state = getKeyboardState();
-+	if (!(state & mask))
-+		return keys;
-+
-+	master = keyboardDev->master;
-+	xkb = master->key->xkbInfo->desc;
-+	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-+		XkbAction *act;
-+		unsigned char key_mask;
-+
-+		if (!key_is_down(master, key, KEY_PROCESSED))
-+			continue;
-+
-+		act = XkbKeyActionPtr(xkb, key, state);
-+		if (act == NULL)
-+			continue;
-+
-+		if (act->type != XkbSA_SetMods)
-+			continue;
-+
-+		if (act->mods.flags & XkbSA_UseModMapMods)
-+			key_mask = xkb->map->modmap[key];
-+		else
-+			key_mask = act->mods.mask;
-+
-+		if (!(key_mask & mask))
-+			continue;
-+
-+		keys.push_back(key);
-+	}
-+
-+	return keys;
-+}
-+
-+KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state,
-+                                     unsigned *new_state)
-+{
-+	XkbDescPtr xkb;
-+	unsigned int key;
-+	KeySym ks;
-+	unsigned level_three_mask;
-+
-+	if (new_state != NULL)
-+		*new_state = state;
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+	for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-+		unsigned int state_out;
-+		KeySym dummy;
-+
-+		XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
-+		if (ks == NoSymbol)
-+			continue;
-+
-+		/*
-+		 * Despite every known piece of documentation on
-+		 * XkbTranslateKeyCode() stating that mods_rtrn returns
-+		 * the unconsumed modifiers, in reality it always
-+		 * returns the _potentially consumed_ modifiers.
-+		 */
-+		state_out = state & ~state_out;
-+		if (state_out & LockMask)
-+			XkbConvertCase(ks, &dummy, &ks);
-+
-+		if (ks == keysym)
-+			return key;
-+	}
-+
-+	if (new_state == NULL)
-+		return 0;
-+
-+	*new_state = (state & ~ShiftMask) |
-+	             ((state & ShiftMask) ? 0 : ShiftMask);
-+	key = keysymToKeycode(keysym, *new_state, NULL);
-+	if (key != 0)
-+		return key;
-+
-+	level_three_mask = getLevelThreeMask();
-+	if (level_three_mask == 0)
-+		return 0;
-+
-+	*new_state = (state & ~level_three_mask) | 
-+	             ((state & level_three_mask) ? 0 : level_three_mask);
-+	key = keysymToKeycode(keysym, *new_state, NULL);
-+	if (key != 0)
-+		return key;
-+
-+	*new_state = (state & ~(ShiftMask | level_three_mask)) | 
-+	             ((state & ShiftMask) ? 0 : ShiftMask) |
-+	             ((state & level_three_mask) ? 0 : level_three_mask);
-+	key = keysymToKeycode(keysym, *new_state, NULL);
-+	if (key != 0)
-+		return key;
-+
-+	return 0;
-+}
-+
-+bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
-+{
-+	XkbDescPtr xkb;
-+	XkbAction *act;
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+
-+	act = XkbKeyActionPtr(xkb, keycode, state);
-+	if (act == NULL)
-+		return false;
-+
-+	if (act->type != XkbSA_LockMods)
-+		return false;
-+
-+	return true;
-+}
-+
-+bool InputDevice::isAffectedByNumLock(KeyCode keycode)
-+{
-+	unsigned state;
-+
-+	KeyCode numlock_keycode;
-+	unsigned numlock_mask;
-+
-+	XkbDescPtr xkb;
-+	XkbAction *act;
-+
-+	unsigned group;
-+	XkbKeyTypeRec *type;
-+
-+	/* Group state is still important */
-+	state = getKeyboardState();
-+	state &= ~0xff;
-+
-+	/*
-+	 * Not sure if hunting for a virtual modifier called "NumLock",
-+	 * or following the keysym Num_Lock is the best approach. We
-+	 * try the latter.
-+	 */
-+	numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL);
-+	if (numlock_keycode == 0)
-+		return false;
-+
-+	xkb = keyboardDev->master->key->xkbInfo->desc;
-+
-+	act = XkbKeyActionPtr(xkb, numlock_keycode, state);
-+	if (act == NULL)
-+		return false;
-+	if (act->type != XkbSA_LockMods)
-+		return false;
-+
-+	if (act->mods.flags & XkbSA_UseModMapMods)
-+		numlock_mask = xkb->map->modmap[keycode];
-+	else
-+		numlock_mask = act->mods.mask;
-+
-+	group = XkbKeyEffectiveGroup(xkb, keycode, state);
-+	type = XkbKeyKeyType(xkb, keycode, group);
-+	if ((type->mods.mask & numlock_mask) == 0)
-+		return false;
-+
-+	return true;
-+}
-+
-+KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
-+{
-+	DeviceIntPtr master;
-+	XkbDescPtr xkb;
-+	unsigned int key;
-+
-+	XkbEventCauseRec cause;
-+	XkbChangesRec changes;
-+
-+	int types[1];
-+	KeySym *syms;
-+	KeySym upper, lower;
-+
-+	master = keyboardDev->master;
-+	xkb = master->key->xkbInfo->desc;
-+	for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
-+		if (XkbKeyNumGroups(xkb, key) == 0)
-+			break;
-+	}
-+
-+	if (key < xkb->min_key_code)
-+		return 0;
-+
-+	memset(&changes, 0, sizeof(changes));
-+	memset(&cause, 0, sizeof(cause));
-+
-+	XkbSetCauseUnknown(&cause);
-+
-+	/*
-+	 * Tools like xkbcomp get confused if there isn't a name
-+	 * assigned to the keycode we're trying to use.
-+	 */
-+	if (xkb->names && xkb->names->keys &&
-+	    (xkb->names->keys[key].name[0] == '\0')) {
-+		xkb->names->keys[key].name[0] = 'I';
-+		xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
-+		xkb->names->keys[key].name[2] = '0' + (key /  10) % 10;
-+		xkb->names->keys[key].name[3] = '0' + (key /   1) % 10;
-+
-+		changes.names.changed |= XkbKeyNamesMask;
-+		changes.names.first_key = key;
-+		changes.names.num_keys = 1;
-+	}
-+
-+	/* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */
-+
-+	/*
-+	 * For keysyms that are affected by Lock, we are better off
-+	 * using ALPHABETIC rather than ONE_LEVEL as the latter
-+	 * generally cannot produce lower case when Lock is active.
-+	 */
-+	XkbConvertCase(keysym, &lower, &upper);
-+	if (upper == lower)
-+		types[XkbGroup1Index] = XkbOneLevelIndex;
-+	else
-+		types[XkbGroup1Index] = XkbAlphabeticIndex;
-+
-+	XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);
-+
-+	syms = XkbKeySymsPtr(xkb,key);
-+	if (upper == lower)
-+		syms[0] = keysym;
-+	else {
-+		syms[0] = lower;
-+		syms[1] = upper;
-+	}
-+
-+	changes.map.changed |= XkbKeySymsMask;
-+	changes.map.first_key_sym = key;
-+	changes.map.num_key_syms = 1;
-+
-+	XkbSendNotification(master, &changes, &cause);
-+
-+	return key;
-+}
-+
-+void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
-+                                           InternalEvent *event,
-+                                           DeviceIntPtr dev)
-+{
-+	InputDevice *self = vncXkbScreenPrivate(screenInfo.screens[screenNum]);
-+	unsigned int backupctrls;
-+
-+	if (event->device_event.sourceid == self->keyboardDev->id) {
-+		XkbControlsPtr ctrls;
-+
-+		/*
-+		 * We need to bypass AccessX since it is timing sensitive and
-+		 * the network can cause fake event delays.
-+		 */
-+		ctrls = dev->key->xkbInfo->desc->ctrls;
-+		backupctrls = ctrls->enabled_ctrls;
-+		ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask;
-+
-+		/*
-+		 * This flag needs to be set for key repeats to be properly
-+		 * respected.
-+		 */
-+		if ((event->device_event.type == ET_KeyPress) &&
-+		    key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED))
-+			event->device_event.key_repeat = TRUE;
-+	}
-+
-+	dev->c_public.processInputProc(event, dev);
-+
-+	if (event->device_event.sourceid == self->keyboardDev->id) {
-+		XkbControlsPtr ctrls;
-+
-+		ctrls = dev->key->xkbInfo->desc->ctrls;
-+		ctrls->enabled_ctrls = backupctrls;
-+	}
-+}
-+
-+#endif /* XORG >= 117 */
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input	2014-01-17 16:01:04.154064515 +0000
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am	2014-01-17 16:01:13.142109459 +0000
-@@ -14,7 +14,7 @@ HDRS = RegionHelper.h vncExtInit.h vncHo
- 	Input.h
- 
- libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \
--	Input.cc
-+	Input.cc InputCore.cc InputXKB.cc
- 
- libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
- 	-DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input	2014-01-17 16:01:32.532206349 +0000
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc	2014-01-17 16:02:13.775412129 +0000
-@@ -579,6 +579,12 @@ static struct timeval XserverDesktopTime
- 
- void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
- {
-+  // We don't have a good callback for when we can init input devices[1],
-+  // so we abuse the fact that this routine will be called first thing
-+  // once the dix is done initialising.
-+  // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
-+  inputDevice->InitInputDevice();
-+
-   try {
-     int nextTimeout;
- 
diff --git a/SOURCES/tigervnc-inputreset.patch b/SOURCES/tigervnc-inputreset.patch
new file mode 100644
index 0000000..90f8663
--- /dev/null
+++ b/SOURCES/tigervnc-inputreset.patch
@@ -0,0 +1,385 @@
+diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc
+index 43c3ac3..4112fee 100644
+--- a/unix/xserver/hw/vnc/Input.cc
++++ b/unix/xserver/hw/vnc/Input.cc
+@@ -68,6 +68,9 @@ rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift pres
+ 
+ #define BUTTONS 7
+ 
++class InputDevice *vncInputDevice;
++InputDevice InputDevice::singleton;
++
+ /* Event queue is shared between all devices. */
+ #if XORG == 15
+ static xEvent *eventq = NULL;
+@@ -116,11 +119,12 @@ static void enqueueEvents(DeviceIntPtr dev, int n)
+ }
+ #endif /* XORG < 111 */
+ 
+-InputDevice::InputDevice(rfb::VNCServerST *_server)
+-	: server(_server), initialized(false), oldButtonMask(0)
++InputDevice::InputDevice()
++	: oldButtonMask(0)
+ {
+ 	int i;
+ 
++        vncInputDevice = this;
+ #if XORG < 111
+ 	initEventq();
+ #endif
+@@ -195,7 +199,7 @@ void InputDevice::PointerMove(const rfb::Point &pos)
+ 	cursorPos = pos;
+ }
+ 
+-void InputDevice::PointerSync(void)
++const rfb::Point &InputDevice::getPointerPos(void)
+ {
+ 	if (pointerDev) {
+ 		int x, y;
+@@ -205,14 +209,10 @@ void InputDevice::PointerSync(void)
+ 		cursorPos.y = y;
+ 	}
+ 
+-	if (cursorPos.equals(oldCursorPos))
+-		return;
+-
+-	oldCursorPos = cursorPos;
+-	server->setCursorPos(cursorPos);
++        return cursorPos;
+ }
+ 
+-static int pointerProc(DeviceIntPtr pDevice, int onoff)
++int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff)
+ {
+ 	BYTE map[BUTTONS + 1];
+ 	DevicePtr pDev = (DevicePtr)pDevice;
+@@ -237,6 +237,8 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff)
+ 		btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+ 		btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ 		btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
++		btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
++		btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+ 
+ 		axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+ 		axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+@@ -261,10 +263,9 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff)
+ 	case DEVICE_OFF:
+ 		pDev->on = FALSE;
+ 		break;
+-#if 0
+ 	case DEVICE_CLOSE:
++		singleton.pointerDev = NULL;
+ 		break;
+-#endif
+ 	}
+ 
+ 	return Success;
+@@ -277,9 +278,7 @@ static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl,
+ 		vncBell();
+ }
+ 
+-extern void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+-
+-static int keyboardProc(DeviceIntPtr pDevice, int onoff)
++int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff)
+ {
+ #if XORG < 17
+ 	KeySymsRec keySyms;
+@@ -306,6 +305,9 @@ static int keyboardProc(DeviceIntPtr pDevice, int onoff)
+ 	case DEVICE_OFF:
+ 		pDev->on = FALSE;
+ 		break;
++	case DEVICE_CLOSE:
++		singleton.keyboardDev = NULL;
++		break;
+ 	}
+ 
+ 	return Success;
+@@ -313,11 +315,9 @@ static int keyboardProc(DeviceIntPtr pDevice, int onoff)
+ 
+ void InputDevice::InitInputDevice(void)
+ {
+-	if (initialized)
++	if ((pointerDev != NULL) || (keyboardDev != NULL))
+ 		return;
+ 
+-	initialized = true;
+-
+ #if XORG < 17
+ 	pointerDev = AddInputDevice(
+ #if XORG >= 16
+diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h
+index e893049..f58242d 100644
+--- a/unix/xserver/hw/vnc/Input.h
++++ b/unix/xserver/hw/vnc/Input.h
+@@ -29,20 +29,26 @@
+ 
+ #include <list>
+ 
+-#include <rfb/VNCServerST.h>
++#include <rdr/types.h>
++#include <rfb/Rect.h>
+ 
+ extern "C" {
+ #include "input.h"
++/* The Xorg headers define macros that wreak havoc with STL */
++#undef max
+ };
+ 
+ #include "xorg-version.h"
+ 
+-/* Represents input device (keyboard + pointer) */
++/*
++ * Represents input device (keyboard + pointer)
++ *
++ * Is a singleton as input devices are global in the X server so
++ * we do not have one per desktop (i.e. per screen).
++ */
++extern class InputDevice *vncInputDevice;
+ class InputDevice {
+ public:
+-	/* Create new InputDevice instance */
+-	InputDevice(rfb::VNCServerST *_server);
+-
+ 	/*
+ 	 * Press or release buttons. Relationship between buttonMask and
+ 	 * buttons is specified in RFB protocol.
+@@ -52,27 +58,28 @@ public:
+ 	/* Move pointer to target location (point coords are absolute). */
+ 	void PointerMove(const rfb::Point &point);
+ 
+-	/*
+-	 * Send pointer position to clients. If not called then Move() calls
+-	 * won't be visible to VNC clients.
+-	 */
+-	void PointerSync(void);
++	/* Get current known location of the pointer */
++	const rfb::Point &getPointerPos(void);
+ 
++	/* Press or release one or more keys to get the given symbol */
+ 	void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); }
+ 	void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); }
+ 
+ 	/*
+-	 * Init input device. This cannot be done in the constructor
+-	 * because constructor is called during X server extensions
+-	 * initialization. Devices must be initialized after core
+-	 * pointer/keyboard initialization which is actually after extesions
+-	 * initialization. Check InitExtensions(), InitCoreDevices() and
+-	 * InitInput() calls in dix/main.c. Instead it is called from
+-	 * XserverDesktop at an appropriate time.
++	 * Init input device.
++	 * This has to be called after core pointer/keyboard
++	 * initialization which unfortunately is after extesions
++	 * initialization (which means we cannot call it in
++	 * vncExtensionInit(). Check InitExtensions(),
++	 * InitCoreDevices() and InitInput() calls in dix/main.c.
++	 * Instead we call it from XserverDesktop at an appropriate
++	 * time.
+ 	 */
+ 	void InitInputDevice(void);
+ 
+ private:
++	InputDevice();
++
+ 	void keyEvent(rdr::U32 keysym, bool down);
+ 
+ 	/* Backend dependent functions below here */
+@@ -96,22 +103,26 @@ private:
+ 	KeyCode addKeysym(KeySym keysym, unsigned state);
+ 
+ private:
++	static int pointerProc(DeviceIntPtr pDevice, int onoff);
++	static int keyboardProc(DeviceIntPtr pDevice, int onoff);
++
+ #if XORG >= 17
+ 	static void vncXkbProcessDeviceEvent(int screenNum,
+ 	                                     InternalEvent *event,
+ 	                                     DeviceIntPtr dev);
++#else
++	static void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+ #endif
+ 
+ private:
+-	rfb::VNCServerST *server;
+-	bool initialized;
+ 	DeviceIntPtr keyboardDev;
+ 	DeviceIntPtr pointerDev;
+ 
+ 	int oldButtonMask;
+-	rfb::Point cursorPos, oldCursorPos;
+-
++	rfb::Point cursorPos;
+ 	KeySym pressedKeys[256];
++private:
++	static InputDevice singleton;
+ };
+ 
+ #endif
+diff --git a/unix/xserver/hw/vnc/InputCore.cc b/unix/xserver/hw/vnc/InputCore.cc
+index a880ca0..b565c73 100644
+--- a/unix/xserver/hw/vnc/InputCore.cc
++++ b/unix/xserver/hw/vnc/InputCore.cc
+@@ -174,7 +174,7 @@ KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = {
+ 	XK_Menu, NoSymbol,
+ };
+ 
+-void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
++void InputDevice::GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap)
+ {
+ 	int i;
+ 
+diff --git a/unix/xserver/hw/vnc/InputXKB.cc b/unix/xserver/hw/vnc/InputXKB.cc
+index ed93afc..92288aa 100644
+--- a/unix/xserver/hw/vnc/InputXKB.cc
++++ b/unix/xserver/hw/vnc/InputXKB.cc
+@@ -42,18 +42,6 @@ extern "C" {
+ #undef class
+ }
+ 
+-#if XORG < 19
+-static int vncXkbScreenPrivateKeyIndex;
+-static DevPrivateKey vncXkbScreenPrivateKey = &vncXkbScreenPrivateKeyIndex;
+-#else
+-static DevPrivateKeyRec vncXkbPrivateKeyRec;
+-#define vncXkbScreenPrivateKey (&vncXkbPrivateKeyRec)
+-#endif
+-
+-#define vncXkbScreenPrivate(pScreen) \
+-	(*(InputDevice**) dixLookupPrivate(&(pScreen)->devPrivates, \
+-	                                   vncXkbScreenPrivateKey))
+-
+ #ifndef KEYBOARD_OR_FLOAT
+ #define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
+ #endif
+@@ -209,18 +197,6 @@ static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int m
+ 
+ void InputDevice::PrepareInputDevices(void)
+ {
+-#if XORG < 19
+-	if (!dixRequestPrivate(vncXkbScreenPrivateKey, sizeof(InputDevice*)))
+-		FatalError("Failed to register TigerVNC XKB screen key\n");
+-#else
+-	if (!dixRegisterPrivateKey(vncXkbScreenPrivateKey, PRIVATE_SCREEN,
+-	                           sizeof(InputDevice*)))
+-		FatalError("Failed to register TigerVNC XKB screen key\n");
+-#endif
+-
+-	for (int scr = 0; scr < screenInfo.numScreens; scr++)
+-		vncXkbScreenPrivate(screenInfo.screens[scr]) = this;
+-
+ 	/*
+ 	 * Not ideal since these callbacks do not stack, but it's the only
+ 	 * decent way we can reliably catch events for both the slave and
+@@ -636,10 +612,9 @@ void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
+                                            InternalEvent *event,
+                                            DeviceIntPtr dev)
+ {
+-	InputDevice *self = vncXkbScreenPrivate(screenInfo.screens[screenNum]);
+ 	unsigned int backupctrls;
+ 
+-	if (event->device_event.sourceid == self->keyboardDev->id) {
++	if (event->device_event.sourceid == singleton.keyboardDev->id) {
+ 		XkbControlsPtr ctrls;
+ 
+ 		/*
+@@ -661,7 +636,7 @@ void InputDevice::vncXkbProcessDeviceEvent(int screenNum,
+ 
+ 	dev->c_public.processInputProc(event, dev);
+ 
+-	if (event->device_event.sourceid == self->keyboardDev->id) {
++	if (event->device_event.sourceid == singleton.keyboardDev->id) {
+ 		XkbControlsPtr ctrls;
+ 
+ 		ctrls = dev->key->xkbInfo->desc->ctrls;
+diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
+index fc0646d..05169b0 100644
+--- a/unix/xserver/hw/vnc/XserverDesktop.cc
++++ b/unix/xserver/hw/vnc/XserverDesktop.cc
+@@ -157,15 +157,12 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
+ 
+   if (httpListener)
+     httpServer = new FileHTTPServer(this);
+-
+-  inputDevice = new InputDevice(server);
+ }
+ 
+ XserverDesktop::~XserverDesktop()
+ {
+   if (!directFbptr)
+     delete [] data;
+-  delete inputDevice;
+   delete httpServer;
+   delete server;
+ }
+@@ -583,7 +580,7 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
+   // so we abuse the fact that this routine will be called first thing
+   // once the dix is done initialising.
+   // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing.
+-  inputDevice->InitInputDevice();
++  vncInputDevice->InitInputDevice();
+ 
+   try {
+     int nextTimeout;
+@@ -691,7 +688,11 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
+         }
+       }
+ 
+-      inputDevice->PointerSync();
++      // We are responsible for propagating mouse movement between clients
++      if (!oldCursorPos.equals(vncInputDevice->getPointerPos())) {
++        oldCursorPos = vncInputDevice->getPointerPos();
++        server->setCursorPos(oldCursorPos);
++      }
+     }
+ 
+     // Then let the timers do some processing. Rescheduling is done in
+@@ -818,8 +819,8 @@ void XserverDesktop::approveConnection(void* opaqueId, bool accept,
+ 
+ void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
+ {
+-  inputDevice->PointerMove(pos);
+-  inputDevice->PointerButtonAction(buttonMask);
++  vncInputDevice->PointerMove(pos);
++  vncInputDevice->PointerButtonAction(buttonMask);
+ }
+ 
+ void XserverDesktop::clientCutText(const char* str, int len)
+@@ -1136,7 +1137,7 @@ void XserverDesktop::lookup(int index, int* r, int* g, int* b)
+ void XserverDesktop::keyEvent(rdr::U32 keysym, bool down)
+ {
+ 	if (down)
+-		inputDevice->KeyboardPress(keysym);
++		vncInputDevice->KeyboardPress(keysym);
+ 	else
+-		inputDevice->KeyboardRelease(keysym);
++		vncInputDevice->KeyboardRelease(keysym);
+ }
+diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
+index fb247b0..ca6e8af 100644
+--- a/unix/xserver/hw/vnc/XserverDesktop.h
++++ b/unix/xserver/hw/vnc/XserverDesktop.h
+@@ -153,5 +153,7 @@ private:
+   typedef std::map<RROutputPtr, rdr::U32> OutputIdMap;
+   OutputIdMap outputIdMap;
+ #endif
++
++  rfb::Point oldCursorPos;
+ };
+ #endif
+diff --git a/unix/xserver/hw/vnc/xf86vncModule.cc b/unix/xserver/hw/vnc/xf86vncModule.cc
+index 3187bba..596d399 100644
+--- a/unix/xserver/hw/vnc/xf86vncModule.cc
++++ b/unix/xserver/hw/vnc/xf86vncModule.cc
+@@ -112,9 +112,9 @@ static void vncExtensionInitWithParams(INITARGS)
+           i.param->setParam(val);
+       }
+     }
+-
+-    vncExtensionInit();
+   }
++
++  vncExtensionInit();
+ }
+ }
+ 
diff --git a/SOURCES/tigervnc-ipv6-support.patch b/SOURCES/tigervnc-ipv6-support.patch
new file mode 100644
index 0000000..083cc7c
--- /dev/null
+++ b/SOURCES/tigervnc-ipv6-support.patch
@@ -0,0 +1,1708 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index f2656d1..0e325e2 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -71,16 +71,9 @@ if(NOT DEFINED BUILD_WINVNC)
+   set(BUILD_WINVNC 1)
+ endif()
+ 
+-# Minimum version is Windows 2000 (5.0)
++# Minimum version is Windows XP SP2 (5.2)
+ if(WIN32)
+-  if(NOT CMAKE_SIZEOF_VOID_P MATCHES 8)
+-    add_definitions(-D_WIN32_IE=0x0500 -D_WIN32_WINNT=0x0500)
+-  else()
+-    set(WIN64 1)
+-    # Win64 doesn't like us requesting a Windows version that didn't have
+-    # 64-bit support. Request XP (5.1) instead.
+-    add_definitions(-D_WIN32_IE=0x0501 -D_WIN32_WINNT=0x0501)
+-  endif()
++  add_definitions(-D_WIN32_IE=0x0502 -D_WIN32_WINNT=0x0502)
+ endif()
+ 
+ if(CMAKE_SIZEOF_VOID_P MATCHES 8)
+@@ -366,20 +359,6 @@ if(ENABLE_PAM)
+ endif()
+ set(HAVE_PAM ${ENABLE_PAM})
+ 
+-# Check for socket functions
+-if(WIN32)
+-  set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h ws2tcpip.h)
+-  set(CMAKE_REQUIRED_LIBRARIES ws2_32)
+-else()
+-  set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+-endif()
+-check_function_exists(inet_aton HAVE_INET_ATON)
+-check_function_exists(inet_ntop HAVE_INET_NTOP)
+-check_function_exists(getaddrinfo HAVE_GETADDRINFO)
+-check_type_size(socklen_t SOCKLEN_T)
+-set(CMAKE_EXTRA_INCLUDE_FILES) 
+-set(CMAKE_REQUIRED_LIBRARIES)
+-
+ # Check for the newer standard string functions
+ check_function_exists(snprintf HAVE_SNPRINTF)
+ check_function_exists(strcasecmp HAVE_STRCASECMP)
+diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
+index afd66f9..83387ab 100644
+--- a/common/network/TcpSocket.cxx
++++ b/common/network/TcpSocket.cxx
+@@ -31,10 +31,8 @@
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+-#include <netinet/in.h>
+ #include <netinet/tcp.h>
+ #include <netdb.h>
+-#include <unistd.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <signal.h>
+@@ -42,10 +40,15 @@
+ #endif
+ 
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <network/TcpSocket.h>
+-#include <os/net.h>
+ #include <rfb/util.h>
+ #include <rfb/LogWriter.h>
++#include <rfb/Configuration.h>
++
++#ifdef WIN32
++#include <os/winerrno.h>
++#endif
+ 
+ #ifndef INADDR_NONE
+ #define INADDR_NONE ((unsigned long)-1)
+@@ -54,26 +57,24 @@
+ #define INADDR_LOOPBACK ((unsigned long)0x7F000001)
+ #endif
+ 
+-#if defined(HAVE_GETADDRINFO) && !defined(IN6_ARE_ADDR_EQUAL)
++#ifndef IN6_ARE_ADDR_EQUAL
+ #define IN6_ARE_ADDR_EQUAL(a,b) \
+   (memcmp ((const void*)(a), (const void*)(b), sizeof (struct in6_addr)) == 0)
+ #endif
+ 
++// Missing on older Windows and OS X
++#ifndef AI_NUMERICSERV
++#define AI_NUMERICSERV 0
++#endif
++
+ using namespace network;
+ using namespace rdr;
+ 
+-typedef struct vnc_sockaddr {
+-	union {
+-		sockaddr	sa;
+-		sockaddr_in	sin;
+-#ifdef HAVE_GETADDRINFO
+-		sockaddr_in6	sin6;
+-#endif
+-	} u;
+-} vnc_sockaddr_t;
+-
+ static rfb::LogWriter vlog("TcpSocket");
+ 
++static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
++static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
++
+ /* Tunnelling support. */
+ int network::findFreeTcpPort (void)
+ {
+@@ -117,6 +118,23 @@ static void initSockets() {
+ }
+ 
+ 
++// -=- Socket duplication help for Windows
++static int dupsocket(int fd)
++{
++#ifdef WIN32
++  int ret;
++  WSAPROTOCOL_INFO info;
++  ret = WSADuplicateSocket(fd, GetCurrentProcessId(), &info);
++  if (ret != 0)
++    throw SocketException("unable to duplicate socket", errorNumber);
++  return WSASocket(info.iAddressFamily, info.iSocketType, info.iProtocol,
++                   &info, 0, 0);
++#else
++  return dup(fd);
++#endif
++}
++
++
+ // -=- TcpSocket
+ 
+ TcpSocket::TcpSocket(int sock, bool close)
+@@ -130,14 +148,11 @@ TcpSocket::TcpSocket(const char *host, int port)
+   int sock, err, result, family;
+   vnc_sockaddr_t sa;
+   socklen_t salen;
+-#ifdef HAVE_GETADDRINFO
+   struct addrinfo *ai, *current, hints;
+-#endif
+ 
+   // - Create a socket
+   initSockets();
+ 
+-#ifdef HAVE_GETADDRINFO
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = AF_UNSPEC;
+   hints.ai_socktype = SOCK_STREAM;
+@@ -147,13 +162,28 @@ TcpSocket::TcpSocket(const char *host, int port)
+ 
+   if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
+     throw Exception("unable to resolve host by name: %s",
+-		    gai_strerror(result));
++                    gai_strerror(result));
+   }
+ 
++  // This logic is too complex for the compiler to determine if
++  // sock is properly assigned or not.
++  sock = -1;
++
+   for (current = ai; current != NULL; current = current->ai_next) {
+     family = current->ai_family;
+-    if (family != AF_INET && family != AF_INET6)
++
++    switch (family) {
++    case AF_INET:
++      if (!UseIPv4)
++        continue;
++      break;
++    case AF_INET6:
++      if (!UseIPv6)
++        continue;
++      break;
++    default:
+       continue;
++    }
+ 
+     salen = current->ai_addrlen;
+     memcpy(&sa, current->ai_addr, salen);
+@@ -163,34 +193,10 @@ TcpSocket::TcpSocket(const char *host, int port)
+     else
+       sa.u.sin6.sin6_port = htons(port);
+ 
+-#else /* HAVE_GETADDRINFO */
+-    family = AF_INET;
+-    salen = sizeof(struct sockaddr_in);
+-
+-    /* Try processing the host as an IP address */
+-    memset(&sa, 0, sizeof(sa));
+-    sa.u.sin.sin_family = AF_INET;
+-    sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
+-    sa.u.sin.sin_port = htons(port);
+-    if ((int)sa.u.sin.sin_addr.s_addr == -1) {
+-      /* Host was not an IP address - try resolving as DNS name */
+-      struct hostent *hostinfo;
+-      hostinfo = gethostbyname((char *)host);
+-      if (hostinfo && hostinfo->h_addr) {
+-        sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
+-      } else {
+-        err = errorNumber;
+-        throw SocketException("unable to resolve host by name", err);
+-      }
+-    }
+-#endif /* HAVE_GETADDRINFO */
+-
+     sock = socket (family, SOCK_STREAM, 0);
+     if (sock == -1) {
+       err = errorNumber;
+-#ifdef HAVE_GETADDRINFO
+       freeaddrinfo(ai);
+-#endif /* HAVE_GETADDRINFO */
+       throw SocketException("unable to create socket", err);
+     }
+ 
+@@ -199,19 +205,20 @@ TcpSocket::TcpSocket(const char *host, int port)
+       err = errorNumber;
+ #ifndef WIN32
+       if (err == EINTR)
+-	continue;
++        continue;
+ #endif
+       closesocket(sock);
+       break;
+     }
+ 
+-#ifdef HAVE_GETADDRINFO
+     if (result == 0)
+       break;
+   }
+ 
+   freeaddrinfo(ai);
+-#endif /* HAVE_GETADDRINFO */
++
++  if (current == NULL)
++    throw Exception("No useful address for host");
+ 
+   if (result == -1)
+     throw SocketException("unable connect to socket", err);
+@@ -240,27 +247,63 @@ int TcpSocket::getMyPort() {
+ }
+ 
+ char* TcpSocket::getPeerAddress() {
+-  struct sockaddr_in  info;
+-  struct in_addr    addr;
+-  socklen_t info_size = sizeof(info);
++  vnc_sockaddr_t sa;
++  socklen_t sa_size = sizeof(sa);
+ 
+-  getpeername(getFd(), (struct sockaddr *)&info, &info_size);
+-  memcpy(&addr, &info.sin_addr, sizeof(addr));
++  if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
++    vlog.error("unable to get peer name for socket");
++    return rfb::strDup("");
++  }
++
++  if (sa.u.sa.sa_family == AF_INET6) {
++    char buffer[INET6_ADDRSTRLEN + 2];
++    int ret;
++
++    buffer[0] = '[';
++
++    ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
++                      buffer + 1, sizeof(buffer) - 2, NULL, 0,
++                      NI_NUMERICHOST);
++    if (ret != 0) {
++      vlog.error("unable to convert peer name to a string");
++      return rfb::strDup("");
++    }
++
++    strcat(buffer, "]");
++
++    return rfb::strDup(buffer);
++  }
++
++  if (sa.u.sa.sa_family == AF_INET) {
++    char *name;
++
++    name = inet_ntoa(sa.u.sin.sin_addr);
++    if (name == NULL) {
++      vlog.error("unable to convert peer name to a string");
++      return rfb::strDup("");
++    }
+ 
+-  char* name = inet_ntoa(addr);
+-  if (name) {
+     return rfb::strDup(name);
+-  } else {
+-    return rfb::strDup("");
+   }
++
++  vlog.error("unknown address family for socket");
++  return rfb::strDup("");
+ }
+ 
+ int TcpSocket::getPeerPort() {
+-  struct sockaddr_in  info;
+-  socklen_t info_size = sizeof(info);
++  vnc_sockaddr_t sa;
++  socklen_t sa_size = sizeof(sa);
++
++  getpeername(getFd(), &sa.u.sa, &sa_size);
+ 
+-  getpeername(getFd(), (struct sockaddr *)&info, &info_size);
+-  return ntohs(info.sin_port);
++  switch (sa.u.sa.sa_family) {
++  case AF_INET6:
++    return ntohs(sa.u.sin6.sin6_port);
++  case AF_INET:
++    return ntohs(sa.u.sin.sin_port);
++  default:
++    return 0;
++  }
+ }
+ 
+ char* TcpSocket::getPeerEndpoint() {
+@@ -288,13 +331,14 @@ bool TcpSocket::sameMachine() {
+   if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
+       return false;
+ 
+-#ifdef HAVE_GETADDRINFO
+   if (peeraddr.u.sa.sa_family == AF_INET6)
+       return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
+-				&myaddr.u.sin6.sin6_addr);
+-#endif
++                                &myaddr.u.sin6.sin6_addr);
++  if (peeraddr.u.sa.sa_family == AF_INET)
++    return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
+ 
+-  return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
++  // No idea what this is. Assume we're on different machines.
++  return false;
+ }
+ 
+ void TcpSocket::shutdown()
+@@ -306,7 +350,7 @@ void TcpSocket::shutdown()
+ bool TcpSocket::enableNagles(int sock, bool enable) {
+   int one = enable ? 0 : 1;
+   if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+-		 (char *)&one, sizeof(one)) < 0) {
++                 (char *)&one, sizeof(one)) < 0) {
+     int e = errorNumber;
+     vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
+     return false;
+@@ -335,77 +379,89 @@ bool TcpSocket::isListening(int sock)
+ 
+ int TcpSocket::getSockPort(int sock)
+ {
+-  struct sockaddr_in info;
+-  socklen_t info_size = sizeof(info);
+-  if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
+-    return 0;
+-  return ntohs(info.sin_port);
++  vnc_sockaddr_t sa;
++  socklen_t sa_size = sizeof(sa);
++  if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
++     return 0;
++
++  switch (sa.u.sa.sa_family) {
++  case AF_INET6:
++    return ntohs(sa.u.sin6.sin6_port);
++  default:
++    return ntohs(sa.u.sin.sin_port);
++  }
+ }
+ 
++TcpListener::TcpListener(int sock)
++{
++  fd = sock;
++}
+ 
+-TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly,
+-			 int sock, bool close_) : closeFd(close_)
++TcpListener::TcpListener(const TcpListener& other)
+ {
+-  if (sock != -1) {
+-    fd = sock;
+-    return;
++  fd = dupsocket (other.fd);
++  // Hope TcpListener::shutdown(other) doesn't get called...
++}
++
++TcpListener& TcpListener::operator= (const TcpListener& other)
++{
++  if (this != &other)
++  {
++    closesocket (fd);
++    fd = dupsocket (other.fd);
++    // Hope TcpListener::shutdown(other) doesn't get called...
+   }
++  return *this;
++}
++
++TcpListener::TcpListener(const struct sockaddr *listenaddr,
++                         socklen_t listenaddrlen)
++{
++  int one = 1;
++  vnc_sockaddr_t sa;
++  int sock;
+ 
+   initSockets();
+-  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+-    throw SocketException("unable to create listening socket", errorNumber);
+ 
++  if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
++     throw SocketException("unable to create listening socket", errorNumber);
++
++  memcpy (&sa, listenaddr, listenaddrlen);
++#ifdef IPV6_V6ONLY
++  if (listenaddr->sa_family == AF_INET6) {
++    if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
++      throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
++  }
++#endif /* defined(IPV6_V6ONLY) */
++
++  if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
++    closesocket(sock);
++    throw SocketException("failed to bind socket", errorNumber);
++  }
+ #ifndef WIN32
+   // - By default, close the socket on exec()
+-  fcntl(fd, F_SETFD, FD_CLOEXEC);
++  fcntl(sock, F_SETFD, FD_CLOEXEC);
+ 
+-  int one = 1;
+-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+-		 (char *)&one, sizeof(one)) < 0) {
++  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
++                 (char *)&one, sizeof(one)) < 0) {
+     int e = errorNumber;
+-    closesocket(fd);
++    closesocket(sock);
+     throw SocketException("unable to create listening socket", e);
+   }
+-#endif
+-
+-  // - Bind it to the desired port
+-  struct sockaddr_in addr;
+-  memset(&addr, 0, sizeof(addr));
+-  addr.sin_family = AF_INET;
+ 
+-  if (localhostOnly) {
+-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+-  } else if (listenaddr != NULL) {
+-#ifdef HAVE_INET_ATON
+-    if (inet_aton(listenaddr, &addr.sin_addr) == 0)
+-#else
+-    /* Some systems (e.g. Windows) do not have inet_aton, sigh */
+-    if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE)
++  fd = sock;
+ #endif
+-    {
+-      closesocket(fd);
+-      throw Exception("invalid network interface address: %s", listenaddr);
+-    }
+-  } else
+-    addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to 0.0.0.0 by default. */
+-
+-  addr.sin_port = htons(port);
+-  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+-    int e = errorNumber;
+-    closesocket(fd);
+-    throw SocketException("unable to bind listening socket", e);
+-  }
+ 
+   // - Set it to be a listening socket
+-  if (listen(fd, 5) < 0) {
++  if (listen(sock, 5) < 0) {
+     int e = errorNumber;
+-    closesocket(fd);
++    closesocket(sock);
+     throw SocketException("unable to set socket to listening mode", e);
+   }
+ }
+ 
+ TcpListener::~TcpListener() {
+-  if (closeFd) closesocket(fd);
++  closesocket(fd);
+ }
+ 
+ void TcpListener::shutdown()
+@@ -444,17 +500,45 @@ TcpListener::accept() {
+ }
+ 
+ void TcpListener::getMyAddresses(std::list<char*>* result) {
+-  const hostent* addrs = gethostbyname(0);
+-  if (addrs == 0)
+-    throw rdr::SystemException("gethostbyname", errorNumber);
+-  if (addrs->h_addrtype != AF_INET)
+-    throw rdr::Exception("getMyAddresses: bad family");
+-  for (int i=0; addrs->h_addr_list[i] != 0; i++) {
+-    const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
+-    char* addr = new char[strlen(addrC)+1];
+-    strcpy(addr, addrC);
++  struct addrinfo *ai, *current, hints;
++
++  initSockets();
++
++  memset(&hints, 0, sizeof(struct addrinfo));
++  hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
++  hints.ai_family = AF_UNSPEC;
++  hints.ai_socktype = SOCK_STREAM;
++  hints.ai_canonname = NULL;
++  hints.ai_addr = NULL;
++  hints.ai_next = NULL;
++
++  // Windows doesn't like NULL for service, so specify something
++  if ((getaddrinfo(NULL, "1", &hints, &ai)) != 0)
++    return;
++
++  for (current= ai; current != NULL; current = current->ai_next) {
++    switch (current->ai_family) {
++    case AF_INET:
++      if (!UseIPv4)
++        continue;
++      break;
++    case AF_INET6:
++      if (!UseIPv6)
++        continue;
++      break;
++    default:
++      continue;
++    }
++
++    char *addr = new char[INET6_ADDRSTRLEN];
++
++    getnameinfo(current->ai_addr, current->ai_addrlen, addr, INET6_ADDRSTRLEN,
++                NULL, 0, NI_NUMERICHOST);
++
+     result->push_back(addr);
+   }
++
++  freeaddrinfo(ai);
+ }
+ 
+ int TcpListener::getMyPort() {
+@@ -462,6 +546,115 @@ int TcpListener::getMyPort() {
+ }
+ 
+ 
++void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
++                                      int port)
++{
++  std::list<TcpListener> new_listeners;
++  vnc_sockaddr_t sa;
++
++  initSockets();
++
++  if (UseIPv6) {
++    sa.u.sin6.sin6_family = AF_INET6;
++    sa.u.sin6.sin6_port = htons (port);
++    sa.u.sin6.sin6_addr = in6addr_loopback;
++    try {
++      new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
++    } catch (SocketException& e) {
++      // Ignore this if it is due to lack of address family support on
++      // the interface or on the system
++      if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
++        // Otherwise, report the error
++        throw;
++    }
++  }
++  if (UseIPv4) {
++    sa.u.sin.sin_family = AF_INET;
++    sa.u.sin.sin_port = htons (port);
++    sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
++    try {
++      new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
++    } catch (SocketException& e) {
++      // Ignore this if it is due to lack of address family support on
++      // the interface or on the system
++      if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
++        // Otherwise, report the error
++        throw;
++    }
++  }
++
++  if (new_listeners.empty ())
++    throw SocketException("createLocalTcpListeners: no addresses available",
++                          EADDRNOTAVAIL);
++
++  listeners->splice (listeners->end(), new_listeners);
++}
++
++void network::createTcpListeners(std::list<TcpListener> *listeners,
++                                 const char *addr,
++                                 int port)
++{
++  std::list<TcpListener> new_listeners;
++
++  struct addrinfo *ai, *current, hints;
++  char service[16];
++  int result;
++
++  initSockets();
++
++  memset(&hints, 0, sizeof(struct addrinfo));
++  hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
++  hints.ai_family = AF_UNSPEC;
++  hints.ai_socktype = SOCK_STREAM;
++  hints.ai_canonname = NULL;
++  hints.ai_addr = NULL;
++  hints.ai_next = NULL;
++
++  snprintf (service, sizeof (service) - 1, "%d", port);
++  service[sizeof (service) - 1] = '\0';
++  if ((result = getaddrinfo(addr, service, &hints, &ai)) != 0)
++    throw rdr::Exception("unable to resolve listening address: %s",
++                         gai_strerror(result));
++
++  for (current = ai; current != NULL; current = current->ai_next) {
++    switch (current->ai_family) {
++    case AF_INET:
++      if (!UseIPv4)
++        continue;
++      break;
++
++    case AF_INET6:
++      if (!UseIPv6)
++        continue;
++      break;
++
++    default:
++      continue;
++    }
++
++    try {
++      new_listeners.push_back(TcpListener (current->ai_addr,
++                                           current->ai_addrlen));
++    } catch (SocketException& e) {
++      // Ignore this if it is due to lack of address family support on
++      // the interface or on the system
++      if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
++        // Otherwise, report the error
++        freeaddrinfo(ai);
++        throw;
++      }
++    }
++  }
++  freeaddrinfo(ai);
++
++  if (new_listeners.empty ())
++    throw SocketException("createTcpListeners: no addresses available",
++                          EADDRNOTAVAIL);
++
++  listeners->splice (listeners->end(), new_listeners);
++}
++
++
+ TcpFilter::TcpFilter(const char* spec) {
+   rfb::CharArray tmp;
+   tmp.buf = rfb::strDup(spec);
+@@ -478,20 +671,69 @@ TcpFilter::~TcpFilter() {
+ 
+ 
+ static bool
+-patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
+-  unsigned long address = inet_addr((char *)value);
+-  if (address == INADDR_NONE) return false;
+-  return ((pattern.address & pattern.mask) == (address & pattern.mask));
++patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
++  switch (pattern.address.u.sa.sa_family) {
++    unsigned long address;
++
++  case AF_INET:
++    if (sa->u.sa.sa_family != AF_INET)
++      return false;
++
++    address = sa->u.sin.sin_addr.s_addr;
++    if (address == htonl (INADDR_NONE)) return false;
++    return ((pattern.address.u.sin.sin_addr.s_addr &
++             pattern.mask.u.sin.sin_addr.s_addr) ==
++            (address & pattern.mask.u.sin.sin_addr.s_addr));
++
++  case AF_INET6:
++    if (sa->u.sa.sa_family != AF_INET6)
++      return false;
++
++    for (unsigned int n = 0; n < 16; n++) {
++      unsigned int bits = (n + 1) * 8;
++      unsigned int mask;
++      if (pattern.prefixlen > bits)
++        mask = 0xff;
++      else {
++        unsigned int lastbits = 0xff;
++        lastbits <<= bits - pattern.prefixlen;
++        mask = lastbits & 0xff;
++      }
++
++      if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
++          (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
++        return false;
++
++      if (mask < 0xff)
++        break;
++    }
++
++    return true;
++
++  case AF_UNSPEC:
++    // Any address matches
++    return true;
++
++  default:
++    break;
++  }
++
++  return false;
+ }
+ 
+ bool
+ TcpFilter::verifyConnection(Socket* s) {
+   rfb::CharArray name;
++  vnc_sockaddr_t sa;
++  socklen_t sa_size = sizeof(sa);
++
++  if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
++    return false;
+ 
+   name.buf = s->getPeerAddress();
+   std::list<TcpFilter::Pattern>::iterator i;
+   for (i=filter.begin(); i!=filter.end(); i++) {
+-    if (patternMatchIP(*i, name.buf)) {
++    if (patternMatchIP(*i, &sa)) {
+       switch ((*i).action) {
+       case Accept:
+         vlog.debug("ACCEPT %s", name.buf);
+@@ -515,31 +757,102 @@ TcpFilter::verifyConnection(Socket* s) {
+ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
+   TcpFilter::Pattern pattern;
+ 
+-  bool expandMask = false;
+-  rfb::CharArray addr, mask;
++  rfb::CharArray addr, pref;
++  bool prefix_specified;
++  int family;
++
++  prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
++  if (addr.buf[0] == '\0') {
++    // Match any address
++    memset (&pattern.address, 0, sizeof (pattern.address));
++    pattern.address.u.sa.sa_family = AF_UNSPEC;
++    pattern.prefixlen = 0;
++  } else {
++    struct addrinfo hints;
++    struct addrinfo *ai;
++    char *p = addr.buf;
++    int result;
++    memset (&hints, 0, sizeof (hints));
++    hints.ai_family = AF_UNSPEC;
++    hints.ai_flags = AI_NUMERICHOST;
++
++    // Take out brackets, if present
++    if (*p == '[') {
++      size_t len;
++      p++;
++      len = strlen (p);
++      if (len > 0 && p[len - 1] == ']')
++        p[len - 1] = '\0';
++    }
++
++    if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
++      throw Exception("unable to resolve host by name: %s",
++                      gai_strerror(result));
++    }
+ 
+-  if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
+-    if (rfb::strContains(mask.buf, '.')) {
+-      pattern.mask = inet_addr(mask.buf);
++    memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
++    freeaddrinfo (ai);
++
++    family = pattern.address.u.sa.sa_family;
++
++    if (prefix_specified) {
++      if (family == AF_INET &&
++          rfb::strContains(pref.buf, '.')) {
++        throw Exception("mask no longer supported for filter, "
++                        "use prefix instead");
++      }
++
++      pattern.prefixlen = (unsigned int) atoi(pref.buf);
+     } else {
+-      pattern.mask = atoi(mask.buf);
+-      expandMask = true;
++      switch (family) {
++      case AF_INET:
++        pattern.prefixlen = 32;
++        break;
++      case AF_INET6:
++        pattern.prefixlen = 128;
++        break;
++      default:
++        throw Exception("unknown address family");
++      }
+     }
+-  } else {
+-    pattern.mask = 32;
+-    expandMask = true;
+-  }
+-  if (expandMask) {
+-    unsigned long expanded = 0;
+-    // *** check endianness!
+-    for (int i=0; i<(int)pattern.mask; i++)
+-      expanded |= 1<<(31-i);
+-    pattern.mask = htonl(expanded);
+   }
+ 
+-  pattern.address = inet_addr(addr.buf) & pattern.mask;
+-  if ((pattern.address == INADDR_NONE) ||
+-      (pattern.address == 0)) pattern.mask = 0;
++  family = pattern.address.u.sa.sa_family;
++
++  if (pattern.prefixlen > (family == AF_INET ? 32: 128))
++    throw Exception("invalid prefix length for filter address: %u",
++                    pattern.prefixlen);
++
++  // Compute mask from address and prefix length
++  memset (&pattern.mask, 0, sizeof (pattern.mask));
++  switch (family) {
++    unsigned long mask;
++  case AF_INET:
++    mask = 0;
++    for (unsigned int i=0; i<pattern.prefixlen; i++)
++      mask |= 1<<(31-i);
++    pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
++    break;
++
++  case AF_INET6:
++    for (unsigned int n = 0; n < 16; n++) {
++      unsigned int bits = (n + 1) * 8;
++      if (pattern.prefixlen > bits)
++        pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
++      else {
++        unsigned int lastbits = 0xff;
++        lastbits <<= bits - pattern.prefixlen;
++        pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
++        break;
++      }
++    }
++    break;
++  case AF_UNSPEC:
++    // No mask to compute
++    break;
++  default:
++    ; /* not reached */
++  }
+ 
+   switch(p[0]) {
+   case '+': pattern.action = TcpFilter::Accept; break;
+@@ -551,21 +864,39 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
+ }
+ 
+ char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
+-  in_addr tmp;
+-  rfb::CharArray addr, mask;
+-  tmp.s_addr = p.address;
+-  addr.buf = rfb::strDup(inet_ntoa(tmp));
+-  tmp.s_addr = p.mask;
+-  mask.buf = rfb::strDup(inet_ntoa(tmp));
+-  char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
++  rfb::CharArray addr;
++  char buffer[INET6_ADDRSTRLEN + 2];
++
++  if (p.address.u.sa.sa_family == AF_INET) {
++    getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
++                buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
++    addr.buf = rfb::strDup(buffer);
++  } else if (p.address.u.sa.sa_family == AF_INET6) {
++    buffer[0] = '[';
++    getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
++                buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
++    strcat(buffer, "]");
++    addr.buf = rfb::strDup(buffer);
++  } else if (p.address.u.sa.sa_family == AF_UNSPEC)
++    addr.buf = rfb::strDup("");
++
++  char action;
+   switch (p.action) {
+-  case Accept: result[0] = '+'; break;
+-  case Reject: result[0] = '-'; break;
+-  case Query: result[0] = '?'; break;
++  case Accept: action = '+'; break;
++  case Reject: action = '-'; break;
++  default:
++  case Query: action = '?'; break;
+   };
+-  result[1] = 0;
+-  strcat(result, addr.buf);
+-  strcat(result, "/");
+-  strcat(result, mask.buf);
++  size_t resultlen = (1                   // action
++                      + strlen (addr.buf) // address
++                      + 1                 // slash
++                      + 3                 // prefix length, max 128
++                      + 1);               // terminating nul
++  char* result = new char[resultlen];
++  if (addr.buf[0] == '\0')
++    snprintf(result, resultlen, "%c", action);
++  else
++    snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
++
+   return result;
+ }
+diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
+index cd4393e..3f72c85 100644
+--- a/common/network/TcpSocket.h
++++ b/common/network/TcpSocket.h
+@@ -30,6 +30,14 @@
+ 
+ #include <network/Socket.h>
+ 
++#ifdef WIN32
++#include <winsock2.h>
++#include <ws2tcpip.h>
++#else
++#include <sys/socket.h> /* for socklen_t */
++#include <netinet/in.h> /* for struct sockaddr_in */
++#endif
++
+ #include <list>
+ 
+ /* Tunnelling support. */
+@@ -65,20 +73,33 @@ namespace network {
+ 
+   class TcpListener : public SocketListener {
+   public:
+-    TcpListener(const char *listenaddr, int port, bool localhostOnly=false,
+-		int sock=-1, bool close=true);
++    TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen);
++    TcpListener(int sock);
++    TcpListener(const TcpListener& other);
++    TcpListener& operator= (const TcpListener& other);
+     virtual ~TcpListener();
+ 
+     virtual void shutdown();
+     virtual Socket* accept();
+ 
+-    void getMyAddresses(std::list<char*>* addrs);
++    static void getMyAddresses(std::list<char*>* result);
+     int getMyPort();
+-
+-  private:
+-    bool closeFd;
+   };
+ 
++  void createLocalTcpListeners(std::list<TcpListener> *listeners,
++                               int port);
++  void createTcpListeners(std::list<TcpListener> *listeners,
++                          const char *addr,
++                          int port);
++
++  typedef struct vnc_sockaddr {
++    union {
++      sockaddr     sa;
++      sockaddr_in  sin;
++      sockaddr_in6 sin6;
++    } u;
++  } vnc_sockaddr_t;
++
+   class TcpFilter : public ConnectionFilter {
+   public:
+     TcpFilter(const char* filter);
+@@ -89,8 +110,10 @@ namespace network {
+     typedef enum {Accept, Reject, Query} Action;
+     struct Pattern {
+       Action action;
+-      unsigned long address;
+-      unsigned long mask;
++      vnc_sockaddr_t address;
++      unsigned int prefixlen;
++
++      vnc_sockaddr_t mask; // computed from address and prefix
+     };
+     static Pattern parsePattern(const char* s);
+     static char* patternToStr(const Pattern& p);
+diff --git a/common/os/CMakeLists.txt b/common/os/CMakeLists.txt
+index 39d5c10..cd066f8 100644
+--- a/common/os/CMakeLists.txt
++++ b/common/os/CMakeLists.txt
+@@ -2,7 +2,6 @@ include_directories(${CMAKE_SOURCE_DIR}/common)
+ 
+ add_library(os STATIC
+   print.c
+-  net.c
+   w32tiger.c
+   os.cxx
+   tls.cxx)
+diff --git a/common/os/net.c b/common/os/net.c
+deleted file mode 100644
+index 7bad36c..0000000
+--- a/common/os/net.c
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/* Copyright (C) 2008 TightVNC Team.  All Rights Reserved.
+- *
+- * This is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- * 
+- * This software is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- * 
+- * You should have received a copy of the GNU General Public License
+- * along with this software; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+- * USA.
+- */
+-
+-#ifdef HAVE_CONFIG_H
+-#include <config.h>
+-#endif
+-
+-#include <stdlib.h>
+-#include <string.h>
+-
+-#ifdef WIN32
+-#include <winsock2.h>
+-#include <ws2tcpip.h>
+-#else
+-#include <sys/socket.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+-#endif
+-
+-#include <os/net.h>
+-
+-
+-#ifndef HAVE_INET_NTOP
+-const char *tight_inet_ntop(int af, const void *src, char *dst,
+-			    socklen_t size) {
+-	char *tempstr;
+-
+-	/* Catch bugs - we should not use IPv6 if we don't have inet_ntop */
+-	if (af != AF_INET)
+-		abort();
+-
+-	/* inet_ntoa never fails */
+-	tempstr = inet_ntoa(*(struct in_addr *)(src));
+-	memcpy(dst, tempstr, strlen(tempstr) + 1);
+-
+-	return dst;
+-}
+-#endif
+diff --git a/common/os/net.h b/common/os/net.h
+deleted file mode 100644
+index bd8b21c..0000000
+--- a/common/os/net.h
++++ /dev/null
+@@ -1,50 +0,0 @@
+-/* Copyright (C) 2008 TightVNC Team.  All Rights Reserved.
+- *
+- * This is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- * 
+- * This software is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- * 
+- * You should have received a copy of the GNU General Public License
+- * along with this software; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+- * USA.
+- */
+-
+-#ifndef OS_NET_H
+-#define OS_NET_H
+-
+-#ifdef HAVE_CONFIG_H
+-#include <config.h>
+-#endif
+-
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+-#ifndef HAVE_SOCKLEN_T
+-typedef int socklen_t;
+-#endif
+-
+-/* IPv6 support on server side - we have to have all those functions */
+-#if defined(HAVE_INET_NTOP)
+-#define HAVE_IPV6
+-#endif
+-
+-/* IPv4-only stub implementation */
+-#ifndef HAVE_INET_NTOP
+-const char *tight_inet_ntop(int af, const void *src,
+-			    char *dst, socklen_t size);
+-#define inet_ntop tight_inet_ntop
+-#endif
+-
+-#ifdef __cplusplus
+-};
+-#endif
+-
+-#endif /* OS_NET_H */
+diff --git a/config.h.in b/config.h.in
+index ec2aed9..c6d27ee 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -2,9 +2,6 @@
+ #define PACKAGE_VERSION "@VERSION@"
+ 
+ #cmakedefine HAVE_SOCKLEN_T
+-#cmakedefine HAVE_INET_ATON
+-#cmakedefine HAVE_INET_NTOP
+-#cmakedefine HAVE_GETADDRINFO
+ #cmakedefine HAVE_SNPRINTF
+ #cmakedefine HAVE_STRCASECMP
+ #cmakedefine HAVE_STRNCASECMP
+diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
+index b5498e1..400af75 100644
+--- a/unix/x0vncserver/x0vncserver.cxx
++++ b/unix/x0vncserver/x0vncserver.cxx
+@@ -434,6 +434,8 @@ int main(int argc, char** argv)
+   signal(SIGINT, CleanupSignalHandler);
+   signal(SIGTERM, CleanupSignalHandler);
+ 
++  std::list<TcpListener> listeners;
++
+   try {
+     TXWindow::init(dpy,"x0vncserver");
+     Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)),
+@@ -448,13 +450,16 @@ int main(int argc, char** argv)
+     QueryConnHandler qcHandler(dpy, &server);
+     server.setQueryConnectionHandler(&qcHandler);
+ 
+-    TcpListener listener(NULL, (int)rfbport);
++    createTcpListeners(&listeners, 0, (int)rfbport);
+     vlog.info("Listening on port %d", (int)rfbport);
+ 
+     const char *hostsData = hostsFile.getData();
+     FileTcpFilter fileTcpFilter(hostsData);
+     if (strlen(hostsData) != 0)
+-      listener.setFilter(&fileTcpFilter);
++      for (std::list<TcpListener>::iterator i = listeners.begin();
++           i != listeners.end();
++           i++)
++        (*i).setFilter(&fileTcpFilter);
+     delete[] hostsData;
+ 
+     PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
+@@ -469,7 +474,11 @@ int main(int argc, char** argv)
+       TXWindow::handleXEvents(dpy);
+ 
+       FD_ZERO(&rfds);
+-      FD_SET(listener.getFd(), &rfds);
++      for (std::list<TcpListener>::iterator i = listeners.begin();
++           i != listeners.end();
++           i++)
++        FD_SET((*i).getFd(), &rfds);
++
+       server.getSockets(&sockets);
+       int clients_connected = 0;
+       for (i = sockets.begin(); i != sockets.end(); i++) {
+@@ -514,12 +523,16 @@ int main(int argc, char** argv)
+       }
+ 
+       // Accept new VNC connections
+-      if (FD_ISSET(listener.getFd(), &rfds)) {
+-        Socket* sock = listener.accept();
+-        if (sock) {
+-          server.addSocket(sock);
+-        } else {
+-          vlog.status("Client connection rejected");
++      for (std::list<TcpListener>::iterator i = listeners.begin();
++           i != listeners.end();
++           i++) {
++        if (FD_ISSET((*i).getFd(), &rfds)) {
++          Socket* sock = (*i).accept();
++          if (sock) {
++            server.addSocket(sock);
++          } else {
++            vlog.status("Client connection rejected");
++          }
+         }
+       }
+ 
+diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
+index 05169b0..d0a9953 100644
+--- a/unix/xserver/hw/vnc/XserverDesktop.cc
++++ b/unix/xserver/hw/vnc/XserverDesktop.cc
+@@ -135,13 +135,13 @@ public:
+ 
+ 
+ XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
+-                               network::TcpListener* listener_,
+-                               network::TcpListener* httpListener_,
++                               std::list<network::TcpListener> listeners_,
++                               std::list<network::TcpListener> httpListeners_,
+                                const char* name, const rfb::PixelFormat &pf,
+                                void* fbptr, int stride)
+   : pScreen(pScreen_),
+     server(0), httpServer(0),
+-    listener(listener_), httpListener(httpListener_),
++    listeners(listeners_), httpListeners(httpListeners_),
+     cmap(0), deferredUpdateTimerSet(false),
+     grabbing(false), ignoreHooks_(false), directFbptr(true),
+     queryConnectId(0)
+@@ -155,7 +155,7 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
+   setFramebuffer(pScreen->width, pScreen->height, fbptr, stride);
+   server->setQueryConnectionHandler(this);
+ 
+-  if (httpListener)
++  if (!httpListeners.empty ())
+     httpServer = new FileHTTPServer(this);
+ }
+ 
+@@ -315,7 +315,7 @@ char* XserverDesktop::substitute(const char* varName)
+   }
+   if (strcmp(varName, "$PORT") == 0) {
+     char* str = new char[10];
+-    sprintf(str, "%d", listener ? listener->getMyPort() : 0);
++    sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort());
+     return str;
+   }
+   if (strcmp(varName, "$WIDTH") == 0) {
+@@ -587,14 +587,18 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
+ 
+     // Add all sockets we want read events for, after purging
+     // any closed sockets.
+-    if (listener)
+-      FD_SET(listener->getFd(), fds);
+-    if (httpListener)
+-      FD_SET(httpListener->getFd(), fds);
++    for (std::list<network::TcpListener>::iterator i = listeners.begin();
++         i != listeners.end();
++         i++)
++      FD_SET((*i).getFd(), fds);
++    for (std::list<network::TcpListener>::iterator i = httpListeners.begin();
++         i != httpListeners.end();
++         i++)
++      FD_SET((*i).getFd(), fds);
+ 
+     std::list<Socket*> sockets;
+-    server->getSockets(&sockets);
+     std::list<Socket*>::iterator i;
++    server->getSockets(&sockets);
+     for (i = sockets.begin(); i != sockets.end(); i++) {
+       int fd = (*i)->getFd();
+       if ((*i)->isShutdown()) {
+@@ -646,20 +650,24 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
+     // First check for file descriptors with something to do
+     if (nfds >= 1) {
+ 
+-      if (listener) {
+-        if (FD_ISSET(listener->getFd(), fds)) {
+-          FD_CLR(listener->getFd(), fds);
+-          Socket* sock = listener->accept();
++      for (std::list<network::TcpListener>::iterator i = listeners.begin();
++           i != listeners.end();
++           i++) {
++        if (FD_ISSET((*i).getFd(), fds)) {
++          FD_CLR((*i).getFd(), fds);
++          Socket* sock = (*i).accept();
+           sock->outStream().setBlocking(false);
+           server->addSocket(sock);
+           vlog.debug("new client, sock %d",sock->getFd());
+         }
+       }
+ 
+-      if (httpListener) {
+-        if (FD_ISSET(httpListener->getFd(), fds)) {
+-          FD_CLR(httpListener->getFd(), fds);
+-          Socket* sock = httpListener->accept();
++      for (std::list<network::TcpListener>::iterator i = httpListeners.begin();
++           i != httpListeners.end();
++           i++) {
++        if (FD_ISSET((*i).getFd(), fds)) {
++          FD_CLR((*i).getFd(), fds);
++          Socket* sock = (*i).accept();
+           sock->outStream().setBlocking(false);
+           httpServer->addSocket(sock);
+           vlog.debug("new http client, sock %d",sock->getFd());
+diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
+index ca6e8af..23cdc83 100644
+--- a/unix/xserver/hw/vnc/XserverDesktop.h
++++ b/unix/xserver/hw/vnc/XserverDesktop.h
+@@ -58,8 +58,9 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
+                        public rfb::VNCServerST::QueryConnectionHandler {
+ public:
+ 
+-  XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
+-                 network::TcpListener* httpListener_,
++  XserverDesktop(ScreenPtr pScreen,
++                 std::list<network::TcpListener> listeners_,
++                 std::list<network::TcpListener> httpListeners_,
+                  const char* name, const rfb::PixelFormat &pf,
+                  void* fbptr, int stride);
+   virtual ~XserverDesktop();
+@@ -136,8 +137,8 @@ private:
+   InputDevice *inputDevice;
+   rfb::VNCServerST* server;
+   rfb::HTTPServer* httpServer;
+-  network::TcpListener* listener;
+-  network::TcpListener* httpListener;
++  std::list<network::TcpListener> listeners;
++  std::list<network::TcpListener> httpListeners;
+   ColormapPtr cmap;
+   int stride_;
+   bool deferredUpdateTimerSet;
+diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
+index 1abf7d5..1cfaf51 100644
+--- a/unix/xserver/hw/vnc/vncExtInit.cc
++++ b/unix/xserver/hw/vnc/vncExtInit.cc
+@@ -127,6 +127,9 @@ rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
+ rfb::BoolParameter localhostOnly("localhost",
+                                  "Only allow connections from localhost",
+                                  false);
++rfb::StringParameter interface("interface",
++                               "listen on the specified network address",
++                               "all");
+ 
+ static PixelFormat vncGetPixelFormat(ScreenPtr pScreen)
+ {
+@@ -222,29 +225,43 @@ void vncExtensionInit()
+     for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ 
+       if (!desktop[scr]) {
+-        network::TcpListener* listener = 0;
+-        network::TcpListener* httpListener = 0;
++        std::list<network::TcpListener> listeners;
++        std::list<network::TcpListener> httpListeners;
+         if (scr == 0 && vncInetdSock != -1) {
+           if (network::TcpSocket::isListening(vncInetdSock))
+           {
+-            listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
++            listeners.push_back (network::TcpListener(vncInetdSock));
+             vlog.info("inetd wait");
+           }
+         } else {
++          const char *addr = interface;
+           int port = rfbport;
+           if (port == 0) port = 5900 + atoi(display);
+           port += 1000 * scr;
+-          listener = new network::TcpListener(listenaddr, port, localhostOnly);
++          if (strcasecmp(addr, "all") == 0)
++            addr = 0;
++          if (localhostOnly)
++            network::createLocalTcpListeners(&listeners, port);
++          else
++            network::createTcpListeners(&listeners, addr, port);
++
+           vlog.info("Listening for VNC connections on %s interface(s), port %d",
+-		    listenaddr == NULL ? "all" : listenaddr, port);
++                    localhostOnly ? "local" : (const char*)interface,
++                    port);
++
+           CharArray httpDirStr(httpDir.getData());
+           if (httpDirStr.buf[0]) {
+             port = httpPort;
+             if (port == 0) port = 5800 + atoi(display);
+             port += 1000 * scr;
+-            httpListener = new network::TcpListener(listenaddr, port, localhostOnly);
++            if (localhostOnly)
++              network::createLocalTcpListeners(&httpListeners, port);
++            else
++              network::createTcpListeners(&httpListeners, addr, port);
++
+             vlog.info("Listening for HTTP connections on %s interface(s), port %d",
+-		      listenaddr == NULL ? "all" : listenaddr, port);
++                      localhostOnly ? "local" : (const char*)interface,
++                      port);
+           }
+         }
+ 
+@@ -252,15 +269,15 @@ void vncExtensionInit()
+         PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]);
+ 
+         desktop[scr] = new XserverDesktop(screenInfo.screens[scr],
+-                                          listener,
+-                                          httpListener,
++                                          listeners,
++                                          httpListeners,
+                                           desktopNameStr.buf,
+                                           pf,
+                                           vncFbptr[scr],
+                                           vncFbstride[scr]);
+         vlog.info("created VNC server for screen %d", scr);
+ 
+-        if (scr == 0 && vncInetdSock != -1 && !listener) {
++        if (scr == 0 && vncInetdSock != -1 && listeners.empty()) {
+           network::Socket* sock = new network::TcpSocket(vncInetdSock);
+           desktop[scr]->addClient(sock, false);
+           vlog.info("added inetd sock");
+diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
+index 2d7685f..81bf849 100644
+--- a/vncviewer/vncviewer.cxx
++++ b/vncviewer/vncviewer.cxx
+@@ -459,15 +459,45 @@ int main(int argc, char** argv)
+ #endif
+ 
+   if (listenMode) {
++    std::list<TcpListener> listeners;
+     try {
+       int port = 5500;
+       if (isdigit(vncServerName[0]))
+         port = atoi(vncServerName);
+ 
+-      TcpListener listener(NULL, port);
++      createTcpListeners(&listeners, 0, port);
+ 
+       vlog.info("Listening on port %d\n", port);
+-      sock = listener.accept();   
++
++      /* Wait for a connection */
++      while (sock == NULL) {
++        fd_set rfds;
++        FD_ZERO(&rfds);
++        for (std::list<TcpListener>::iterator i = listeners.begin();
++             i != listeners.end();
++             i++)
++          FD_SET((*i).getFd(), &rfds);
++
++        int n = select(FD_SETSIZE, &rfds, 0, 0, 0);
++        if (n < 0) {
++          if (errno == EINTR) {
++            vlog.debug("Interrupted select() system call");
++            continue;
++          } else {
++            throw rdr::SystemException("select", errno);
++          }
++        }
++
++        for (std::list<TcpListener>::iterator i = listeners.begin ();
++             i != listeners.end();
++             i++)
++          if (FD_ISSET((*i).getFd(), &rfds)) {
++            sock = (*i).accept();
++            if (sock)
++              /* Got a connection */
++              break;
++          }
++      }
+     } catch (rdr::Exception& e) {
+       vlog.error("%s", e.str());
+       fl_alert("%s", e.str());
+diff --git a/win/rfb_win32/Dialog.cxx b/win/rfb_win32/Dialog.cxx
+index 70a5fb5..24e0d9f 100644
+--- a/win/rfb_win32/Dialog.cxx
++++ b/win/rfb_win32/Dialog.cxx
+@@ -86,21 +86,17 @@ TCHAR* Dialog::getItemString(int id) {
+ }
+ 
+ void Dialog::setItemChecked(int id, bool state) {
+-  dlog.debug("bool[%d]=%d", id, (int)state);
+   SendMessage(GetDlgItem(handle, id), BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
+ }
+ void Dialog::setItemInt(int id, int value) {
+-  dlog.debug("int[%d]=%d", id, value);
+   SetDlgItemInt(handle, id, value, TRUE);
+ }
+ void Dialog::setItemString(int id, const TCHAR* s) {
+-  dlog.debug("string[%d]=%s", id, (const char*)CStr(s));
+   SetDlgItemText(handle, id, s);
+ }
+ 
+ 
+ void Dialog::enableItem(int id, bool state) {
+-  dlog.debug("enable[%d]=%d", id, (int)state);
+   EnableWindow(GetDlgItem(handle, id), state);
+ }
+ 
+@@ -361,7 +357,6 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo
+ }
+ 
+ void PropSheet::reInitPages() {
+-  plog.debug("reInitPages %lx", handle);
+   std::list<PropSheetPage*>::iterator pspi;
+   for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
+     if ((*pspi)->handle)
+@@ -370,7 +365,6 @@ void PropSheet::reInitPages() {
+ }
+ 
+ bool PropSheet::commitPages() {
+-  plog.debug("commitPages %lx", handle);
+   bool result = true;
+   std::list<PropSheetPage*>::iterator pspi;
+   for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
+@@ -383,7 +377,6 @@ bool PropSheet::commitPages() {
+ 
+ void PropSheetPage::setChanged(bool changed) {
+   if (propSheet) {
+-    plog.debug("setChanged[%lx(%lx)]=%d", handle, propSheet->handle, (int)changed);
+     if (changed)
+       PropSheet_Changed(propSheet->handle, handle);
+     else
+diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
+index d4f1965..b073b8f 100644
+--- a/win/rfb_win32/SocketManager.cxx
++++ b/win/rfb_win32/SocketManager.cxx
+@@ -174,7 +174,7 @@ void SocketManager::processEvent(HANDLE event) {
+       vlog.info("deleting listening socket");
+       remListener(li.sock);
+     } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
+-      li.notifier->processAddressChange(li.sock);
++      li.notifier->processAddressChange();
+       requestAddressChangeEvents(li.sock);
+     } else {
+       vlog.error("unknown listener event: %lx", network_events.lNetworkEvents);
+diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
+index ef35974..c3c8faf 100644
+--- a/win/rfb_win32/SocketManager.h
++++ b/win/rfb_win32/SocketManager.h
+@@ -48,7 +48,7 @@ namespace rfb {
+       class AddressChangeNotifier {
+       public:
+         virtual ~AddressChangeNotifier() {}
+-        virtual void processAddressChange(network::SocketListener* sl) = 0;
++        virtual void processAddressChange() = 0;
+       };
+ 
+       // Add a listening socket.  Incoming connections will be added to the supplied
+diff --git a/win/vncconfig/vncconfig.cxx b/win/vncconfig/vncconfig.cxx
+index 535febb..74d5e66 100644
+--- a/win/vncconfig/vncconfig.cxx
++++ b/win/vncconfig/vncconfig.cxx
+@@ -16,6 +16,7 @@
+  * USA.
+  */
+ 
++#include <winsock2.h>
+ #include <windows.h>
+ #include <commctrl.h>
+ #include <string.h>
+diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
+index f2933bb..ac408e7 100644
+--- a/win/winvnc/ManagedListener.cxx
++++ b/win/winvnc/ManagedListener.cxx
+@@ -26,12 +26,16 @@ static LogWriter vlog("ManagedListener");
+ 
+ 
+ ManagedListener::ManagedListener(SocketManager* mgr)
+-: sock(0), filter(0), manager(mgr), addrChangeNotifier(0), server(0), port(0), localOnly(false) {
++: filter(0), manager(mgr), addrChangeNotifier(0), server(0), port(0), localOnly(false) {
+ }
+ 
+ ManagedListener::~ManagedListener() {
+-  if (sock)
+-    manager->remListener(sock);
++  if (!sockets.empty()) {
++    std::list<network::TcpListener>::iterator iter;
++    for (iter = sockets.begin(); iter != sockets.end(); ++iter)
++      manager->remListener(&*iter);
++    sockets.clear();
++  }
+   delete filter;
+ }
+ 
+@@ -57,8 +61,11 @@ void ManagedListener::setFilter(const char* filterStr) {
+   vlog.info("set filter to %s", filterStr);
+   delete filter;
+   filter = new network::TcpFilter(filterStr);
+-  if (sock && !localOnly)
+-    sock->setFilter(filter);
++  if (!sockets.empty() && !localOnly) {
++    std::list<network::TcpListener>::iterator iter;
++    for (iter = sockets.begin(); iter != sockets.end(); ++iter)
++      iter->setFilter(filter);
++  }
+ }
+ 
+ void ManagedListener::setAddressChangeNotifier(SocketManager::AddressChangeNotifier* acn) {
+@@ -68,26 +75,39 @@ void ManagedListener::setAddressChangeNotifier(SocketManager::AddressChangeNotif
+   refresh();
+ }
+ 
++bool ManagedListener::isListening() {
++  return !sockets.empty();
++}
+ 
+ void ManagedListener::refresh() {
+-  if (sock)
+-    manager->remListener(sock);
+-  sock = 0;
++  std::list<network::TcpListener>::iterator iter;
++  if (!sockets.empty()) {
++    for (iter = sockets.begin(); iter != sockets.end(); ++iter)
++      manager->remListener(&*iter);
++    sockets.clear();
++  }
+   if (!server)
+     return;
+   try {
+-    if (port)
+-      sock = new network::TcpListener(NULL, port, localOnly);
++    if (port) {
++      if (localOnly)
++        network::createLocalTcpListeners(&sockets, port);
++      else
++        network::createTcpListeners(&sockets, NULL, port);
++    }
+   } catch (rdr::Exception& e) {
+     vlog.error(e.str());
+   }
+-  if (sock) {
+-    if (!localOnly)
+-      sock->setFilter(filter);
++  if (!sockets.empty()) {
++    if (!localOnly) {
++      for (iter = sockets.begin(); iter != sockets.end(); ++iter)
++        iter->setFilter(filter);
++    }
+     try {
+-      manager->addListener(sock, server, addrChangeNotifier);
+-    } catch (...) {
+-      sock = 0;
++      for (iter = sockets.begin(); iter != sockets.end(); ++iter)
++        manager->addListener(&*iter, server, addrChangeNotifier);    } catch (...) {
++      // FIXME: Should unwind what we've added
++      sockets.clear();
+       throw;
+     }
+   }
+diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
+index e83aa0b..1c7099f 100644
+--- a/win/winvnc/ManagedListener.h
++++ b/win/winvnc/ManagedListener.h
+@@ -40,10 +40,12 @@ namespace winvnc {
+     void setPort(int port, bool localOnly=false);
+     void setFilter(const char* filter);
+     void setAddressChangeNotifier(rfb::win32::SocketManager::AddressChangeNotifier* acn);
+-  
+-    network::TcpListener* sock;
++
++    bool isListening();
++
+   protected:
+     void refresh();
++    std::list<network::TcpListener> sockets;
+     network::TcpFilter* filter;
+     rfb::win32::SocketManager* manager;
+     rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;
+diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
+index 4d89a0e..467ff70 100644
+--- a/win/winvnc/VNCServerWin32.cxx
++++ b/win/winvnc/VNCServerWin32.cxx
+@@ -43,7 +43,7 @@ static IntParameter http_port("HTTPPortNumber",
+ static IntParameter port_number("PortNumber",
+   "TCP/IP port on which the server will accept connections", 5900);
+ static StringParameter hosts("Hosts",
+-  "Filter describing which hosts are allowed access to this server", "+0.0.0.0/0.0.0.0");
++  "Filter describing which hosts are allowed access to this server", "+");
+ static BoolParameter localHost("LocalHost",
+   "Only accept connections from via the local loop-back network interface", false);
+ static BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
+@@ -86,8 +86,8 @@ VNCServerWin32::~VNCServerWin32() {
+ }
+ 
+ 
+-void VNCServerWin32::processAddressChange(network::SocketListener* sock_) {
+-  if (!trayIcon || (sock_ != rfbSock.sock))
++void VNCServerWin32::processAddressChange() {
++  if (!trayIcon)
+     return;
+ 
+   // Tool-tip prefix depends on server mode
+@@ -97,8 +97,8 @@ void VNCServerWin32::processAddressChange(network::SocketListener* sock_) {
+ 
+   // Fetch the list of addresses
+   std::list<char*> addrs;
+-  if (rfbSock.sock)
+-    rfbSock.sock->getMyAddresses(&addrs);
++  if (rfbSock.isListening())
++    TcpListener::getMyAddresses(&addrs);
+   else
+     addrs.push_front(strDup("Not accepting connections"));
+ 
+@@ -132,7 +132,7 @@ void VNCServerWin32::regConfigChanged() {
+   httpSock.setPort(http_port, localHost);
+ 
+   // -=- Update the Java viewer's web page port number.
+-  httpServer.setRFBport(rfbSock.sock ? port_number : 0);
++  httpServer.setRFBport(rfbSock.isListening() ? port_number : 0);
+ 
+   // -=- Update the TCP address filter for both ports, if open.
+   CharArray pattern(hosts.getData());
+@@ -140,7 +140,7 @@ void VNCServerWin32::regConfigChanged() {
+   httpSock.setFilter(pattern.buf);
+ 
+   // -=- Update the tray icon tooltip text with IP addresses
+-  processAddressChange(rfbSock.sock);
++  processAddressChange();
+ }
+ 
+ 
+diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h
+index 5b40a5a..27305d0 100644
+--- a/win/winvnc/VNCServerWin32.h
++++ b/win/winvnc/VNCServerWin32.h
+@@ -82,7 +82,7 @@ namespace winvnc {
+ 
+     // SocketManager::AddressChangeNotifier interface
+     // Used to keep tray icon up to date
+-    virtual void processAddressChange(network::SocketListener* sl);
++    virtual void processAddressChange();
+ 
+     // RegConfig::Callback interface
+     // Called via the EventManager whenver RegConfig sees the registry change
diff --git a/SOURCES/tigervnc-no-warning-with-wformat-security.patch b/SOURCES/tigervnc-no-warning-with-wformat-security.patch
new file mode 100644
index 0000000..f588be0
--- /dev/null
+++ b/SOURCES/tigervnc-no-warning-with-wformat-security.patch
@@ -0,0 +1,12 @@
+diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
+index c15c951..2d7685f 100644
+--- a/vncviewer/vncviewer.cxx
++++ b/vncviewer/vncviewer.cxx
+@@ -309,7 +309,6 @@ interpretViaParam(char *remoteHost, int *remotePort, int localPort)
+
+   snprintf(vncServerName, VNCSERVERNAMELEN, "localhost::%d", localPort);
+   vncServerName[VNCSERVERNAMELEN - 1] = '\0';
+-  vlog.error(vncServerName);
+
+   return 0;
+ }
diff --git a/SOURCES/tigervnc-pointersync.patch b/SOURCES/tigervnc-pointersync.patch
new file mode 100644
index 0000000..3870f2e
--- /dev/null
+++ b/SOURCES/tigervnc-pointersync.patch
@@ -0,0 +1,19 @@
+diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc
+index d093f89..43c3ac3 100644
+--- a/unix/xserver/hw/vnc/Input.cc
++++ b/unix/xserver/hw/vnc/Input.cc
+@@ -197,6 +197,14 @@ void InputDevice::PointerMove(const rfb::Point &pos)
+ 
+ void InputDevice::PointerSync(void)
+ {
++	if (pointerDev) {
++		int x, y;
++
++		GetSpritePosition (pointerDev, &x, &y);
++		cursorPos.x = x;
++		cursorPos.y = y;
++	}
++
+ 	if (cursorPos.equals(oldCursorPos))
+ 		return;
+ 
diff --git a/SOURCES/tigervnc-set-initial-mode-as-prefered.patch b/SOURCES/tigervnc-set-initial-mode-as-prefered.patch
new file mode 100644
index 0000000..773981f
--- /dev/null
+++ b/SOURCES/tigervnc-set-initial-mode-as-prefered.patch
@@ -0,0 +1,41 @@
+diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.cc
+index f2656d1..0e325e2 100644
+--- a/unix/xserver/hw/vnc/xvnc.cc
++++ b/unix/xserver/hw/vnc/xvnc.cc
+@@ -1318,12 +1318,22 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
+     /* Make sure the CRTC has this output set */
+     vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output);
+ 
+-    /* Populate a list of default modes */
+-    RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
+-    int num_modes;
++    /* Populate a list of modes */
++    RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths) + 1];
++    int num_modes = 0;
+ 
+-    num_modes = 0;
++    /* Start with requested mode */
++    mode = vncRandRModeGet(pScreen->width, pScreen->height);
++    if(mode != NULL) {
++      modes[num_modes] = mode;
++      num_modes++;
++    }
++
++    /* Add default modes */
+     for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
++        if (vncRandRWidths[i] == pScreen->width && vncRandRHeights[i] == pScreen->height)
++            continue;
++
+         mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
+         if (mode != NULL) {
+             modes[num_modes] = mode;
+ @@ -1331,7 +1341,7 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
+         }
+     }
+ 
+-    RROutputSetModes(output, modes, num_modes, 0);
++    RROutputSetModes(output, modes, num_modes, 1);
+ 
+     return crtc;
+ }
+ 
diff --git a/SOURCES/tigervnc-xserver117.patch b/SOURCES/tigervnc-xserver117.patch
new file mode 100644
index 0000000..5f5a73c
--- /dev/null
+++ b/SOURCES/tigervnc-xserver117.patch
@@ -0,0 +1,137 @@
+diff -up xorg-server-1.17.1/configure.ac.xserver116-rebased xorg-server-1.17.1/configure.ac
+--- xorg-server-1.17.1/configure.ac.xserver116-rebased	2015-02-10 22:43:52.000000000 +0000
++++ xorg-server-1.17.1/configure.ac	2015-02-13 16:14:05.074515927 +0000
+@@ -74,6 +74,7 @@ dnl forcing an entire recompile.x
+ AC_CONFIG_HEADERS(include/version-config.h)
+ 
+ AM_PROG_AS
++AC_PROG_CXX
+ AC_PROG_LN_S
+ LT_PREREQ([2.2])
+ LT_INIT([disable-static win32-dll])
+@@ -1795,6 +1796,10 @@ if test "x$XVFB" = xyes; then
+ 	AC_SUBST([XVFB_SYS_LIBS])
+ fi
+ 
++dnl Xvnc DDX
++AC_SUBST([XVNC_CPPFLAGS], ["-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS"])
++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"])
++AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"])
+ 
+ dnl Xnest DDX
+ 
+@@ -1830,6 +1835,8 @@ if test "x$XORG" = xauto; then
+ fi
+ AC_MSG_RESULT([$XORG])
+ 
++AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
++
+ if test "x$XORG" = xyes; then
+ 	XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common'
+ 	XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os'
+@@ -2059,7 +2066,6 @@ if test "x$XORG" = xyes; then
+ 	AC_DEFINE(XORG_SERVER, 1, [Building Xorg server])
+ 	AC_DEFINE(XORGSERVER, 1, [Building Xorg server])
+ 	AC_DEFINE(XFree86Server, 1, [Building XFree86 server])
+-	AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version])
+ 	AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs])
+ 	AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions])
+ 	AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server])
+@@ -2599,6 +2605,7 @@ hw/dmx/Makefile
+ hw/dmx/man/Makefile
+ hw/vfb/Makefile
+ hw/vfb/man/Makefile
++hw/vnc/Makefile
+ hw/xnest/Makefile
+ hw/xnest/man/Makefile
+ hw/xwin/Makefile
+diff -up xorg-server-1.17.1/hw/Makefile.am.xserver116-rebased xorg-server-1.17.1/hw/Makefile.am
+--- xorg-server-1.17.1/hw/Makefile.am.xserver116-rebased	2014-04-16 21:24:00.000000000 +0100
++++ xorg-server-1.17.1/hw/Makefile.am	2015-02-13 16:14:05.131516821 +0000
+@@ -38,7 +38,8 @@ SUBDIRS =			\
+ 	$(DMX_SUBDIRS)		\
+ 	$(KDRIVE_SUBDIRS)	\
+ 	$(XQUARTZ_SUBDIRS)	\
+-	$(XWAYLAND_SUBDIRS)
++	$(XWAYLAND_SUBDIRS)	\
++	vnc
+ 
+ DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
+ 
+diff -up xorg-server-1.17.1/mi/miinitext.c.xserver116-rebased xorg-server-1.17.1/mi/miinitext.c
+--- xorg-server-1.17.1/mi/miinitext.c.xserver116-rebased	2015-01-17 23:42:52.000000000 +0000
++++ xorg-server-1.17.1/mi/miinitext.c	2015-02-13 16:14:05.131516821 +0000
+@@ -111,6 +111,10 @@ SOFTWARE.
+ #include "micmap.h"
+ #include "globals.h"
+ 
++#ifdef TIGERVNC
++extern void vncExtensionInit(INITARGS);
++#endif
++
+ /* The following is only a small first step towards run-time
+  * configurable extensions.
+  */
+@@ -235,6 +239,9 @@ EnableDisableExtensionError(const char *
+ 
+ /* List of built-in (statically linked) extensions */
+ static const ExtensionModule staticExtensions[] = {
++#ifdef TIGERVNC
++    {vncExtensionInit, "VNC-EXTENSION", NULL},
++#endif
+     {GEExtensionInit, "Generic Event Extension", &noGEExtension},
+     {ShapeExtensionInit, "SHAPE", NULL},
+ #ifdef MITSHM
+diff -up xorg-server-1.17.1/os/WaitFor.c.xserver116-rebased xorg-server-1.17.1/os/WaitFor.c
+--- xorg-server-1.17.1/os/WaitFor.c.xserver116-rebased	2015-01-26 18:40:30.000000000 +0000
++++ xorg-server-1.17.1/os/WaitFor.c	2015-02-13 16:14:05.132516837 +0000
+@@ -125,6 +125,9 @@ static void DoTimer(OsTimerPtr timer, CA
+ static void CheckAllTimers(void);
+ static volatile OsTimerPtr timers = NULL;
+ 
++extern void vncWriteBlockHandler(fd_set *fds);
++extern void vncWriteWakeupHandler(int nfds, fd_set *fds);
++
+ /*****************
+  * WaitForSomething:
+  *     Make the server suspend until there is
+@@ -150,6 +153,7 @@ WaitForSomething(int *pClientsReady)
+     INT32 timeout = 0;
+     fd_set clientsReadable;
+     fd_set clientsWritable;
++    fd_set socketsWritable;
+     int curclient;
+     int selecterr;
+     static int nready;
+@@ -212,6 +216,9 @@ WaitForSomething(int *pClientsReady)
+             XFD_COPYSET(&AllSockets, &LastSelectMask);
+         }
+ 
++        FD_ZERO(&socketsWritable);
++        vncWriteBlockHandler(&socketsWritable);
++
+         BlockHandler((void *) &wt, (void *) &LastSelectMask);
+         if (NewOutputPending)
+             FlushAllOutput();
+@@ -223,10 +230,20 @@ WaitForSomething(int *pClientsReady)
+             i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt);
+         }
+         else {
+-            i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
++	    if (AnyClientsWriteBlocked)
++		XFD_ORSET(&socketsWritable, &ClientsWriteBlocked, &socketsWritable);
++
++	    if (XFD_ANYSET(&socketsWritable)) {
++		i = Select(MaxClients, &LastSelectMask, &socketsWritable, NULL, wt);
++		if (AnyClientsWriteBlocked)
++		    XFD_ANDSET(&clientsWritable, &socketsWritable, &ClientsWriteBlocked);
++	    } else {
++		i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
++	    }
+         }
+         selecterr = GetErrno();
+         WakeupHandler(i, (void *) &LastSelectMask);
++	vncWriteWakeupHandler(i, &socketsWritable);
+         if (i <= 0) {           /* An error or timeout occurred */
+             if (dispatchException)
+                 return 0;
diff --git a/SOURCES/tigervnc12-xorg113-glx.patch b/SOURCES/tigervnc12-xorg113-glx.patch
deleted file mode 100644
index c5a5621..0000000
--- a/SOURCES/tigervnc12-xorg113-glx.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc
---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx	2013-02-19 13:51:29.000000000 +0000
-+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc	2013-12-09 17:03:52.147179079 +0000
-@@ -1564,6 +1564,18 @@ static void vfbClientStateChange(Callbac
-   dispatchException &= ~DE_RESET;
- }
- 
-+#if XORG >= 113
-+#ifdef GLXEXT
-+extern "C" void GlxExtensionInit(void);
-+
-+static ExtensionModule glxExt = {
-+    GlxExtensionInit,
-+    "GLX",
-+    &noGlxExtension
-+};
-+#endif
-+#endif
-+
- void
- InitOutput(ScreenInfo *screenInfo, int argc, char **argv)
- {
-@@ -1573,6 +1585,13 @@ InitOutput(ScreenInfo *screenInfo, int a
-     int i;
-     int NumFormats = 0;
- 
-+#if XORG >= 113
-+#ifdef GLXEXT
-+    if (serverGeneration == 1)
-+        LoadExtension(&glxExt, TRUE);
-+#endif
-+#endif
-+
-     /* initialize pixmap formats */
- 
-     /* must have a pixmap depth to match every screen depth */
diff --git a/SOURCES/vncserver.service b/SOURCES/vncserver.service
index 4d55de2..4cec744 100644
--- a/SOURCES/vncserver.service
+++ b/SOURCES/vncserver.service
@@ -1,7 +1,7 @@
 # The vncserver service unit file
 #
 # Quick HowTo:
-# 1. Copy this file to /etc/systemd/system/vncserver@:<display>.service
+# 1. Copy this file to /etc/systemd/system/vncserver@.service
 # 2. Edit <USER> and vncserver parameters appropriately
 #   ("runuser -l <USER> -c /usr/bin/vncserver %i -arg1 -arg2")
 # 3. Run `systemctl daemon-reload`
@@ -37,7 +37,7 @@ After=syslog.target network.target
 Type=forking
 # Clean any existing files in /tmp/.X11-unix environment
 ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
-ExecStart=/sbin/runuser -l <USER> -c "/usr/bin/vncserver %i"
+ExecStart=/usr/sbin/runuser -l <USER> -c "/usr/bin/vncserver %i"
 PIDFile=/home/<USER>/.vnc/%H%i.pid
 ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
 
diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec
index 659aa18..b9bdcfc 100644
--- a/SPECS/tigervnc.spec
+++ b/SPECS/tigervnc.spec
@@ -1,59 +1,66 @@
-%global		snap 20130314svn5065
-
-Name:		tigervnc
-Version:	1.2.80
-Release:	0.30.%{snap}%{?dist}
-Summary:	A TigerVNC remote display system
-
-Group:		User Interface/Desktops
-License:	GPLv2+
-URL:		http://www.tigervnc.com
-
-Source0:	%{name}-%{version}-%{snap}.tar.bz2
-Source1:	vncserver.service
-Source2:	vncserver.sysconfig
-Source3:	10-libvnc.conf
-Source6:	vncviewer.desktop
-BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-BuildRequires:	libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint
-BuildRequires:	libXext-devel, xorg-x11-server-source, libXi-devel
-BuildRequires:	xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel
-BuildRequires:	libdrm-devel, libXt-devel, pixman-devel libXfont-devel
-BuildRequires:	libxkbfile-devel, openssl-devel, libpciaccess-devel
-BuildRequires:	mesa-libGL-devel, libXinerama-devel, ImageMagick
+Name:           tigervnc
+Version:        1.3.1
+Release:        3%{?dist}
+Summary:        A TigerVNC remote display system
+
+Group:          User Interface/Desktops
+License:        GPLv2+
+URL:            http://www.tigervnc.com
+
+Source0:        %{name}-%{version}.tar.gz
+Source1:        vncserver.service
+Source2:        vncserver.sysconfig
+Source3:        10-libvnc.conf
+Source6:        vncviewer.desktop
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+BuildRequires:  libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint
+BuildRequires:  libXext-devel, xorg-x11-server-source, libXi-devel
+BuildRequires:  xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel
+BuildRequires:  libdrm-devel, libXt-devel, pixman-devel libXfont-devel
+BuildRequires:  libxkbfile-devel, openssl-devel, libpciaccess-devel
+BuildRequires:  mesa-libGL-devel, libXinerama-devel, ImageMagick
 BuildRequires:  freetype-devel, libXdmcp-devel
-BuildRequires:	desktop-file-utils, java-devel, jpackage-utils
-BuildRequires:	libjpeg-turbo-devel, gnutls-devel, pam-devel
-BuildRequires:	systemd, cmake, fltk-devel
-
-Requires(post):	coreutils
-Requires(postun):coreutils
-
-Requires:	hicolor-icon-theme
-Requires:	tigervnc-license
-Requires:	tigervnc-icons
-
-Provides:	vnc = 4.1.3-2, vnc-libs = 4.1.3-2
-Obsoletes:	vnc < 4.1.3-2, vnc-libs < 4.1.3-2
-Provides:	tightvnc = 1.5.0-0.15.20090204svn3586
-Obsoletes:	tightvnc < 1.5.0-0.15.20090204svn3586
-
-Patch4:		tigervnc-cookie.patch
-Patch10:	tigervnc11-ldnow.patch
-Patch11:	tigervnc11-gethomedir.patch
-Patch13:	tigervnc11-rh692048.patch
-Patch14:	tigervnc12-xorg113-glx.patch
-Patch15:	tigervnc-inetd-nowait.patch
-Patch16:	tigervnc-setcursor-crash.patch
-Patch17:	tigervnc-manpages.patch
-Patch18:	tigervnc-shebang.patch
-Patch19:	tigervnc-1.3.0-xserver-1.15.patch
-Patch20:	tigervnc-zrle-crash.patch
-Patch21:	tigervnc-cursor.patch
-Patch22:	tigervnc-input.patch
-Patch23:	tigervnc-xstartup.patch
-Patch24:	tigervnc-CVE-2014-0011.patch
+BuildRequires:  desktop-file-utils, java-devel, jpackage-utils
+BuildRequires:  libjpeg-turbo-devel, gnutls-devel, pam-devel
+BuildRequires:  systemd, cmake, fltk-devel
+
+Requires(post):   coreutils
+Requires(postun): coreutils
+
+Requires:       hicolor-icon-theme
+Requires:       tigervnc-license
+Requires:       tigervnc-icons
+
+Provides:       vnc = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:      vnc < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:       tightvnc = 1.5.0-0.15.20090204svn3586
+Obsoletes:      tightvnc < 1.5.0-0.15.20090204svn3586
+
+Patch4:         tigervnc-cookie.patch
+Patch10:        tigervnc11-ldnow.patch
+Patch11:        tigervnc11-gethomedir.patch
+Patch13:        tigervnc11-rh692048.patch
+Patch14:        tigervnc-inetd-nowait.patch
+Patch15:        tigervnc-setcursor-crash.patch
+Patch16:        tigervnc-manpages.patch
+Patch17:        tigervnc-shebang.patch
+Patch18:        tigervnc-1.3.1-xserver-1.16.patch
+Patch19:        tigervnc-1.3.1-xserver-1.17.patch
+Patch20:        tigervnc-zrle-crash.patch
+Patch21:        tigervnc-cursor.patch
+Patch22:        tigervnc-xstartup.patch
+Patch23:        tigervnc-no-warning-with-wformat-security.patch
+Patch24:        tigervnc-check-return-value-from-xshmattach.patch
+Patch25:        tigervnc-pointersync.patch
+Patch26:        tigervnc-inputreset.patch
+Patch27:        tigervnc-ipv6-support.patch
+Patch28:        tigervnc-set-initial-mode-as-prefered.patch
+Patch29:        tigervnc-CVE-2014-8241.patch
+Patch30:        tigervnc-1.3.1-CVE-2014-8240.patch
+
+# This is tigervnc-%{version}/unix/xserver116.patch rebased on the latest xorg
+Patch100:       tigervnc-xserver117.patch
 
 %description
 Virtual Network Computing (VNC) is a remote display system which
@@ -64,20 +71,20 @@ client which will allow you to connect to other desktops running a VNC
 server.
 
 %package server
-Summary:	A TigerVNC server
-Group:		User Interface/X
-Provides:	vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
-Obsoletes:	vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
-Provides:	tightvnc-server = 1.5.0-0.15.20090204svn3586
-Obsoletes:	tightvnc-server < 1.5.0-0.15.20090204svn3586
-Requires:	perl
-Requires:	tigervnc-server-minimal
-Requires:	xorg-x11-xauth
-Requires:	xorg-x11-xinit
-Requires(post): systemd
-Requires(preun): systemd
+Summary:        A TigerVNC server
+Group:          User Interface/X
+Provides:       vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:      vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:       tightvnc-server = 1.5.0-0.15.20090204svn3586
+Obsoletes:      tightvnc-server < 1.5.0-0.15.20090204svn3586
+Requires:       perl
+Requires:       tigervnc-server-minimal
+Requires:       xorg-x11-xauth
+Requires:       xorg-x11-xinit
+Requires(post):   systemd
+Requires(preun):  systemd
 Requires(postun): systemd
-Requires(post):	systemd-sysv chkconfig
+Requires(post):   systemd-sysv chkconfig
 
 %description server
 The VNC system allows you to access the same desktop from a wide
@@ -87,15 +94,15 @@ contains x0vncserver program which can export your active
 X session.
 
 %package server-minimal
-Summary:	A minimal installation of TigerVNC server
-Group:		User Interface/X
-Requires(post):	chkconfig
-Requires(preun):chkconfig
-Requires(preun):initscripts
-Requires(postun):initscripts
+Summary:        A minimal installation of TigerVNC server
+Group:          User Interface/X
+Requires(post):   chkconfig
+Requires(preun):  chkconfig
+Requires(preun):  initscripts
+Requires(postun): initscripts
 
-Requires:	mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils
-Requires:	tigervnc-license
+Requires:         mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils
+Requires:         tigervnc-license
 
 %description server-minimal
 The VNC system allows you to access the same desktop from a wide
@@ -105,14 +112,14 @@ machine.
 
 %ifnarch s390 s390x
 %package server-module
-Summary:	TigerVNC module to Xorg
-Group:		User Interface/X
-Provides:	vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
-Obsoletes:	vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
-Provides:	tightvnc-server-module = 1.5.0-0.15.20090204svn3586
-Obsoletes:	tightvnc-server-module < 1.5.0-0.15.20090204svn3586
-Requires:	xorg-x11-server-Xorg
-Requires:	tigervnc-license
+Summary:        TigerVNC module to Xorg
+Group:          User Interface/X
+Provides:       vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:      vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:       tightvnc-server-module = 1.5.0-0.15.20090204svn3586
+Obsoletes:      tightvnc-server-module < 1.5.0-0.15.20090204svn3586
+Requires:       xorg-x11-server-Xorg
+Requires:       tigervnc-license
 
 %description server-module
 This package contains libvnc.so module to X server, allowing others
@@ -120,33 +127,33 @@ to access the desktop on your machine.
 %endif
 
 %package server-applet
-Summary:	Java TigerVNC viewer applet for TigerVNC server
-Group:		User Interface/X
-Requires:	tigervnc-server, java, jpackage-utils
-BuildArch:	noarch
+Summary:        Java TigerVNC viewer applet for TigerVNC server
+Group:          User Interface/X
+Requires:       tigervnc-server, java, jpackage-utils
+BuildArch:      noarch
 
 %description server-applet
 The Java TigerVNC viewer applet for web browsers. Install this package to allow
 clients to use web browser when connect to the TigerVNC server.
 
 %package license
-Summary:	License of TigerVNC suite
-Group:		User Interface/X
-BuildArch:	noarch
+Summary:        License of TigerVNC suite
+Group:          User Interface/X
+BuildArch:      noarch
 
 %description license
 This package contains license of the TigerVNC suite
 
 %package icons
-Summary:	Icons for TigerVNC viewer
-Group:		User Interface/X
-BuildArch:	noarch
+Summary:        Icons for TigerVNC viewer
+Group:          User Interface/X
+BuildArch:      noarch
 
 %description icons
 This package contains icons for TigerVNC viewer
 
 %prep
-%setup -q -n %{name}-%{version}-%{snap}
+%setup -q -n %{name}-%{version}
 
 %patch4 -p1 -b .cookie
 %patch10 -p1 -b .ldnow
@@ -156,27 +163,26 @@ This package contains icons for TigerVNC viewer
 cp -r /usr/share/xorg-x11-server-source/* unix/xserver
 pushd unix/xserver
 for all in `find . -type f -perm -001`; do
-	chmod -x "$all"
+        chmod -x "$all"
 done
-patch -p1 -b --suffix .vnc < ../xserver114.patch
+%patch100 -p1 -b .xserver117
 popd
 
-%patch14 -p1 -b .glx
-
 # Applied Debian patch to fix busy loop when run from inetd in nowait
 # mode (bug #920373).
-%patch15 -p1 -b .inetd-nowait
+%patch14 -p1 -b .inetd-nowait
 
-%patch16 -p1 -b .setcursor-crash
+%patch15 -p1 -b .setcursor-crash
 
 # Synchronise manpages and --help output (bug #980870).
-%patch17 -p1 -b .manpages
+%patch16 -p1 -b .manpages
 
 # Don't use shebang in vncserver script.
-%patch18 -p1 -b .shebang
+%patch17 -p1 -b .shebang
 
-# source compatibility with xserver 1.15
-%patch19 -p1 -b .115
+# source compatibility with xserver 1.16 and 1.17
+%patch18 -p1 -b .xserver-1.16
+%patch19 -p1 -b .xserver-1.17
 
 # Avoid invalid read when ZRLE connection closed (upstream bug #133).
 %patch20 -p1 -b .zrle-crash
@@ -184,14 +190,33 @@ popd
 # Fixed viewer crash when cursor has not been set (bug #1051333).
 %patch21 -p1 -b .cursor
 
-# Use keyboard input code from tigervnc-1.3.0 (bug #1053536).
-%patch22 -p1 -b .input
-
 # Clearer xstartup file (bug #923655).
-%patch23 -p1 -b .xstartup
+%patch22 -p1 -b .xstartup
+
+# No warning when compiling with gcc's -Wformat-security option
+%patch23 -p1 -b .no-warning-with-wformat-security
+
+# Check the return value from XShmAttach
+%patch24 -p1 -b .check-return-value-from-xshmattach
+
+# Keep pointer in sync
+%patch25 -p1 -b .pointersync
 
-# Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928).
-%patch24 -p1 -b .CVE-2014-0011
+# Input reset fixes from upstream
+%patch26 -p1 -b .inputreset
+
+# Add IPv6 support
+%patch27 -p1 -b .ipv6-support
+
+# Set initial mode as prefered
+%patch28 -p1 -b .set-initial-mode-as-prefered
+
+# CVE-2014-8241 tigervnc: NULL pointer dereference flaw in XRegion
+%patch29 -p1 -b .tigervnc-CVE-2014-8241
+
+# CVE-2014-8240 tigervnc: integer overflow flaw, leading to a heap-based
+# buffer overflow in screen size handling
+%patch30 -p1 -b .tigervnc-1.3.1-CVE-2014-8240
 
 %build
 %ifarch sparcv9 sparc64 s390 s390x
@@ -207,24 +232,24 @@ make %{?_smp_mflags}
 pushd unix/xserver
 autoreconf -fiv
 %configure \
-	--disable-xorg --disable-xnest --disable-xvfb --disable-dmx \
-	--disable-xwin --disable-xephyr --disable-kdrive --with-pic \
-	--disable-static --disable-xinerama \
-	--with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \
-	--with-fontdir=%{_datadir}/X11/fonts \
-	--with-xkb-output=%{_localstatedir}/lib/xkb \
-	--enable-install-libxf86config \
-	--enable-glx --disable-dri --enable-dri2 \
-	--disable-wayland \
-	--disable-present \
-	--disable-config-dbus \
-	--disable-config-hal \
-	--disable-config-udev \
-	--with-dri-driver-path=%{_libdir}/dri \
-	--without-dtrace \
-	--disable-unit-tests \
-	--disable-devel-docs \
-	--disable-selective-werror
+        --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \
+        --disable-xwin --disable-xephyr --disable-kdrive --with-pic \
+        --disable-static --disable-xwayland \
+        --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \
+        --with-fontdir=%{_datadir}/X11/fonts \
+        --with-xkb-output=%{_localstatedir}/lib/xkb \
+        --enable-install-libxf86config \
+        --enable-glx --disable-dri --enable-dri2 \
+        --disable-wayland \
+        --disable-present \
+        --disable-config-dbus \
+        --disable-config-hal \
+        --disable-config-udev \
+        --with-dri-driver-path=%{_libdir}/dri \
+        --without-dtrace \
+        --disable-unit-tests \
+        --disable-devel-docs \
+        --disable-selective-werror
 
 make %{?_smp_mflags}
 popd
@@ -267,8 +292,8 @@ popd
 
 mkdir $RPM_BUILD_ROOT%{_datadir}/applications
 desktop-file-install \
-	--dir $RPM_BUILD_ROOT%{_datadir}/applications \
-	%{SOURCE6}
+        --dir $RPM_BUILD_ROOT%{_datadir}/applications \
+        %{SOURCE6}
 
 # Install Java applet
 pushd java
@@ -295,13 +320,13 @@ rm -rf $RPM_BUILD_ROOT
 %post
 touch -c %{_datadir}/icons/hicolor
 if [ -x %{_bindir}/gtk-update-icon-cache ]; then
-	%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
+        %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
 fi
 
 %postun
 touch -c %{_datadir}/icons/hicolor
 if [ -x %{_bindir}/gtk-update-icon-cache ]; then
-	%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
+        %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
 fi
 
 %post server
@@ -319,7 +344,7 @@ fi
 
 %files -f %{name}.lang
 %defattr(-,root,root,-)
-%doc README.txt
+%doc %{_docdir}/%{name}-%{version}/README.txt
 %{_bindir}/vncviewer
 %{_datadir}/applications/*
 %{_mandir}/man1/vncviewer.1*
@@ -355,13 +380,38 @@ fi
 %{_datadir}/vnc/classes/*
 
 %files license
-%doc LICENCE.TXT
+%doc %{_docdir}/%{name}-%{version}/LICENCE.TXT
 
 %files icons
 %defattr(-,root,root,-)
 %{_datadir}/icons/hicolor/*/apps/*
 
 %changelog
+* Wed Sep 02 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-3
+- Do not mention that display number is required in the file name
+  Resolves: bz#1195266
+
+* Thu Jul 30 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-2
+- Resolves: bz#1248422
+  CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws
+
+* Wed Apr 15 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-1
+- Drop unecessary patches
+- Re-base to 1.3.1 (bug #1199453)
+- Re-build against re-based xserver (bug #1194898)
+- Check the return value from XShmAttach (bug #1072733)
+- Add missing part of xserver114.patch (bug #1140603)
+- Keep pointer in sync (bug #1100661)
+- Make input device class global (bug #1119640)
+- Add IPv6 support (bug #1162722)
+- Set initial mode as prefered (bug #1181287)
+- Do not mention that display number is required in the file name (bug #1195266)
+- Enable Xinerama extension (bug #1199437)
+- Specify full path for runuser command (bug #1208817)
+
+* Tue Sep 23 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.31.20130314svn5065
+- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424).
+
 * Mon Mar 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.30.20130314svn5065
 - Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928).