diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/Vncviewer vnc_unixsrc/vncviewer/Vncviewer
--- vnc_unixsrc.orig/vncviewer/Vncviewer	2003-02-07 05:30:57.000000000 -0500
+++ vnc_unixsrc/vncviewer/Vncviewer	2008-08-24 16:26:01.000000000 -0400
@@ -1,20 +1,22 @@
 !
-! Application defaults file for vncviewer.
+! Application defaults file for SSVNC vncviewer.
+!
+! N.B.: You will need to rename this file to be "Ssvnc" instead of "Vncviewer"
 !
 
 
 !
 ! The title of the main window.  "%s" will be replaced by the desktop name.
-! 
+!
 
-Vncviewer.title: TightVNC: %s
+Ssvnc.title: SSVNC: %s Press F8 for Menu
 
 
 !
 ! Translations on the main window.
 !
 
-Vncviewer.translations:\
+Ssvnc.translations:\
   <Enter>: SelectionToVNC()\n\
   <Leave>: SelectionFromVNC()
 
@@ -23,7 +25,7 @@
 ! Uncomment to grab the keyboard in full-screen mode.
 !
 
-! Vncviewer.grabKeyboard: True
+! Ssvnc.grabKeyboard: True
 
 
 !
@@ -43,6 +45,9 @@
 *viewport.useRight: True
 *viewport*Scrollbar*thumb: None
 
+*viewport.horizontal.height:   6
+*viewport.vertical.width:   6
+
 
 !
 ! Default translations on desktop window.
@@ -50,89 +55,591 @@
 
 *desktop.baseTranslations:\
   <Key>F8: ShowPopup()\n\
+  <Key>F9: ToggleFullScreen()\n\
   <ButtonPress>: SendRFBEvent()\n\
   <ButtonRelease>: SendRFBEvent()\n\
   <Motion>: SendRFBEvent()\n\
   <KeyPress>: SendRFBEvent()\n\
   <KeyRelease>: SendRFBEvent()
 
+*viewport.horizontal.translations: #override\n\
+     <KeyPress>Right:  StartScroll(Forward)\n\
+     <KeyRelease>Right:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Left:  StartScroll(Backward)\n\
+     <KeyRelease>Left:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Next:  StartScroll(Forward)\n\
+     <KeyRelease>Next:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Prior:  StartScroll(Backward)\n\
+     <KeyRelease>Prior:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>z:  StartScroll(Forward)\n\
+     <KeyRelease>z:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>a:  StartScroll(Backward)\n\
+     <KeyRelease>a:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>f:  StartScroll(Forward)\n\
+     <KeyRelease>f:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>b:  StartScroll(Backward)\n\
+     <KeyRelease>b:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Down:  StartScroll(Forward)\n\
+     <KeyRelease>Down:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Up:  StartScroll(Backward)\n\
+     <KeyRelease>Up:  NotifyScroll(FullLength) EndScroll()
+
+*viewport.vertical.translations: #override\n\
+     <KeyPress>Down:  StartScroll(Forward)\n\
+     <KeyRelease>Down:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Up:  StartScroll(Backward)\n\
+     <KeyRelease>Up:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Next:  StartScroll(Forward)\n\
+     <KeyRelease>Next:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Prior:  StartScroll(Backward)\n\
+     <KeyRelease>Prior:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>z:  StartScroll(Forward)\n\
+     <KeyRelease>z:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>a:  StartScroll(Backward)\n\
+     <KeyRelease>a:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>f:  StartScroll(Forward)\n\
+     <KeyRelease>f:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>b:  StartScroll(Backward)\n\
+     <KeyRelease>b:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Right:  StartScroll(Forward)\n\
+     <KeyRelease>Right:  NotifyScroll(FullLength) EndScroll()\n\
+     <KeyPress>Left:  StartScroll(Backward)\n\
+     <KeyRelease>Left:  NotifyScroll(FullLength) EndScroll()
+
 
 !
 ! Dialog boxes
 !
 
 *serverDialog.dialog.label: VNC server:
+
 *serverDialog.dialog.value:
+
 *serverDialog.dialog.value.translations: #override\n\
-  <Key>Return: ServerDialogDone()
+     <Key>Return: ServerDialogDone()
+
+*ycropDialog.dialog.label: Y Crop (max-height in pixels):
+
+*ycropDialog.dialog.value:
+
+*ycropDialog.dialog.value.translations: #override\n\
+     <Key>Return: YCropDialogDone()
+
+*scbarDialog.dialog.label: Scroll Bars width:
+
+*scbarDialog.dialog.value:
+
+*scbarDialog.dialog.value.translations: #override\n\
+     <Key>Return: ScbarDialogDone()
+
+*scaleDialog.dialog.label: Integer n for 1/n server scaling:
+
+*scaleDialog.dialog.value:
+
+*scaleDialog.dialog.value.translations: #override\n\
+     <Key>Return: ScaleDialogDone()
 
 *passwordDialog.dialog.label: Password:
+
 *passwordDialog.dialog.value:
+
 *passwordDialog.dialog.value.AsciiSink.echo: False
+
 *passwordDialog.dialog.value.translations: #override\n\
-  <Key>Return: PasswordDialogDone()
+     <Key>Return: PasswordDialogDone()
 
 
 !
 ! Popup window appearance
 !
 
-*popup.title: TightVNC popup
+*popup.title: SSVNC popup
+
 *popup*background: grey
-*popup*font: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*
-*popup.buttonForm.Command.borderWidth: 0
-*popup.buttonForm.Toggle.borderWidth: 0
+
+*popup*font_old: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*
+
+*popup*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
+
+*popup.buttonForm*.Command.borderWidth: 0
+
+*popup.buttonForm*.Toggle.borderWidth: 0
+
+*scaleN.title: 1/n scale
+
+*scaleN*background: grey
+
+*scaleN*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
+
+*scaleN.buttonForm.Command.borderWidth: 0
+
+*scaleN.buttonForm.Toggle.borderWidth: 0
+
+*quality.title: quality
+
+*quality*background: grey
+
+*quality*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
+
+*quality.buttonForm.Command.borderWidth: 0
+
+*quality.buttonForm.Toggle.borderWidth: 0
+
+*compress.title: compress
+
+*compress*background: grey
+
+*compress*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
+
+*compress.buttonForm.Command.borderWidth: 0
+
+*compress.buttonForm.Toggle.borderWidth: 0
+
 
 !
 ! Translations on popup window - send key presses through
 !
 
 *popup.translations: #override <Message>WM_PROTOCOLS: HidePopup()
+
 *popup.buttonForm.translations: #override\n\
-  <KeyPress>: SendRFBEvent() HidePopup()
+     <KeyPress>: SendRFBEvent() HidePopup()
 
 
 !
 ! Popup buttons
 !
 
-*popupButtonCount: 8
+*popupButtonCount: 38
+
+*popupButtonBreak: 19
 
 *popup*button1.label: Dismiss popup
+
 *popup*button1.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: HidePopup()
+     <Btn1Down>,<Btn1Up>: HidePopup()
 
 *popup*button2.label: Quit viewer
+
 *popup*button2.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: Quit()
+     <Btn1Down>,<Btn1Up>: Quit()
+
+*popup*button3.label: Full screen  (also F9)
 
-*popup*button3.label: Full screen
 *popup*button3.type: toggle
+
 *popup*button3.translations: #override\n\
-  <Visible>: SetFullScreenState()\n\
-  <Btn1Down>,<Btn1Up>: toggle() HidePopup() ToggleFullScreen()
+     <Visible>: SetFullScreenState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleFullScreen() HidePopup()
 
 *popup*button4.label: Clipboard: local -> remote
+
 *popup*button4.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: SelectionToVNC(always) HidePopup()
+     <Btn1Down>,<Btn1Up>: SelectionToVNC(always) HidePopup()
 
 *popup*button5.label: Clipboard: local <- remote
+
 *popup*button5.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: SelectionFromVNC(always) HidePopup()
+     <Btn1Down>,<Btn1Up>: SelectionFromVNC(always) HidePopup()
 
 *popup*button6.label: Request refresh
+
 *popup*button6.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate) HidePopup()
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate) HidePopup()
 
 *popup*button7.label: Send ctrl-alt-del
+
 *popup*button7.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: SendRFBEvent(keydown,Control_L)\
-                       SendRFBEvent(keydown,Alt_L)\
-                       SendRFBEvent(key,Delete)\
-                       SendRFBEvent(keyup,Alt_L)\
-                       SendRFBEvent(keyup,Control_L)\
-                       HidePopup()
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(keydown,Control_L)     SendRFBEvent(keydown,Alt_L)     SendRFBEvent(key,Delete)     SendRFBEvent(keyup,Alt_L)     SendRFBEvent(keyup,Control_L)     HidePopup()
 
 *popup*button8.label: Send F8
+
 *popup*button8.translations: #override\n\
-  <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup()
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup()
+
+*popup*button9.label: Send F9
+
+*popup*button9.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F9) HidePopup()
+
+*popup*button10.label: ViewOnly
+
+*popup*button10.type: toggle
+
+*popup*button10.translations: #override\n\
+     <Visible>: SetViewOnlyState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleViewOnly() HidePopup()
+
+*popup*button11.label: Disable Bell
+
+*popup*button11.type: toggle
+
+*popup*button11.translations: #override\n\
+     <Visible>: SetBellState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleBell() HidePopup()
+
+*popup*button12.label: Cursor Shape
+
+*popup*button12.type: toggle
+
+*popup*button12.translations: #override\n\
+     <Visible>: SetCursorShapeState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleCursorShape() HidePopup()
+
+*popup*button13.label: X11 Cursor
+
+*popup*button13.type: toggle
+
+*popup*button13.translations: #override\n\
+     <Visible>: SetX11CursorState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleX11Cursor() HidePopup()
+
+*popup*button14.label: Cursor Alphablend
+
+*popup*button14.type: toggle
+
+*popup*button14.translations: #override\n\
+     <Visible>: SetCursorAlphaState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleCursorAlpha() HidePopup()
+
+*popup*button15.label: Toggle Tight/ZRLE
+
+*popup*button15.type: toggle
+
+*popup*button15.translations: #override\n\
+     <Visible>: SetZRLEState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleTightZRLE() HidePopup()
+
+*popup*button16.label: Toggle ZRLE/ZYWRLE
+
+*popup*button16.type: toggle
+
+*popup*button16.translations: #override\n\
+     <Visible>: SetZYWRLEState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleZRLEZYWRLE() HidePopup()
+
+*popup*button17.label: Quality Level
+
+*popup*button17.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowQuality()
+
+*popup*button18.label: Compress Level
+
+*popup*button18.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowCompress()
+
+*popup*button19.label: Disable JPEG
+
+*popup*button19.type: toggle
+
+*popup*button19.translations: #override\n\
+     <Visible>: SetNOJPEGState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleJPEG() HidePopup()
+
+*popup*button20.label: Full Color
+
+*popup*button20.type: toggle
+
+*popup*button20.translations: #override\n\
+     <Visible>: SetFullColorState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleFullColor() HidePopup()
+
+*popup*button21.label: Grey Scale (16 & 8-bpp)
+
+*popup*button21.type: toggle
+
+*popup*button21.translations: #override\n\
+     <Visible>: SetGreyScaleState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleGreyScale() HidePopup()
+
+*popup*button22.label: 16 bit color (BGR565)
+
+*popup*button22.type: toggle
+
+*popup*button22.translations: #override\n\
+     <Visible>: Set16bppState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle16bpp() HidePopup()
+
+*popup*button23.label: 8   bit color (BGR233)
+
+*popup*button23.type: toggle
+
+*popup*button23.translations: #override\n\
+     <Visible>: Set8bppState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle8bpp() HidePopup()
+
+*popup*button24.label: -     256 colors
+
+*popup*button24.type: toggle
+
+*popup*button24.translations: #override\n\
+     <Visible>: Set256ColorsState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle256Colors() HidePopup()
+
+*popup*button25.label: -       64 colors
+
+*popup*button25.type: toggle
+
+*popup*button25.translations: #override\n\
+     <Visible>: Set64ColorsState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle64Colors() HidePopup()
+
+*popup*button26.label: -         8 colors
+
+*popup*button26.type: toggle
+
+*popup*button26.translations: #override\n\
+     <Visible>: Set8ColorsState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle8Colors() HidePopup()
+
+*popup*button27.label: Set Y Crop (y-max)
+
+*popup*button27.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop()
+
+*popup*button28.label: Set Scrollbar Width
+
+*popup*button28.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() SetScbar()
+
+*popup*button29.label: UltraVNC Extensions:
+
+*popup*button29.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup()
+
+*popup*button30.label: - Set 1/n Server Scale
+
+*popup*button30.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN()
+
+*popup*button31.label: - Text Chat
+
+*popup*button31.type: toggle
+
+*popup*button31.translations: #override\n\
+     <Visible>: SetTextChatState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleTextChat() HidePopup()
+
+*popup*button32.label: - File Transfer
+
+*popup*button32.type: toggle
+
+*popup*button32.translations: #override\n\
+     <Visible>: SetFileXferState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleFileXfer() HidePopup()
+
+*popup*button33.label: - Single Window
+
+*popup*button33.type: toggle
+
+*popup*button33.translations: #override\n\
+     <Visible>: SetSingleWindowState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleSingleWindow() HidePopup()
+
+*popup*button34.label: - Disable Remote Input
+
+*popup*button34.type: toggle
+
+*popup*button34.translations: #override\n\
+     <Visible>: SetServerInputState()\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleServerInput() HidePopup()
+
+*popup*button35.label:
+
+*popup*button36.label:
+
+*popup*button37.label:
+
+*popup*button38.label:
+
+*scaleN*button0.label: Dismiss
+
+*scaleN*button0.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HideScaleN()
+
+*scaleN*button1.label: 1/1
+
+*scaleN*button1.translations: #override\n\
+     <Visible>: SetScaleNState(1)\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(1) HideScaleN()
+
+*scaleN*button2.label: 1/2
+
+*scaleN*button2.translations: #override\n\
+     <Visible>: SetScaleNState(2)\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(2) HideScaleN()
+
+*scaleN*button3.label: 1/3
+
+*scaleN*button3.translations: #override\n\
+     <Visible>: SetScaleNState(3)\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(3) HideScaleN()
+
+*scaleN*button4.label: 1/4
+
+*scaleN*button4.translations: #override\n\
+     <Visible>: SetScaleNState(4)\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(4) HideScaleN()
+
+*scaleN*button5.label: 1/5
+
+*scaleN*button5.translations: #override\n\
+     <Visible>: SetScaleNState(5)\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(5) HideScaleN()
+
+*scaleN*button6.label: Other
+
+*scaleN*button6.translations: #override\n\
+     <Visible>: SetScaleNState(6)\n\
+     <Btn1Down>,<Btn1Up>: HideScaleN() DoServerScale()
+
+*quality*buttonD.label: Dismiss
+
+*quality*buttonD.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HideQuality()
+
+*quality*button0.label: 0
+
+*quality*button0.type: toggle
+
+*quality*button0.translations: #override\n\
+     <Visible>: SetQualityState(0)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(0) HideQuality()
+
+*quality*button1.label: 1
+
+*quality*button1.type: toggle
+
+*quality*button1.translations: #override\n\
+     <Visible>: SetQualityState(1)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(1) HideQuality()
+
+*quality*button2.label: 2
+
+*quality*button2.type: toggle
+
+*quality*button2.translations: #override\n\
+     <Visible>: SetQualityState(2)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(2) HideQuality()
+
+*quality*button3.label: 3
+
+*quality*button3.type: toggle
+
+*quality*button3.translations: #override\n\
+     <Visible>: SetQualityState(3)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(3) HideQuality()
+
+*quality*button4.label: 4
+
+*quality*button4.type: toggle
+
+*quality*button4.translations: #override\n\
+     <Visible>: SetQualityState(4)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(4) HideQuality()
+
+*quality*button5.label: 5
+
+*quality*button5.type: toggle
+
+*quality*button5.translations: #override\n\
+     <Visible>: SetQualityState(5)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(5) HideQuality()
+
+*quality*button6.label: 6
+
+*quality*button6.type: toggle
+
+*quality*button6.translations: #override\n\
+     <Visible>: SetQualityState(6)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(6) HideQuality()
+
+*quality*button7.label: 7
+
+*quality*button7.type: toggle
+
+*quality*button7.translations: #override\n\
+     <Visible>: SetQualityState(7)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(7) HideQuality()
+
+*quality*button8.label: 8
+
+*quality*button8.type: toggle
+
+*quality*button8.translations: #override\n\
+     <Visible>: SetQualityState(8)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(8) HideQuality()
+
+*quality*button9.label: 9
+
+*quality*button9.type: toggle
+
+*quality*button9.translations: #override\n\
+     <Visible>: SetQualityState(9)\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(9) HideQuality()
+
+*compress*buttonD.label: Dismiss
+
+*compress*buttonD.translations: #override\n\
+     <Btn1Down>,<Btn1Up>: HideCompress()
+
+*compress*button0.label: 0
+
+*compress*button0.translations: #override\n\
+     <Visible>: SetCompressState(0)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(0) HideCompress()
+
+*compress*button1.label: 1
+
+*compress*button1.translations: #override\n\
+     <Visible>: SetCompressState(1)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(1) HideCompress()
+
+*compress*button2.label: 2
+
+*compress*button2.translations: #override\n\
+     <Visible>: SetCompressState(2)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(2) HideCompress()
+
+*compress*button3.label: 3
+
+*compress*button3.translations: #override\n\
+     <Visible>: SetCompressState(3)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(3) HideCompress()
+
+*compress*button4.label: 4
+
+*compress*button4.translations: #override\n\
+     <Visible>: SetCompressState(4)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(4) HideCompress()
+
+*compress*button5.label: 5
+
+*compress*button5.translations: #override\n\
+     <Visible>: SetCompressState(5)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(5) HideCompress()
+
+*compress*button6.label: 6
+
+*compress*button6.translations: #override\n\
+     <Visible>: SetCompressState(6)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(6) HideCompress()
+
+*compress*button7.label: 7
+
+*compress*button7.translations: #override\n\
+     <Visible>: SetCompressState(7)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(7) HideCompress()
+
+*compress*button8.label: 8
+
+*compress*button8.translations: #override\n\
+     <Visible>: SetCompressState(8)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(8) HideCompress()
+
+*compress*button9.label: 9
+
+*compress*button9.translations: #override\n\
+     <Visible>: SetCompressState(9)\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(9) HideCompress()
+
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/vncviewer/argsresources.c
--- vnc_unixsrc.orig/vncviewer/argsresources.c	2007-02-04 17:10:31.000000000 -0500
+++ vnc_unixsrc/vncviewer/argsresources.c	2010-04-18 12:39:55.000000000 -0400
@@ -31,9 +31,9 @@
 
 char *fallback_resources[] = {
 
-  "Vncviewer.title: TightVNC: %s",
+  "Ssvnc.title: SSVNC: %s - Press F8 for Menu",
 
-  "Vncviewer.translations:\
+  "Ssvnc.translations:\
     <Enter>: SelectionToVNC()\\n\
     <Leave>: SelectionFromVNC()",
 
@@ -45,8 +45,60 @@
   "*viewport.useRight: True",
   "*viewport*Scrollbar*thumb: None",
 
+           "*viewport.horizontal.height:   6 ",
+              "*viewport.vertical.width:   6 ",
+  "ssvnc*viewport.horizontal.height:   6 ",
+     "ssvnc*viewport.vertical.width:   6 ",
+
+  "*viewport.horizontal.translations: #override\\n\
+     <KeyPress>Right:  StartScroll(Forward)\\n\
+     <KeyRelease>Right:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Left:  StartScroll(Backward)\\n\
+     <KeyRelease>Left:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Next:  StartScroll(Forward)\\n\
+     <KeyRelease>Next:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Prior:  StartScroll(Backward)\\n\
+     <KeyRelease>Prior:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>z:  StartScroll(Forward)\\n\
+     <KeyRelease>z:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>a:  StartScroll(Backward)\\n\
+     <KeyRelease>a:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>f:  StartScroll(Forward)\\n\
+     <KeyRelease>f:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>b:  StartScroll(Backward)\\n\
+     <KeyRelease>b:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Down:  StartScroll(Forward)\\n\
+     <KeyRelease>Down:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Up:  StartScroll(Backward)\\n\
+     <KeyRelease>Up:  NotifyScroll(FullLength) EndScroll()",
+
+  "*viewport.vertical.translations: #override\\n\
+     <KeyPress>Down:  StartScroll(Forward)\\n\
+     <KeyRelease>Down:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Up:  StartScroll(Backward)\\n\
+     <KeyRelease>Up:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Next:  StartScroll(Forward)\\n\
+     <KeyRelease>Next:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Prior:  StartScroll(Backward)\\n\
+     <KeyRelease>Prior:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>z:  StartScroll(Forward)\\n\
+     <KeyRelease>z:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>a:  StartScroll(Backward)\\n\
+     <KeyRelease>a:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>f:  StartScroll(Forward)\\n\
+     <KeyRelease>f:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>b:  StartScroll(Backward)\\n\
+     <KeyRelease>b:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Right:  StartScroll(Forward)\\n\
+     <KeyRelease>Right:  NotifyScroll(FullLength) EndScroll()\\n\
+     <KeyPress>Left:  StartScroll(Backward)\\n\
+     <KeyRelease>Left:  NotifyScroll(FullLength) EndScroll()",
+
   "*desktop.baseTranslations:\
-     <Key>F8: ShowPopup()\\n\
+     <KeyPress>F8:  ShowPopup()\\n\
+     <KeyRelease>F8:  Noop()\\n\
+     <KeyPress>F9:  ToggleFullScreen()\\n\
+     <KeyRelease>F9:  Noop()\\n\
      <ButtonPress>: SendRFBEvent()\\n\
      <ButtonRelease>: SendRFBEvent()\\n\
      <Motion>: SendRFBEvent()\\n\
@@ -55,26 +107,137 @@
 
   "*serverDialog.dialog.label: VNC server:",
   "*serverDialog.dialog.value:",
+  "*serverDialog.dialog.value.width: 150",
   "*serverDialog.dialog.value.translations: #override\\n\
      <Key>Return: ServerDialogDone()",
 
-  "*passwordDialog.dialog.label: Password:",
+  "*userDialog.dialog.label: SSVNC: Enter Username",
+  "*userDialog.dialog.value:",
+  "*userDialog.dialog.value.width: 150",
+  "*userDialog.dialog.value.translations: #override\\n\
+     <Key>Return: UserDialogDone()",
+
+  "*scaleDialog.dialog.label: Scale: Enter 'none' (same as '1' or '1.0'),\\na geometry WxH (e.g. 1280x1024), or\\na fraction (e.g. 0.75 or 3/4).\\nUse 'fit' for full screen size.\\nUse 'auto' to match window size.\\nCurrent value:",
+  "*scaleDialog.dialog.value:",
+  "*scaleDialog.dialog.value.translations: #override\\n\
+     <KeyRelease>Return: ScaleDialogDone()",
+
+  "*escapeDialog.dialog.label: Escape Keys:  Enter a comma separated list of modifier keys to be the\\n"
+                              "'escape sequence'.  When these keys are held down, the next keystroke is\\n"
+                              "interpreted locally to invoke a special action instead of being sent to\\n"
+                              "the remote VNC server.  In other words, a set of 'Hot Keys'.\\n"
+                              "\\n"
+                              "To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\\n"
+                              "\\n"
+                              "Here is the list of hot-key mappings to special actions:\\n"
+                              "\\n"
+                              "   r: refresh desktop  b: toggle bell   c: toggle full-color\\n"
+                              "   f: file transfer    x: x11cursor     z: toggle Tight/ZRLE\\n"
+                              "   l: full screen      g: graball       e: escape keys dialog\\n"
+                              "   s: scale dialog     +: scale up (=)  -: scale down (_)\\n"
+                              "   t: text chat                         a: alphablend cursor\\n"
+                              "   V: toggle viewonly  Q: quit viewer   1 2 3 4 5 6: UltraVNC scale 1/n\\n"
+                              "\\n"
+                              "   Arrow keys:         pan the viewport about 10% for each keypress.\\n"
+                              "   PageUp / PageDown:  pan the viewport by a screenful vertically.\\n"
+                              "   Home   / End:       pan the viewport by a screenful horizontally.\\n"
+                              "   KeyPad Arrow keys:  pan the viewport by 1 pixel for each keypress.\\n"
+                              "   Dragging the Mouse with Button1 pressed also pans the viewport.\\n"
+                              "   Clicking Mouse Button3 brings up the Popup Menu.\\n"
+                              "\\n"
+                              "The above mappings are *always* active in ViewOnly mode, unless you set the\\n"
+                              "Escape Keys value to 'never'.\\n"
+                              "\\n"
+                              "x11vnc -appshare hot-keys:  x11vnc has a simple application sharing mode\\n"
+                              "that enables the viewer-side to move, resize, or raise the remote toplevel\\n"
+                              "windows.  To enable it, hold down Shift + the Escape Keys and press these:\\n"
+                              "\\n"
+                              "   Arrow keys:              move the remote window around in its desktop.\\n"
+                              "   PageUp/PageDn/Home/End:  resize the remote window.\\n"
+                              "   +/-                      raise or lower the remote window.\\n"
+                              "   M or Button1 move win to local position;  D or Button3: delete remote win.\\n"
+                              "\\n"
+                              "If the Escape Keys value below is set to 'default' then a fixed list of\\n"
+                              "modifier keys is used.  For Unix it is: Alt_L,Super_L and for MacOSX it is\\n"
+                              "Control_L,Meta_L.  Note: the Super_L key usually has a Windows(TM) Flag.\\n"
+                              "Also note the _L and _R mean the key is on the LEFT or RIGHT side of keyboard.\\n"
+                              "\\n"
+                              "On Unix   the default is Alt and Windows keys on Left side of keyboard.\\n"
+                              "On MacOSX the default is Control and Command keys on Left side of keyboard.\\n"
+                              "\\n"
+                              "Example: Press and hold the Alt and Windows keys on the LEFT side of the\\n"
+                              "keyboard and then press 'c' to toggle the full-color state.  Or press 't'\\n"
+                              "to toggle the ultravnc Text Chat window, etc.\\n"
+                              "\\n"
+                              "To use something besides the default, supply a comma separated list (or a\\n"
+                              "single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\\n"
+                              "Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\\n"
+                              "\\n"
+                              "Current Escape Keys Value:",
+  "*escapeDialog.dialog.value:",
+  "*escapeDialog.dialog.value.width: 280",
+  "*escapeDialog.dialog.value.translations: #override\\n\
+     <KeyRelease>Return: EscapeDialogDone()",
+
+  "*ycropDialog.dialog.label: Y Crop (max-height in pixels):",
+  "*ycropDialog.dialog.value:",
+  "*ycropDialog.dialog.value.translations: #override\\n\
+     <KeyRelease>Return: YCropDialogDone()",
+
+  "*scbarDialog.dialog.label: Scroll Bars width:",
+  "*scbarDialog.dialog.value:",
+  "*scbarDialog.dialog.value.translations: #override\\n\
+     <KeyRelease>Return: ScbarDialogDone()",
+
+  "*scaleNDialog.dialog.label: Integer n for 1/n server scaling:",
+  "*scaleNDialog.dialog.value:",
+  "*scaleNDialog.dialog.value.translations: #override\\n\
+     <KeyRelease>Return: ScaleNDialogDone()",
+
+  "*passwordDialog.dialog.label: SSVNC: Enter Password",
   "*passwordDialog.dialog.value:",
+  "*passwordDialog.dialog.value.width: 150",
   "*passwordDialog.dialog.value.AsciiSink.echo: False",
   "*passwordDialog.dialog.value.translations: #override\\n\
      <Key>Return: PasswordDialogDone()",
 
-  "*popup.title: TightVNC popup",
+  "*popup.title: SSVNC popup",
   "*popup*background: grey",
-  "*popup*font: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*",
-  "*popup.buttonForm.Command.borderWidth: 0",
-  "*popup.buttonForm.Toggle.borderWidth: 0",
+  "*popup*font_old: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*",
+  "*popup*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
+  "*popup.buttonForm*.Command.borderWidth: 0",
+  "*popup.buttonForm*.Toggle.borderWidth: 0",
+
+  "*scaleN.title: 1/n scale",
+  "*scaleN*background: grey",
+  "*scaleN*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
+  "*scaleN.buttonForm.Command.borderWidth: 0",
+  "*scaleN.buttonForm.Toggle.borderWidth: 0",
+
+  "*turboVNC.title: TurboVNC",
+  "*turboVNC*background: grey",
+  "*turboVNC*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
+  "*turboVNC.buttonForm.Command.borderWidth: 0",
+  "*turboVNC.buttonForm.Toggle.borderWidth: 0",
+
+  "*quality.title: quality",
+  "*quality*background: grey",
+  "*quality*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
+  "*quality.buttonForm.Command.borderWidth: 0",
+  "*quality.buttonForm.Toggle.borderWidth: 0",
+
+  "*compress.title: compress",
+  "*compress*background: grey",
+  "*compress*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
+  "*compress.buttonForm.Command.borderWidth: 0",
+  "*compress.buttonForm.Toggle.borderWidth: 0",
 
   "*popup.translations: #override <Message>WM_PROTOCOLS: HidePopup()",
   "*popup.buttonForm.translations: #override\\n\
      <KeyPress>: SendRFBEvent() HidePopup()",
 
-  "*popupButtonCount: 8",
+  "*popupButtonCount: 44",
+  "*popupButtonBreak: 22",
 
   "*popup*button1.label: Dismiss popup",
   "*popup*button1.translations: #override\\n\
@@ -84,7 +247,7 @@
   "*popup*button2.translations: #override\\n\
      <Btn1Down>,<Btn1Up>: Quit()",
 
-  "*popup*button3.label: Full screen",
+  "*popup*button3.label: Full screen  (also F9)",
   "*popup*button3.type: toggle",
   "*popup*button3.translations: #override\\n\
      <Visible>: SetFullScreenState()\\n\
@@ -105,16 +268,426 @@
   "*popup*button7.label: Send ctrl-alt-del",
   "*popup*button7.translations: #override\\n\
      <Btn1Down>,<Btn1Up>: SendRFBEvent(keydown,Control_L)\
-                          SendRFBEvent(keydown,Alt_L)\
-                          SendRFBEvent(key,Delete)\
-                          SendRFBEvent(keyup,Alt_L)\
-                          SendRFBEvent(keyup,Control_L)\
-                          HidePopup()",
+     SendRFBEvent(keydown,Alt_L)\
+     SendRFBEvent(key,Delete)\
+     SendRFBEvent(keyup,Alt_L)\
+     SendRFBEvent(keyup,Control_L)\
+     HidePopup()",
 
   "*popup*button8.label: Send F8",
   "*popup*button8.translations: #override\\n\
      <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup()",
 
+  "*popup*button9.label: Send F9",
+  "*popup*button9.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F9) HidePopup()",
+
+  "*popup*button10.label: ViewOnly",
+  "*popup*button10.type: toggle",
+  "*popup*button10.translations: #override\\n\
+     <Visible>: SetViewOnlyState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleViewOnly() HidePopup()",
+
+  "*popup*button11.label: Disable Bell",
+  "*popup*button11.type: toggle",
+  "*popup*button11.translations: #override\\n\
+     <Visible>: SetBellState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleBell() HidePopup()",
+
+  "*popup*button12.label: Cursor Shape",
+  "*popup*button12.type: toggle",
+  "*popup*button12.translations: #override\\n\
+     <Visible>: SetCursorShapeState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleCursorShape() HidePopup()",
+
+  "*popup*button13.label: X11 Cursor",
+  "*popup*button13.type: toggle",
+  "*popup*button13.translations: #override\\n\
+     <Visible>: SetX11CursorState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleX11Cursor() HidePopup()",
+
+  "*popup*button14.label: Cursor Alphablend",
+  "*popup*button14.type: toggle",
+  "*popup*button14.translations: #override\\n\
+     <Visible>: SetCursorAlphaState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleCursorAlpha() HidePopup()",
+
+  "*popup*button15.label: Toggle Tight/Hextile",
+  "*popup*button15.type: toggle",
+  "*popup*button15.translations: #override\\n\
+     <Visible>: SetHextileState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleTightHextile() HidePopup()",
+
+  "*popup*button16.label: Toggle Tight/ZRLE",
+  "*popup*button16.type: toggle",
+  "*popup*button16.translations: #override\\n\
+     <Visible>: SetZRLEState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleTightZRLE() HidePopup()",
+
+  "*popup*button17.label: Toggle ZRLE/ZYWRLE",
+  "*popup*button17.type: toggle",
+  "*popup*button17.translations: #override\\n\
+     <Visible>: SetZYWRLEState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleZRLEZYWRLE() HidePopup()",
+
+  "*popup*button18.label: Quality Level",
+  "*popup*button18.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowQuality()",
+
+  "*popup*button19.label: Compress Level",
+  "*popup*button19.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowCompress()",
+
+  "*popup*button20.label: Disable JPEG",
+  "*popup*button20.type: toggle",
+  "*popup*button20.translations: #override\\n\
+     <Visible>: SetNOJPEGState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleJPEG() HidePopup()",
+
+  "*popup*button21.label: TurboVNC Settings",
+  "*popup*button21.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowTurboVNC()",
+
+  "*popup*button22.label: Pipeline Updates",
+  "*popup*button22.type: toggle",
+  "*popup*button22.translations: #override\\n\
+     <Visible>: SetPipelineUpdates()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() TogglePipelineUpdates() HidePopup()",
+
+  "*popup*button23.label: Full Color",
+  "*popup*button23.type: toggle",
+  "*popup*button23.translations: #override\\n\
+     <Visible>: SetFullColorState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleFullColor() HidePopup()",
+
+  "*popup*button24.label: Grey Scale (16 & 8-bpp)",
+  "*popup*button24.type: toggle",
+  "*popup*button24.translations: #override\\n\
+     <Visible>: SetGreyScaleState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleGreyScale() HidePopup()",
+
+  "*popup*button25.label: 16 bit color (BGR565)",
+  "*popup*button25.type: toggle",
+  "*popup*button25.translations: #override\\n\
+     <Visible>: Set16bppState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle16bpp() HidePopup()",
+
+  "*popup*button26.label: 8   bit color (BGR233)",
+  "*popup*button26.type: toggle",
+  "*popup*button26.translations: #override\\n\
+     <Visible>: Set8bppState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle8bpp() HidePopup()",
+
+  "*popup*button27.label: -     256 colors",
+  "*popup*button27.type: toggle",
+  "*popup*button27.translations: #override\\n\
+     <Visible>: Set256ColorsState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle256Colors() HidePopup()",
+
+  "*popup*button28.label: -       64 colors",
+  "*popup*button28.type: toggle",
+  "*popup*button28.translations: #override\\n\
+     <Visible>: Set64ColorsState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle64Colors() HidePopup()",
+
+  "*popup*button29.label: -         8 colors",
+  "*popup*button29.type: toggle",
+  "*popup*button29.translations: #override\\n\
+     <Visible>: Set8ColorsState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() Toggle8Colors() HidePopup()",
+
+  "*popup*button30.label: Scale Viewer",
+  "*popup*button30.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() SetScale()",
+
+  "*popup*button31.label: Escape Keys: Toggle",
+  "*popup*button31.type: toggle",
+  "*popup*button31.translations: #override\\n\
+     <Visible>: SetEscapeKeysState()\\n\
+     <Btn1Down>, <Btn1Up>: toggle() ToggleEscapeActive() HidePopup()",
+
+  "*popup*button32.label: Escape Keys: Help+Set",
+  "*popup*button32.translations: #override\\n\
+      <Btn1Down>, <Btn1Up>: HidePopup() SetEscapeKeys()",
+
+  "*popup*button33.label: Set Y Crop (y-max)",
+  "*popup*button33.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop()",
+
+  "*popup*button34.label: Set Scrollbar Width",
+  "*popup*button34.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() SetScbar()",
+
+  "*popup*button35.label: XGrabServer",
+  "*popup*button35.type: toggle",
+  "*popup*button35.translations: #override\\n\
+     <Visible>: SetXGrabState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleXGrab() HidePopup()",
+
+  "*popup*button36.label: UltraVNC Extensions:",
+  "*popup*button36.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup()",
+
+  "*popup*button37.label: - Set 1/n Server Scale",
+  "*popup*button37.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN()",
+
+  "*popup*button38.label: - Text Chat",
+  "*popup*button38.type: toggle",
+  "*popup*button38.translations: #override\\n\
+     <Visible>: SetTextChatState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleTextChat() HidePopup()",
+
+  "*popup*button39.label: - File Transfer",
+  "*popup*button39.type: toggle",
+  "*popup*button39.translations: #override\\n\
+     <Visible>: SetFileXferState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleFileXfer() HidePopup()",
+
+  "*popup*button40.label: - Single Window",
+  "*popup*button40.type: toggle",
+  "*popup*button40.translations: #override\\n\
+     <Visible>: SetSingleWindowState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleSingleWindow() HidePopup()",
+
+  "*popup*button41.label: - Disable Remote Input",
+  "*popup*button41.type: toggle",
+  "*popup*button41.translations: #override\\n\
+     <Visible>: SetServerInputState()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleServerInput() HidePopup()",
+
+  "*popup*button42.label: Send Clipboard not Primary",
+  "*popup*button42.type: toggle",
+  "*popup*button42.translations: #override\\n\
+     <Visible>: SetSendClipboard()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleSendClipboard() HidePopup()",
+
+  "*popup*button43.label: Send Selection Every time",
+  "*popup*button43.type: toggle",
+  "*popup*button43.translations: #override\\n\
+     <Visible>: SetSendAlways()\\n\
+     <Btn1Down>,<Btn1Up>: toggle() ToggleSendAlways() HidePopup()",
+
+  "*popup*button44.label: ",
+
+  "*turboVNC*button0.label: Dismiss",
+  "*turboVNC*button0.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HideTurboVNC()",
+
+  "*turboVNC*button1.label: High Quality (LAN)",
+  "*turboVNC*button1.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(1)",
+
+  "*turboVNC*button2.label: Medium Quality",
+  "*turboVNC*button2.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(2)",
+
+  "*turboVNC*button3.label: Low Quality (WAN)",
+  "*turboVNC*button3.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(3)",
+
+  "*turboVNC*button4.label: Lossless (Gigabit)",
+  "*turboVNC*button4.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(4)",
+
+  "*turboVNC*button5.label: Lossless Zlib (WAN)",
+  "*turboVNC*button5.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(5)",
+
+  "*turboVNC*button6.label: Subsampling:",
+
+  "*turboVNC*button7.label: -           None",
+  "*turboVNC*button7.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(6)",
+
+  "*turboVNC*button8.label: -           2X",
+  "*turboVNC*button8.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(7)",
+
+  "*turboVNC*button9.label: -           4X",
+  "*turboVNC*button9.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(8)",
+
+  "*turboVNC*button10.label: -          Gray",
+  "*turboVNC*button10.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(9)",
+
+  "*turboVNC*button11.label: Lossless Refresh",
+  "*turboVNC*button11.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SetTurboVNC(10)",
+
+  "*turboVNC*button12.label: Lossy Refresh",
+  "*turboVNC*button12.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate)",
+
+  "*turboVNC*buttonNone.label: Not Compiled with\\nTurboVNC Support.",
+  "*turboVNC*buttonNone.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HideTurboVNC()",
+
+  "*qualLabel.label: JPEG Image Quality:",
+  "*qualBar.length: 100",
+  "*qualBar.width: 130",
+  "*qualBar.orientation: horizontal",
+  "*qualBar.translations: #override\\n\
+     <Btn1Down>: StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\
+     <Btn1Motion>: MoveThumb() NotifyThumb()\\n\
+     <Btn3Down>: StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\
+     <Btn3Motion>: MoveThumb() NotifyThumb()",
+    
+  "*qualText.label: 000",
+
+  "*scaleN*button0.label: Dismiss",
+  "*scaleN*button0.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HideScaleN()",
+
+  "*scaleN*button1.label: 1/1",
+  "*scaleN*button1.translations: #override\\n\
+     <Visible>: SetScaleNState(1)\\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(1) HideScaleN()",
+
+  "*scaleN*button2.label: 1/2",
+  "*scaleN*button2.translations: #override\\n\
+     <Visible>: SetScaleNState(2)\\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(2) HideScaleN()",
+
+  "*scaleN*button3.label: 1/3",
+  "*scaleN*button3.translations: #override\\n\
+     <Visible>: SetScaleNState(3)\\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(3) HideScaleN()",
+
+  "*scaleN*button4.label: 1/4",
+  "*scaleN*button4.translations: #override\\n\
+     <Visible>: SetScaleNState(4)\\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(4) HideScaleN()",
+
+  "*scaleN*button5.label: 1/5",
+  "*scaleN*button5.translations: #override\\n\
+     <Visible>: SetScaleNState(5)\\n\
+     <Btn1Down>,<Btn1Up>: SetScaleN(5) HideScaleN()",
+
+  "*scaleN*button6.label: Other",
+  "*scaleN*button6.translations: #override\\n\
+     <Visible>: SetScaleNState(6)\\n\
+     <Btn1Down>,<Btn1Up>: HideScaleN() DoServerScale()",
+
+  "*quality*buttonD.label: Dismiss",
+  "*quality*buttonD.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HideQuality()",
+
+  "*quality*button0.label: 0",
+  "*quality*button0.type: toggle",
+  "*quality*button0.translations: #override\\n\
+     <Visible>: SetQualityState(0)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(0) HideQuality()",
+
+  "*quality*button1.label: 1",
+  "*quality*button1.type: toggle",
+  "*quality*button1.translations: #override\\n\
+     <Visible>: SetQualityState(1)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(1) HideQuality()",
+
+  "*quality*button2.label: 2",
+  "*quality*button2.type: toggle",
+  "*quality*button2.translations: #override\\n\
+     <Visible>: SetQualityState(2)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(2) HideQuality()",
+
+  "*quality*button3.label: 3",
+  "*quality*button3.type: toggle",
+  "*quality*button3.translations: #override\\n\
+     <Visible>: SetQualityState(3)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(3) HideQuality()",
+
+  "*quality*button4.label: 4",
+  "*quality*button4.type: toggle",
+  "*quality*button4.translations: #override\\n\
+     <Visible>: SetQualityState(4)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(4) HideQuality()",
+
+  "*quality*button5.label: 5",
+  "*quality*button5.type: toggle",
+  "*quality*button5.translations: #override\\n\
+     <Visible>: SetQualityState(5)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(5) HideQuality()",
+
+  "*quality*button6.label: 6",
+  "*quality*button6.type: toggle",
+  "*quality*button6.translations: #override\\n\
+     <Visible>: SetQualityState(6)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(6) HideQuality()",
+
+  "*quality*button7.label: 7",
+  "*quality*button7.type: toggle",
+  "*quality*button7.translations: #override\\n\
+     <Visible>: SetQualityState(7)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(7) HideQuality()",
+
+  "*quality*button8.label: 8",
+  "*quality*button8.type: toggle",
+  "*quality*button8.translations: #override\\n\
+     <Visible>: SetQualityState(8)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(8) HideQuality()",
+
+  "*quality*button9.label: 9",
+  "*quality*button9.type: toggle",
+  "*quality*button9.translations: #override\\n\
+     <Visible>: SetQualityState(9)\\n\
+     <Btn1Down>,<Btn1Up>: SetQuality(9) HideQuality()",
+
+  "*compress*buttonD.label: Dismiss",
+  "*compress*buttonD.translations: #override\\n\
+     <Btn1Down>,<Btn1Up>: HideCompress()",
+
+  "*compress*button0.label: 0",
+  "*compress*button0.translations: #override\\n\
+     <Visible>: SetCompressState(0)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(0) HideCompress()",
+
+  "*compress*button1.label: 1",
+  "*compress*button1.translations: #override\\n\
+     <Visible>: SetCompressState(1)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(1) HideCompress()",
+
+  "*compress*button2.label: 2",
+  "*compress*button2.translations: #override\\n\
+     <Visible>: SetCompressState(2)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(2) HideCompress()",
+
+  "*compress*button3.label: 3",
+  "*compress*button3.translations: #override\\n\
+     <Visible>: SetCompressState(3)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(3) HideCompress()",
+
+  "*compress*button4.label: 4",
+  "*compress*button4.translations: #override\\n\
+     <Visible>: SetCompressState(4)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(4) HideCompress()",
+
+  "*compress*button5.label: 5",
+  "*compress*button5.translations: #override\\n\
+     <Visible>: SetCompressState(5)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(5) HideCompress()",
+
+  "*compress*button6.label: 6",
+  "*compress*button6.translations: #override\\n\
+     <Visible>: SetCompressState(6)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(6) HideCompress()",
+
+  "*compress*button7.label: 7",
+  "*compress*button7.translations: #override\\n\
+     <Visible>: SetCompressState(7)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(7) HideCompress()",
+
+  "*compress*button8.label: 8",
+  "*compress*button8.translations: #override\\n\
+     <Visible>: SetCompressState(8)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(8) HideCompress()",
+
+  "*compress*button9.label: 9",
+  "*compress*button9.translations: #override\\n\
+     <Visible>: SetCompressState(9)\\n\
+     <Btn1Down>,<Btn1Up>: SetCompress(9) HideCompress()",
+
   NULL
 };
 
@@ -124,7 +697,7 @@
  * from a dialog box.
  */
 
-char vncServerHost[256];
+char vncServerHost[1024];
 int vncServerPort = 0;
 
 
@@ -135,6 +708,7 @@
  */
 
 AppData appData;
+AppData appDataNew;
 
 static XtResource appDataResourceList[] = {
   {"shareDesktop", "ShareDesktop", XtRBool, sizeof(Bool),
@@ -155,14 +729,44 @@
   {"userLogin", "UserLogin", XtRString, sizeof(String),
    XtOffsetOf(AppData, userLogin), XtRImmediate, (XtPointer) 0},
 
+  {"unixPW", "UnixPW", XtRString, sizeof(String),
+   XtOffsetOf(AppData, unixPW), XtRImmediate, (XtPointer) 0},
+
+  {"msLogon", "MSLogon", XtRString, sizeof(String),
+   XtOffsetOf(AppData, msLogon), XtRImmediate, (XtPointer) 0},
+
+  {"repeaterUltra", "RepeaterUltra", XtRString, sizeof(String),
+   XtOffsetOf(AppData, repeaterUltra), XtRImmediate, (XtPointer) 0},
+
+  {"ultraDSM", "UltraDSM", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, ultraDSM), XtRImmediate, (XtPointer) False},
+
+  {"acceptPopup", "AcceptPopup", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, acceptPopup), XtRImmediate, (XtPointer) False},
+
+  {"rfbVersion", "RfbVersion", XtRString, sizeof(String),
+   XtOffsetOf(AppData, rfbVersion), XtRImmediate, (XtPointer) 0},
+
   {"passwordDialog", "PasswordDialog", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, passwordDialog), XtRImmediate, (XtPointer) False},
 
   {"encodings", "Encodings", XtRString, sizeof(String),
    XtOffsetOf(AppData, encodingsString), XtRImmediate, (XtPointer) 0},
 
-  {"useBGR233", "UseBGR233", XtRBool, sizeof(Bool),
-   XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) False},
+  {"useBGR233", "UseBGR233", XtRInt, sizeof(int),
+   XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) 0},
+
+  {"useBGR565", "UseBGR565", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useBGR565), XtRImmediate, (XtPointer) False},
+
+  {"useGreyScale", "UseGreyScale", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useGreyScale), XtRImmediate, (XtPointer) False},
+
+  {"yCrop", "yCrop", XtRInt, sizeof(int),
+   XtOffsetOf(AppData, yCrop), XtRImmediate, (XtPointer) 0},
+
+  {"sbWidth", "sbWidth", XtRInt, sizeof(int),
+   XtOffsetOf(AppData, sbWidth), XtRImmediate, (XtPointer) 2},
 
   {"nColours", "NColours", XtRInt, sizeof(int),
    XtOffsetOf(AppData, nColours), XtRImmediate, (XtPointer) 256},
@@ -179,9 +783,12 @@
   {"requestedDepth", "RequestedDepth", XtRInt, sizeof(int),
    XtOffsetOf(AppData, requestedDepth), XtRImmediate, (XtPointer) 0},
 
-  {"useSharedMemory", "UseSharedMemory", XtRBool, sizeof(Bool),
+  {"useShm", "UseShm", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, useShm), XtRImmediate, (XtPointer) True},
 
+  {"termChat", "TermChat", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, termChat), XtRImmediate, (XtPointer) False},
+
   {"wmDecorationWidth", "WmDecorationWidth", XtRInt, sizeof(int),
    XtOffsetOf(AppData, wmDecorationWidth), XtRImmediate, (XtPointer) 4},
 
@@ -191,6 +798,9 @@
   {"popupButtonCount", "PopupButtonCount", XtRInt, sizeof(int),
    XtOffsetOf(AppData, popupButtonCount), XtRImmediate, (XtPointer) 0},
 
+  {"popupButtonBreak", "PopupButtonBreak", XtRInt, sizeof(int),
+   XtOffsetOf(AppData, popupButtonBreak), XtRImmediate, (XtPointer) 0},
+
   {"debug", "Debug", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, debug), XtRImmediate, (XtPointer) False},
 
@@ -206,11 +816,13 @@
   {"bumpScrollPixels", "BumpScrollPixels", XtRInt, sizeof(int),
    XtOffsetOf(AppData, bumpScrollPixels), XtRImmediate, (XtPointer) 20},
 
+  /* hardwired compress -1 vs . 7 */
   {"compressLevel", "CompressionLevel", XtRInt, sizeof(int),
    XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1},
 
+  /* hardwired quality was 6 */
   {"qualityLevel", "QualityLevel", XtRInt, sizeof(int),
-   XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) 6},
+   XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) -1},
 
   {"enableJPEG", "EnableJPEG", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, enableJPEG), XtRImmediate, (XtPointer) True},
@@ -218,14 +830,97 @@
   {"useRemoteCursor", "UseRemoteCursor", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, useRemoteCursor), XtRImmediate, (XtPointer) True},
 
+  {"useCursorAlpha", "UseCursorAlpha", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useCursorAlpha), XtRImmediate, (XtPointer) False},
+
+  {"useRawLocal", "UseRawLocal", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useRawLocal), XtRImmediate, (XtPointer) False},
+
+  {"notty", "NoTty", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, notty), XtRImmediate, (XtPointer) False},
+
   {"useX11Cursor", "UseX11Cursor", XtRBool, sizeof(Bool),
    XtOffsetOf(AppData, useX11Cursor), XtRImmediate, (XtPointer) False},
 
+  {"useBell", "UseBell", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useBell), XtRImmediate, (XtPointer) True},
+
   {"grabKeyboard", "GrabKeyboard", XtRBool, sizeof(Bool),
-   XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) False},
+   XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) True},
 
   {"autoPass", "AutoPass", XtRBool, sizeof(Bool),
-   XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False}
+   XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False},
+
+  {"grabAll", "GrabAll", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, grabAll), XtRImmediate, (XtPointer) False},
+
+  {"useXserverBackingStore", "UseXserverBackingStore", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, useXserverBackingStore), XtRImmediate, (XtPointer) False},
+
+  {"overrideRedir", "OverrideRedir", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, overrideRedir), XtRImmediate, (XtPointer) True},
+
+  {"serverInput", "ServerInput", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, serverInput), XtRImmediate, (XtPointer) True},
+
+  {"singleWindow", "SingleWindow", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, singleWindow), XtRImmediate, (XtPointer) False},
+
+  {"serverScale", "ServerScale", XtRInt, sizeof(int),
+   XtOffsetOf(AppData, serverScale), XtRImmediate, (XtPointer) 1},
+
+  {"chatActive", "ChatActive", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, chatActive), XtRImmediate, (XtPointer) False},
+
+  {"chatOnly", "ChatOnly", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, chatOnly), XtRImmediate, (XtPointer) False},
+
+  {"fileActive", "FileActive", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, fileActive), XtRImmediate, (XtPointer) False},
+
+  {"popupFix", "PopupFix", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, popupFix), XtRImmediate, (XtPointer) False},
+
+  {"scale", "Scale", XtRString, sizeof(String),
+   XtOffsetOf(AppData, scale), XtRImmediate, (XtPointer) 0},
+
+  {"pipelineUpdates", "PipelineUpdates", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, pipelineUpdates), XtRImmediate, (XtPointer)
+#ifdef TURBOVNC
+ True},
+#else
+#if 0
+ False},
+#else
+ True},
+#endif
+#endif
+
+  {"noipv4", "noipv4", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, noipv4), XtRImmediate, (XtPointer) False},
+
+  {"noipv6", "noipv6", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, noipv6), XtRImmediate, (XtPointer) False},
+
+  {"sendClipboard", "SendClipboard", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, sendClipboard), XtRImmediate, (XtPointer) False},
+
+  {"sendAlways", "SendAlways", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, sendAlways), XtRImmediate, (XtPointer) False},
+
+  {"recvText", "RecvText", XtRString, sizeof(String),
+   XtOffsetOf(AppData, recvText), XtRImmediate, (XtPointer) 0},
+
+  {"appShare", "AppShare", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, appShare), XtRImmediate, (XtPointer) False},
+
+  {"escapeKeys", "EscapeKeys", XtRString, sizeof(String),
+   XtOffsetOf(AppData, escapeKeys), XtRImmediate, (XtPointer) 0},
+
+  {"escapeActive", "EscapeActive", XtRBool, sizeof(Bool),
+   XtOffsetOf(AppData, escapeActive), XtRImmediate, (XtPointer) False}
+
+  /* check commas */
 };
 
 
@@ -242,8 +937,29 @@
   {"-noraiseonbeep", "*raiseOnBeep",        XrmoptionNoArg,  "False"},
   {"-passwd",        "*passwordFile",       XrmoptionSepArg, 0},
   {"-user",          "*userLogin",          XrmoptionSepArg, 0},
+  {"-unixpw",        "*unixPW",             XrmoptionSepArg, 0},
+  {"-mslogon",       "*msLogon",            XrmoptionSepArg, 0},
+  {"-repeater",      "*repeaterUltra",      XrmoptionSepArg, 0},
+  {"-ultradsm",      "*ultraDSM",           XrmoptionNoArg,  "True"},
+  {"-acceptpopup",   "*acceptPopup",        XrmoptionNoArg,  "True"},
+  {"-acceptpopupsc", "*acceptPopup",        XrmoptionNoArg,  "True"},
+  {"-rfbversion",    "*rfbVersion",         XrmoptionSepArg, 0},
   {"-encodings",     "*encodings",          XrmoptionSepArg, 0},
-  {"-bgr233",        "*useBGR233",          XrmoptionNoArg,  "True"},
+  {"-bgr233",        "*useBGR233",          XrmoptionNoArg,  "256"},
+  {"-use64",         "*useBGR233",          XrmoptionNoArg,   "64"},
+  {"-bgr222",        "*useBGR233",          XrmoptionNoArg,   "64"},
+  {"-use8",          "*useBGR233",          XrmoptionNoArg,    "8"},
+  {"-bgr111",        "*useBGR233",          XrmoptionNoArg,    "8"},
+  {"-16bpp",         "*useBGR565",          XrmoptionNoArg,  "True"},
+  {"-bgr565",        "*useBGR565",          XrmoptionNoArg,  "True"},
+  {"-grey",          "*useGreyScale",       XrmoptionNoArg,  "True"},
+  {"-gray",          "*useGreyScale",       XrmoptionNoArg,  "True"},
+  {"-sbwidth",       "*sbwidth",            XrmoptionSepArg, 0},
+  {"-env",           "*envDummy",           XrmoptionSepArg, 0},
+  {"-ycrop",         "*yCrop",              XrmoptionSepArg, 0},
+  {"-rawlocal",      "*useRawLocal",        XrmoptionNoArg,  "True"},
+  {"-notty",         "*notty",              XrmoptionNoArg,  "True"},
+  {"-alpha",         "*useCursorAlpha",     XrmoptionNoArg,  "True"},
   {"-owncmap",       "*forceOwnCmap",       XrmoptionNoArg,  "True"},
   {"-truecolor",     "*forceTrueColour",    XrmoptionNoArg,  "True"},
   {"-truecolour",    "*forceTrueColour",    XrmoptionNoArg,  "True"},
@@ -253,8 +969,30 @@
   {"-nojpeg",        "*enableJPEG",         XrmoptionNoArg,  "False"},
   {"-nocursorshape", "*useRemoteCursor",    XrmoptionNoArg,  "False"},
   {"-x11cursor",     "*useX11Cursor",       XrmoptionNoArg,  "True"},
-  {"-autopass",      "*autoPass",           XrmoptionNoArg,  "True"}
-
+  {"-nobell",        "*useBell",            XrmoptionNoArg,  "False"},
+  {"-autopass",      "*autoPass",           XrmoptionNoArg,  "True"},
+  {"-graball",       "*grabAll",            XrmoptionNoArg,  "True"},
+  {"-grabkbd",       "*grabKeyboard",       XrmoptionNoArg,  "True"},
+  {"-nograbkbd",     "*grabKeyboard",       XrmoptionNoArg,  "False"},
+  {"-grabkeyboard",  "*grabKeyboard",       XrmoptionNoArg,  "True"},
+  {"-nograbkeyboard","*grabKeyboard",       XrmoptionNoArg,  "False"},
+  {"-nooverride",    "*overrideRedir",      XrmoptionNoArg,  "False"},
+  {"-bs",            "*useXserverBackingStore",    XrmoptionNoArg,  "True"},
+  {"-nobs",          "*useXserverBackingStore",    XrmoptionNoArg,  "False"},
+  {"-popupfix",      "*popupFix",           XrmoptionNoArg,  "True"},
+  {"-noshm",         "*useShm",             XrmoptionNoArg,  "False"},
+  {"-termchat",      "*termChat",           XrmoptionNoArg,  "True"},
+  {"-chatonly",      "*chatOnly",           XrmoptionNoArg,  "True"},
+  {"-scale",         "*scale",              XrmoptionSepArg, 0},
+  {"-appshare",      "*appShare",           XrmoptionNoArg,  "True"},
+  {"-escape",        "*escapeKeys",         XrmoptionSepArg, 0},
+  {"-sendclipboard", "*sendClipboard",      XrmoptionNoArg,  "True"},
+  {"-sendalways",    "*sendAlways",         XrmoptionNoArg,  "True"},
+  {"-recvtext",      "*recvText",           XrmoptionSepArg, 0},
+  {"-pipeline",      "*pipelineUpdates",    XrmoptionNoArg,  "True"},
+  {"-nopipeline",    "*pipelineUpdates",    XrmoptionNoArg,  "False"},
+  {"-noipv4",        "*noipv4",             XrmoptionNoArg,  "True"},
+  {"-noipv6",        "*noipv6",             XrmoptionNoArg,  "True"}
 };
 
 int numCmdLineOptions = XtNumber(cmdLineOptions);
@@ -267,16 +1005,100 @@
 static XtActionsRec actions[] = {
     {"SendRFBEvent", SendRFBEvent},
     {"ShowPopup", ShowPopup},
+    {"Noop", Noop},
     {"HidePopup", HidePopup},
+    {"HideScaleN", HideScaleN},
+    {"HideTurboVNC", HideTurboVNC},
+    {"HideQuality", HideQuality},
+    {"HideCompress", HideCompress},
     {"ToggleFullScreen", ToggleFullScreen},
+    {"JumpLeft", JumpLeft},
+    {"JumpRight", JumpRight},
+    {"JumpUp", JumpUp},
+    {"JumpDown", JumpDown},
     {"SetFullScreenState", SetFullScreenState},
     {"SelectionFromVNC", SelectionFromVNC},
     {"SelectionToVNC", SelectionToVNC},
     {"ServerDialogDone", ServerDialogDone},
+    {"UserDialogDone", UserDialogDone},
+    {"YCropDialogDone", YCropDialogDone},
+    {"ScbarDialogDone", ScbarDialogDone},
+    {"ScaleNDialogDone", ScaleNDialogDone},
+    {"ScaleDialogDone", ScaleDialogDone},
     {"PasswordDialogDone", PasswordDialogDone},
     {"Pause", Pause},
     {"RunCommand", RunCommand},
     {"Quit", Quit},
+    {"HideChat", HideChat},
+    {"Toggle8bpp", Toggle8bpp},
+    {"Toggle16bpp", Toggle16bpp},
+    {"ToggleFullColor", ToggleFullColor},
+    {"Toggle256Colors", Toggle256Colors},
+    {"Toggle64Colors", Toggle64Colors},
+    {"Toggle8Colors", Toggle8Colors},
+    {"ToggleGreyScale", ToggleGreyScale},
+    {"ToggleTightZRLE", ToggleTightZRLE},
+    {"ToggleTightHextile", ToggleTightHextile},
+    {"ToggleZRLEZYWRLE", ToggleZRLEZYWRLE},
+    {"ToggleViewOnly", ToggleViewOnly},
+    {"ToggleJPEG", ToggleJPEG},
+    {"ToggleCursorShape", ToggleCursorShape},
+    {"ToggleCursorAlpha", ToggleCursorAlpha},
+    {"ToggleX11Cursor", ToggleX11Cursor},
+    {"ToggleBell", ToggleBell},
+    {"ToggleRawLocal", ToggleRawLocal},
+    {"ToggleServerInput", ToggleServerInput},
+    {"TogglePipelineUpdates", TogglePipelineUpdates},
+    {"ToggleSendClipboard", ToggleSendClipboard},
+    {"ToggleSendAlways", ToggleSendAlways},
+    {"ToggleSingleWindow", ToggleSingleWindow},
+    {"ToggleTextChat", ToggleTextChat},
+    {"ToggleFileXfer", ToggleFileXfer},
+    {"ToggleXGrab", ToggleXGrab},
+    {"DoServerScale", DoServerScale},
+    {"SetScale", SetScale},
+    {"SetYCrop", SetYCrop},
+    {"SetScbar", SetScbar},
+    {"ShowScaleN", ShowScaleN},
+    {"ShowTurboVNC", ShowTurboVNC},
+    {"ShowQuality", ShowQuality},
+    {"ShowCompress", ShowCompress},
+    {"SetScaleN", SetScaleN},
+    {"SetTurboVNC", SetTurboVNC},
+    {"SetQuality", SetQuality},
+    {"SetCompress", SetCompress},
+    {"Set8bppState", Set8bppState},
+    {"Set16bppState", Set16bppState},
+    {"SetFullColorState", SetFullColorState},
+    {"Set256ColorsState", Set256ColorsState},
+    {"Set64ColorsState", Set64ColorsState},
+    {"Set8ColorsState", Set8ColorsState},
+    {"SetGreyScaleState", SetGreyScaleState},
+    {"SetZRLEState", SetZRLEState},
+    {"SetHextileState", SetHextileState},
+    {"SetZYWRLEState", SetZYWRLEState},
+    {"SetNOJPEGState", SetNOJPEGState},
+    {"SetScaleNState", SetScaleNState},
+    {"SetQualityState", SetQualityState},
+    {"SetCompressState", SetCompressState},
+    {"SetViewOnlyState", SetViewOnlyState},
+    {"SetCursorShapeState", SetCursorShapeState},
+    {"SetCursorAlphaState", SetCursorAlphaState},
+    {"SetX11CursorState", SetX11CursorState},
+    {"SetBellState", SetBellState},
+    {"SetRawLocalState", SetRawLocalState},
+    {"SetServerInputState", SetServerInputState},
+    {"SetPipelineUpdates", SetPipelineUpdates},
+    {"SetSendClipboard", SetSendClipboard},
+    {"SetSendAlways", SetSendAlways},
+    {"SetSingleWindowState", SetSingleWindowState},
+    {"SetTextChatState", SetTextChatState},
+    {"SetFileXferState", SetFileXferState},
+    {"SetXGrabState", SetXGrabState},
+    {"SetEscapeKeysState", SetEscapeKeysState},
+    {"ToggleEscapeActive", ToggleEscapeActive},
+    {"EscapeDialogDone", EscapeDialogDone},
+    {"SetEscapeKeys", SetEscapeKeys}
 };
 
 
@@ -302,11 +1124,14 @@
 void
 usage(void)
 {
-  fprintf(stderr,
-	  "TightVNC viewer version 1.3dev7\n"
+  fprintf(stdout,
+	  "SSVNC Viewer (based on TightVNC viewer version 1.3.9)\n"
 	  "\n"
 	  "Usage: %s [<OPTIONS>] [<HOST>][:<DISPLAY#>]\n"
 	  "       %s [<OPTIONS>] [<HOST>][::<PORT#>]\n"
+	  "       %s [<OPTIONS>] exec=[CMD ARGS...]\n"
+	  "       %s [<OPTIONS>] fd=n\n"
+	  "       %s [<OPTIONS>] /path/to/unix/socket\n"
 	  "       %s [<OPTIONS>] -listen [<DISPLAY#>]\n"
 	  "       %s -help\n"
 	  "\n"
@@ -319,7 +1144,7 @@
 	  "        -noraiseonbeep\n"
 	  "        -passwd <PASSWD-FILENAME> (standard VNC authentication)\n"
 	  "        -user <USERNAME> (Unix login authentication)\n"
-	  "        -encodings <ENCODING-LIST> (e.g. \"tight copyrect\")\n"
+	  "        -encodings <ENCODING-LIST> (e.g. \"tight,copyrect\")\n"
 	  "        -bgr233\n"
 	  "        -owncmap\n"
 	  "        -truecolour\n"
@@ -332,10 +1157,390 @@
 	  "        -autopass\n"
 	  "\n"
 	  "Option names may be abbreviated, e.g. -bgr instead of -bgr233.\n"
-	  "See the manual page for more information."
-	  "\n", programName, programName, programName, programName);
+	  "See the manual page for more information.\n"
+	  "\n"
+	  "\n"
+	  "Enhanced TightVNC viewer (SSVNC) options:\n"
+	  "\n"
+	  "   URL http://www.karlrunge.com/x11vnc/ssvnc.html\n"
+	  "\n"
+	  "   Note: ZRLE and ZYWRLE encodings are now supported.\n"
+	  "\n"
+	  "   Note: F9 is shortcut to Toggle FullScreen mode.\n"
+	  "\n"
+	  "   Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1\n"
+	  "         to allow more than one incoming VNC server at a time.\n"
+	  "         This is the same as -multilisten described below.  Set\n"
+	  "         SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than \"n\"\n"
+	  "         simultaneous reverse connections.\n"
+	  "\n"
+	  "   Note: If the host:port is specified as \"exec=command args...\"\n"
+	  "         then instead of making a TCP/IP socket connection to the\n"
+	  "         remote VNC server, \"command args...\" is executed and the\n"
+	  "         viewer is attached to its stdio.  This enables tunnelling\n"
+	  "         established via an external command, e.g. an stunnel(8)\n"
+	  "         that does not involve a listening socket.  This mode does\n"
+	  "         not work for -listen reverse connections.\n"
+	  "\n"
+	  "         If the host:port is specified as \"fd=n\" then it is assumed\n"
+	  "         n is an already opened file descriptor to the socket. (i.e\n"
+	  "         the parent did fork+exec)\n"
+	  "\n"
+	  "         If the host:port contains a '/' it is interpreted as a\n"
+	  "         unix-domain socket (AF_LOCAL insead of AF_INET)\n"
+	  "\n"
+	  "        -multilisten  As in -listen (reverse connection listening) except\n"
+	  "                    allow more than one incoming VNC server to be connected\n"
+	  "                    at a time.  The default for -listen of only one at a\n"
+	  "                    time tries to play it safe by not allowing anyone on\n"
+	  "                    the network to put (many) desktops on your screen over\n"
+	  "                    a long window of time. Use -multilisten for no limit.\n"
+	  "\n"
+	  "        -acceptpopup  In -listen (reverse connection listening) mode when\n"
+	  "                    a reverse VNC connection comes in show a popup asking\n"
+	  "                    whether to Accept or Reject the connection.  The IP\n"
+	  "                    address of the connecting host is shown.  Same as\n"
+	  "                    setting the env. var. SSVNC_ACCEPT_POPUP=1.\n"
+	  "\n"
+	  "        -acceptpopupsc  As in -acceptpopup except assume UltraVNC Single\n"
+	  "                    Click (SC) server.  Retrieve User and ComputerName\n"
+	  "                    info from UltraVNC Server and display in the Popup.\n"
+	  "\n"
+	  "        -use64      In -bgr233 mode, use 64 colors instead of 256.\n"
+	  "        -bgr222     Same as -use64.\n"
+	  "\n"
+	  "        -use8       In -bgr233 mode, use 8 colors instead of 256.\n"
+	  "        -bgr111     Same as -use8.\n"
+	  "\n"
+	  "        -16bpp      If the vnc viewer X display is depth 24 at 32bpp\n"
+	  "                    request a 16bpp format from the VNC server to cut\n"
+	  "                    network traffic by up to 2X, then tranlate the\n"
+	  "                    pixels to 32bpp locally.\n"
+	  "        -bgr565     Same as -16bpp.\n"
+	  "\n"
+	  "        -grey       Use a grey scale for the 16- and 8-bpp modes.\n"
+	  "\n"
+	  "        -alpha      Use alphablending transparency for local cursors\n"
+	  "                    requires: x11vnc server, both client and server\n"
+          "                    must be 32bpp and same endianness.\n"
+	  "\n"
+	  "        -scale str  Scale the desktop locally.  The string \"str\" can\n"
+	  "                    a floating point ratio, e.g. \"0.9\", or a fraction,\n"
+	  "                    e.g. \"3/4\", or WxH, e.g. 1280x1024.  Use \"fit\"\n"
+	  "                    to fit in the current screen size.  Use \"auto\" to\n"
+	  "                    fit in the window size.  \"str\" can also be set by\n"
+	  "                    the env. var. SSVNC_SCALE.\n"
+	  "\n"
+	  "                    If you observe mouse trail painting errors, enable\n"
+	  "                    X11 Cursor mode (either via Popup or -x11cursor.)\n"
+	  "\n"
+	  "                    Note that scaling is done in software and so can be\n"
+	  "                    slow and requires more memory.  Some speedup Tips:\n"
+	  "\n"
+	  "                        ZRLE is faster than Tight in this mode.  When\n"
+	  "                        scaling is first detected, the encoding will\n"
+	  "                        be automatically switched to ZRLE.  Use the\n"
+	  "                        Popup menu if you want to go back to Tight.\n"
+	  "                        Set SSVNC_PRESERVE_ENCODING=1 to disable this.\n"
+	  "\n"
+	  "                        Use a solid background on the remote side.\n"
+	  "                        (e.g. manually or via x11vnc -solid ...)\n"
+	  "\n"
+	  "                        If the remote server is x11vnc, try client\n"
+	  "                        side caching: x11vnc -ncache 10 ...\n"
+	  "\n"
+	  "        -ycrop n    Only show the top n rows of the framebuffer.  For\n"
+	  "                    use with x11vnc -ncache client caching option\n"
+	  "                    to help \"hide\" the pixel cache region.\n"
+	  "                    Use a negative value (e.g. -1) for autodetection.\n"
+	  "                    Autodetection will always take place if the remote\n"
+	  "                    fb height is more than 2 times the width.\n"
+	  "\n"
+	  "        -sbwidth n  Scrollbar width for x11vnc -ncache mode (-ycrop),\n"
+          "                    default is very narrow: 2 pixels, it is narrow to\n"
+          "                    avoid distraction in -ycrop mode.\n"
+	  "\n"
+	  "        -nobell     Disable bell.\n"
+	  "\n"
+	  "        -rawlocal   Prefer raw encoding for localhost, default is\n"
+	  "                    no, i.e. assumes you have a SSH tunnel instead.\n"
+	  "\n"
+	  "        -notty      Try to avoid using the terminal for interactive\n"
+	  "                    responses: use windows for messages and prompting\n"
+	  "                    instead.  Messages will also be printed to terminal.\n"
+	  "\n"
+	  "        -sendclipboard  Send the X CLIPBOARD selection (i.e. Ctrl+C,\n"
+	  "                        Ctrl+V) instead of the X PRIMARY selection (mouse\n"
+	  "                        select and middle button paste.)\n"
+	  "\n"
+	  "        -sendalways     Whenever the mouse enters the VNC viewer main\n"
+	  "                        window, send the selection to the VNC server even if\n"
+	  "                        it has not changed.  This is like the Xt resource\n"
+	  "                        translation SelectionToVNC(always)\n"
+	  "\n"
+	  "        -recvtext str   When cut text is received from the VNC server,\n"
+	  "                        ssvncviewer will set both the X PRIMARY and the\n"
+	  "                        X CLIPBOARD local selections.  To control which\n"
+	  "                        is set, specify 'str' as 'primary', 'clipboard',\n"
+	  "                        or 'both' (the default.)\n"
+	  "\n"
+	  "        -graball    Grab the entire X server when in fullscreen mode,\n"
+	  "                    needed by some old window managers like fvwm2.\n"
+	  "\n"
+	  "        -popupfix   Warp the popup back to the pointer position,\n"
+	  "                    needed by some old window managers like fvwm2.\n"
+	  "        -sendclipboard  Send the X CLIPBOARD selection (i.e. Ctrl+C,\n"
+	  "                        Ctrl+V) instead of the X PRIMARY selection (mouse\n"
+	  "                        select and middle button paste.)\n"
+	  "\n"
+	  "        -sendalways     Whenever the mouse enters the VNC viewer main\n"
+	  "                        window, send the selection to the VNC server even if\n"
+	  "                        it has not changed.  This is like the Xt resource\n"
+	  "                        translation SelectionToVNC(always)\n"
+	  "\n"
+	  "        -recvtext str   When cut text is received from the VNC server,\n"
+	  "                        ssvncviewer will set both the X PRIMARY and the\n"
+	  "                        X CLIPBOARD local selections.  To control which\n"
+	  "                        is set, specify 'str' as 'primary', 'clipboard',\n"
+	  "                        or 'both' (the default.)\n"
+	  "\n"
+	  "        -graball    Grab the entire X server when in fullscreen mode,\n"
+	  "                    needed by some old window managers like fvwm2.\n"
+	  "\n"
+	  "        -popupfix   Warp the popup back to the pointer position,\n"
+	  "                    needed by some old window managers like fvwm2.\n"
+	  "\n"
+	  "        -grabkbd    Grab the X keyboard when in fullscreen mode,\n"
+	  "                    needed by some window managers. Same as -grabkeyboard.\n"
+	  "                    -grabkbd is the default, use -nograbkbd to disable.\n"
+	  "\n"
+	  "        -bs, -nobs  Whether or not to use X server Backingstore for the\n"
+	  "                    main viewer window.  The default is to not, mainly\n"
+	  "                    because most Linux, etc, systems X servers disable\n"
+	  "                    *all* Backingstore by default.  To re-enable it put\n"
+	  "\n"
+	  "                        Option \"Backingstore\"\n"
+	  "\n"
+	  "                    in the Device section of /etc/X11/xorg.conf.\n"
+	  "                    In -bs mode with no X server backingstore, whenever an\n"
+	  "                    area of the screen is re-exposed it must go out to the\n"
+	  "                    VNC server to retrieve the pixels. This is too slow.\n"
+	  "\n"
+	  "                    In -nobs mode, memory is allocated by the viewer to\n"
+	  "                    provide its own backing of the main viewer window. This\n"
+	  "                    actually makes some activities faster (changes in large\n"
+	  "                    regions) but can appear to \"flash\" too much.\n"
+	  "\n"
+	  "        -noshm      Disable use of MIT shared memory extension (not recommended)\n"
+	  "\n"
+	  "        -termchat   Do the UltraVNC chat in the terminal vncviewer is in\n"
+	  "                    instead of in an independent window.\n"
+	  "\n"
+	  "        -unixpw str Useful for logging into x11vnc in -unixpw mode. \"str\" is a\n"
+	  "                    string that allows many ways to enter the Unix Username\n"
+	  "                    and Unix Password.  These characters: username, newline,\n"
+	  "                    password, newline are sent to the VNC server after any VNC\n"
+	  "                    authentication has taken place.  Under x11vnc they are\n"
+	  "                    used for the -unixpw login.  Other VNC servers could do\n"
+	  "                    something similar.\n"
+	  "\n"
+	  "                    You can also indicate \"str\" via the environment\n"
+	  "                    variable SSVNC_UNIXPW.\n"
+	  "\n"
+	  "                    Note that the Escape key is actually sent first to tell\n"
+	  "                    x11vnc to not echo the Unix Username back to the VNC\n"
+	  "                    viewer. Set SSVNC_UNIXPW_NOESC=1 to override this.\n"
+	  "\n"
+	  "                    If str is \".\", then you are prompted at the command line\n"
+	  "                    for the username and password in the normal way.  If str is\n"
+	  "                    \"-\" the stdin is read via getpass(3) for username@password.\n"
+	  "                    Otherwise if str is a file, it is opened and the first line\n"
+	  "                    read is taken as the Unix username and the 2nd as the\n"
+	  "                    password. If str prefixed by \"rm:\" the file is removed\n"
+	  "                    after reading. Otherwise, if str has a \"@\" character,\n"
+	  "                    it is taken as username@password. Otherwise, the program\n"
+	  "                    exits with an error. Got all that?\n"
+	  "\n"
+	  "     -repeater str  This is for use with UltraVNC repeater proxy described\n"  
+	  "                    here: http://www.uvnc.com/addons/repeater.html.  The \"str\"\n"  
+	  "                    is the ID string to be sent to the repeater.  E.g. ID:1234\n"  
+	  "                    It can also be the hostname and port or display of the VNC\n"  
+	  "                    server, e.g. 12.34.56.78:0 or snoopy.com:1.  Note that when\n"  
+	  "                    using -repeater, the host:dpy on the cmdline is the repeater\n"  
+	  "                    server, NOT the VNC server.  The repeater will connect you.\n"  
+	  "\n"
+	  "                    Example: vncviewer ... -repeater ID:3333 repeat.host:5900\n"  
+	  "                    Example: vncviewer ... -repeater vhost:0 repeat.host:5900\n"  
+	  "\n"
+	  "                    Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a\n"
+	  "                    Single Click III (SSL) repeater (repeater_SSL.exe) and you\n"
+	  "                    are passing the SSL part of the connection through stunnel,\n"
+	  "                    socat, etc. This way the magic UltraVNC string 'testB'\n"
+          "                    needed to work with the repeater is sent to it.\n"
+	  "\n"
+	  "     -rfbversion str Set the advertised RFB version.  E.g.: -rfbversion 3.6\n"
+	  "                    For some servers, e.g. UltraVNC this needs to be done.\n"
+	  "\n"
+	  "     -ultradsm      UltraVNC has symmetric private key encryption DSM plugins:\n"  
+	  "                    http://www.uvnc.com/features/encryption.html. It is assumed\n"  
+	  "                    you are using a unix program (e.g. our ultravnc_dsm_helper)\n"  
+	  "                    to encrypt and decrypt the UltraVNC DSM stream. IN ADDITION\n"  
+	  "                    TO THAT supply -ultradsm to tell THIS viewer to modify the\n"  
+	  "                    RFB data sent so as to work with the UltraVNC Server. For\n"  
+	  "                    some reason, each RFB msg type must be sent twice under DSM.\n"  
+	  "\n"
+	  "     -mslogon user  Use Windows MS Logon to an UltraVNC server.  Supply the\n"  
+	  "                    username or \"1\" to be prompted.  The default is to\n"
+	  "                    autodetect the UltraVNC MS Logon server and prompt for\n"
+	  "                    the username and password.\n"
+	  "\n"
+	  "                    IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman\n"
+	  "                    exchange is very weak and can be brute forced to recover\n"
+	  "                    your username and password in a few seconds of CPU time.\n"
+	  "                    To be safe, be sure to use an additional encrypted tunnel\n"
+	  "                    (e.g. SSL or SSH) for the entire VNC session.\n"
+	  "\n"
+	  "     -chatonly      Try to be a client that only does UltraVNC text chat. This\n"  
+	  "                    mode is used by x11vnc to present a chat window on the\n"
+	  "                    physical X11 console (i.e. chat with the person at the\n"
+	  "                    display).\n"
+	  "\n"
+	  "     -env VAR=VALUE To save writing a shell script to set environment variables,\n"
+	  "                    specify as many as you need on the command line.  For\n"
+	  "                    example, -env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi\n"
+	  "\n"
+	  "     -noipv6        Disable all IPv6 sockets.  Same as VNCVIEWER_NO_IPV6=1.\n"
+	  "\n"
+	  "     -noipv4        Disable all IPv4 sockets.  Same as VNCVIEWER_NO_IPV4=1.\n"
+	  "\n"
+	  "     -printres      Print out the Ssvnc X resources (appdefaults) and then exit\n"  
+	  "                    You can save them to a file and customize them (e.g. the\n"  
+	  "                    keybindings and Popup menu)  Then point to the file via\n"  
+	  "                    XENVIRONMENT or XAPPLRESDIR.\n"  
+	  "\n"
+	  "     -pipeline      Like TurboVNC, request the next framebuffer update as soon\n"
+	  "                    as possible instead of waiting until the end of the current\n"
+	  "                    framebuffer update coming in.  Helps 'pipeline' the updates.\n"
+	  "                    This is currently the default, use -nopipeline to disable.\n"
+	  "\n"
+	  "     -appshare      Enable features for use with x11vnc's -appshare mode where\n"
+	  "                    instead of sharing the full desktop only the application's\n"
+	  "                    windows are shared.  Viewer multilisten mode is used to\n"
+	  "                    create the multiple windows: -multilisten is implied.\n"
+	  "                    See 'x11vnc -appshare -help' more information on the mode.\n"
+	  "\n"
+	  "                    Features enabled in the viewer under -appshare are:\n"
+	  "                    Minimum extra text in the title, auto -ycrop is disabled,\n"
+	  "                    x11vnc -remote_prefix X11VNC_APPSHARE_CMD: message channel,\n"
+	  "                    x11vnc initial window position hints.  See also Escape Keys\n"
+	  "                    below for additional key and mouse bindings.\n"
+	  "\n"
+	  "     -escape str    This sets the 'Escape Keys' modifier sequence and enables\n"
+	  "                    escape keys mode.  When the modifier keys escape sequence\n"
+	  "                    is held down, the next keystroke is interpreted locally\n"
+	  "                    to perform a special action instead of being sent to the\n"
+	  "                    remote VNC server.\n"
+	  "\n"
+	  "                    Use '-escape default' for the default modifier sequence.\n"
+	  "                    (Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L)\n"
+	  "\n"
+	  "    Here are the 'Escape Keys: Help+Set' instructions from the Popup Menu:\n"
+	  "\n"
+          "    Escape Keys:  Enter a comma separated list of modifier keys to be the\n"
+          "    'escape sequence'.  When these keys are held down, the next keystroke is\n"
+          "    interpreted locally to invoke a special action instead of being sent to\n"
+          "    the remote VNC server.  In other words, a set of 'Hot Keys'.\n"
+          "    \n"
+          "    To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\n"
+          "    \n"
+          "    Here is the list of hot-key mappings to special actions:\n"
+          "    \n"
+          "       r: refresh desktop  b: toggle bell   c: toggle full-color\n"
+          "       f: file transfer    x: x11cursor     z: toggle Tight/ZRLE\n"
+          "       l: full screen      g: graball       e: escape keys dialog\n"
+          "       s: scale dialog     +: scale up (=)  -: scale down (_)\n"
+          "       t: text chat                         a: alphablend cursor\n"
+          "       V: toggle viewonly  Q: quit viewer   1 2 3 4 5 6: UltraVNC scale 1/n\n"
+          "    \n"
+          "       Arrow keys:         pan the viewport about 10%% for each keypress.\n"
+          "       PageUp / PageDown:  pan the viewport by a screenful vertically.\n"
+          "       Home   / End:       pan the viewport by a screenful horizontally.\n"
+          "       KeyPad Arrow keys:  pan the viewport by 1 pixel for each keypress.\n"
+          "       Dragging the Mouse with Button1 pressed also pans the viewport.\n"
+          "       Clicking Mouse Button3 brings up the Popup Menu.\n"
+          "    \n"
+          "    The above mappings are *always* active in ViewOnly mode, unless you set the\n"
+          "    Escape Keys value to 'never'.\n"
+          "    \n"
+          "    If the Escape Keys value below is set to 'default' then a default list of\n"
+          "    of modifier keys is used.  For Unix it is: Alt_L,Super_L and for MacOSX it\n"
+          "    is Control_L,Meta_L.  Note: the Super_L key usually has a Windows(TM) Flag\n"
+          "    on it.  Also note the _L and _R mean the key is on the LEFT or RIGHT side\n"
+          "    of the keyboard.\n"
+          "    \n"
+          "    On Unix   the default is Alt and Windows keys on Left side of keyboard.\n"
+          "    On MacOSX the default is Control and Command keys on Left side of keyboard.\n"
+          "    \n"
+          "    Example: Press and hold the Alt and Windows keys on the LEFT side of the\n"
+          "    keyboard and then press 'c' to toggle the full-color state.  Or press 't'\n"
+          "    to toggle the ultravnc Text Chat window, etc.\n"
+          "    \n"
+          "    To use something besides the default, supply a comma separated list (or a\n"
+          "    single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\n"
+          "    Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\n"
+	  "\n"
+	  "\n"
+	  "   New Popup actions:\n"
+	  "\n"
+	  "        ViewOnly:                ~ -viewonly\n"
+	  "        Disable Bell:            ~ -nobell\n"
+	  "        Cursor Shape:            ~ -nocursorshape\n"
+	  "        X11 Cursor:              ~ -x11cursor\n"
+	  "        Cursor Alphablend:       ~ -alpha\n"
+	  "        Toggle Tight/Hextile:    ~ -encodings hextile...\n"
+	  "        Toggle Tight/ZRLE:       ~ -encodings zrle...\n"
+	  "        Toggle ZRLE/ZYWRLE:      ~ -encodings zywrle...\n"
+	  "        Quality Level            ~ -quality (both Tight and ZYWRLE)\n"
+	  "        Compress Level           ~ -compresslevel\n"
+	  "        Disable JPEG:            ~ -nojpeg  (Tight)\n"
+	  "        Pipeline Updates         ~ -pipeline\n"
+	  "\n"
+	  "        Full Color                 as many colors as local screen allows.\n"
+	  "        Grey scale (16 & 8-bpp)  ~ -grey, for low colors 16/8bpp modes only.\n"
+	  "        16 bit color (BGR565)    ~ -16bpp / -bgr565\n"
+	  "        8  bit color (BGR233)    ~ -bgr233\n"
+	  "        256 colors               ~ -bgr233 default # of colors.\n"
+	  "         64 colors               ~ -bgr222 / -use64\n"
+	  "          8 colors               ~ -bgr111 / -use8\n"
+	  "        Scale Viewer             ~ -scale\n"
+	  "        Escape Keys: Toggle      ~ -escape\n"
+	  "        Escape Keys: Help+Set    ~ -escape\n"
+	  "        Set Y Crop (y-max)       ~ -ycrop\n"
+	  "        Set Scrollbar Width      ~ -sbwidth\n"
+	  "        XGrabServer              ~ -graball\n"
+	  "\n"
+	  "        UltraVNC Extensions:\n"
+	  "\n"
+	  "          Set 1/n Server Scale     Ultravnc ext. Scale desktop by 1/n.\n"
+	  "          Text Chat                Ultravnc ext. Do Text Chat.\n"
+	  "          File Transfer            Ultravnc ext. File xfer via Java helper.\n"
+	  "          Single Window            Ultravnc ext. Grab and view a single window.\n"
+	  "                                   (select then click on the window you want).\n"
+	  "          Disable Remote Input     Ultravnc ext. Try to prevent input and\n"
+	  "                                   viewing of monitor at physical display.\n"
+	  "\n"
+	  "        Note: the Ultravnc extensions only apply to servers that support\n"
+	  "              them.  x11vnc/libvncserver supports some of them.\n"
+	  "\n"
+	  "        Send Clipboard not Primary  ~ -sendclipboard\n"
+	  "        Send Selection Every time   ~ -sendalways\n"
+	  "\n"
+	  "\n", programName, programName, programName, programName, programName, programName, programName);
   exit(1);
 }
+#if 0
+	  "        -nooverride Do not apply OverrideRedirect in fullscreen mode.\n"
+#endif
 
 
 /*
@@ -343,77 +1548,247 @@
  * not already processed by XtVaAppInitialize().  It sets vncServerHost and
  * vncServerPort and all the fields in appData.
  */
+extern int saw_appshare;
 
 void
 GetArgsAndResources(int argc, char **argv)
 {
-  int i;
-  char *vncServerName, *colonPos;
-  int len, portOffset;
+	char *vncServerName = NULL, *colonPos, *bracketPos;
+	int len, portOffset;
+	int disp;
 
   /* Turn app resource specs into our appData structure for the rest of the
      program to use */
 
-  XtGetApplicationResources(toplevel, &appData, appDataResourceList,
-			    XtNumber(appDataResourceList), 0, 0);
+	XtGetApplicationResources(toplevel, &appData, appDataResourceList,
+	    XtNumber(appDataResourceList), 0, 0);
+
+	/*
+	 * we allow setting of some by env, to avoid clash with other
+	 * viewer's cmdlines (e.g. change viewer in SSVNC).
+	 */
+	if (getenv("VNCVIEWER_ALPHABLEND")) {
+		appData.useCursorAlpha = True;
+	}
+	if (getenv("VNCVIEWER_POPUP_FIX")) {
+		if (getenv("NOPOPUPFIX")) {
+			;
+		} else if (!strcmp(getenv("VNCVIEWER_POPUP_FIX"), "0")) {
+			;
+		} else {
+			appData.popupFix = True;
+		}
+	}
+	if (getenv("VNCVIEWER_GRAB_SERVER")) {
+		appData.grabAll = True;
+	}
+	if (getenv("VNCVIEWER_YCROP")) {
+		int n = atoi(getenv("VNCVIEWER_YCROP"));
+		if (n != 0) {
+			appData.yCrop = n;
+		}
+	}
+	if (getenv("VNCVIEWER_RFBVERSION") && strcmp(getenv("VNCVIEWER_RFBVERSION"), "")) {
+		appData.rfbVersion = strdup(getenv("VNCVIEWER_RFBVERSION"));
+	}
+	if (getenv("VNCVIEWER_ENCODINGS") && strcmp(getenv("VNCVIEWER_ENCODINGS"), "")) {
+		appData.encodingsString = strdup(getenv("VNCVIEWER_ENCODINGS"));
+	}
+	if (getenv("VNCVIEWER_NOBELL")) {
+		appData.useBell = False;
+	}
+	if (getenv("VNCVIEWER_X11CURSOR")) {
+		appData.useX11Cursor = True;
+	}
+	if (getenv("VNCVIEWER_RAWLOCAL")) {
+		appData.useRawLocal = True;
+	}
+	if (getenv("VNCVIEWER_NOTTY") || getenv("SSVNC_VNCVIEWER_NOTTY")) {
+		appData.notty = True;
+	}
+	if (getenv("VNCVIEWER_SBWIDTH")) {
+		int n = atoi(getenv("VNCVIEWER_SBWIDTH"));
+		if (n != 0) {
+			appData.sbWidth = n;
+		}
+	}
+	if (getenv("VNCVIEWER_ULTRADSM")) {
+		appData.ultraDSM = True;
+	}
+	if (getenv("SSVNC_ULTRA_DSM") && strcmp(getenv("SSVNC_ULTRA_DSM"), "")) {
+		appData.ultraDSM = True;
+	}
+	if (getenv("SSVNC_NO_ULTRA_DSM")) {
+		appData.ultraDSM = False;
+	}
+	if (getenv("SSVNC_SCALE") && strcmp(getenv("SSVNC_SCALE"), "")) {
+		if (appData.scale == NULL) {
+			appData.scale = strdup(getenv("SSVNC_SCALE"));
+		}
+	}
+	if (getenv("VNCVIEWER_ESCAPE") && strcmp(getenv("VNCVIEWER_ESCAPE"), "")) {
+		if (appData.escapeKeys == NULL) {
+			appData.escapeKeys = strdup(getenv("VNCVIEWER_ESCAPE"));
+		}
+	}
+	if (saw_appshare) {
+		appData.appShare = True;
+	}
+	if (appData.appShare && appData.escapeKeys == NULL) {
+		appData.escapeKeys = strdup("default");
+	}
+	if (appData.escapeKeys != NULL) {
+		appData.escapeActive = True;
+	}
+	if (getenv("VNCVIEWER_SEND_CLIPBOARD")) {
+		appData.sendClipboard = True;
+	}
+	if (getenv("VNCVIEWER_SEND_ALWAYS")) {
+		appData.sendAlways = True;
+	}
+	if (getenv("VNCVIEWER_RECV_TEXT")) {
+		char *s = getenv("VNCVIEWER_RECV_TEXT");
+		if (!strcasecmp(s, "clipboard")) {
+			appData.recvText = strdup("clipboard");
+		} else if (!strcasecmp(s, "primary")) {
+			appData.recvText = strdup("primary");
+		} else if (!strcasecmp(s, "both")) {
+			appData.recvText = strdup("both");
+		}
+	}
+	if (getenv("VNCVIEWER_PIPELINE_UPDATES")) {
+		appData.pipelineUpdates = True;
+	} else if (getenv("VNCVIEWER_NO_PIPELINE_UPDATES")) {
+		appData.pipelineUpdates = False;
+	}
+
+	if (getenv("VNCVIEWER_NO_IPV4")) {
+		appData.noipv4 = True;
+	}
+	if (getenv("VNCVIEWER_NO_IPV6")) {
+		appData.noipv6 = True;
+	}
+
+	if (appData.useBGR233 && appData.useBGR565) {
+		appData.useBGR233 = 0;
+	}
+
+	if (getenv("SSVNC_ULTRA_FTP_JAR") == NULL && programName != NULL) {
+		int len = strlen(programName) + 200;
+		char *q, *jar = (char *) malloc(len);
+		
+		sprintf(jar, "%s", programName);
+		q = strrchr(jar, '/');
+		if (q) {
+			struct stat sb;
+			*(q+1) = '\0';
+			strcat(jar, "../lib/ssvnc/util/ultraftp.jar");
+			if (stat(jar, &sb) == 0) {
+				char *put = (char *) malloc(len);
+				sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar);
+				fprintf(stderr, "Setting: %s\n\n", put);
+				putenv(put);
+			} else {
+				sprintf(jar, "%s", programName);
+				q = strrchr(jar, '/');
+				*(q+1) = '\0';
+				strcat(jar, "util/ultraftp.jar");
+				if (stat(jar, &sb) == 0) {
+					char *put = (char *) malloc(len);
+					sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar);
+					fprintf(stderr, "Setting: %s\n\n", put);
+					putenv(put);
+				}
+			}
+		}
+		free(jar);
+	}
+
 
   /* Add our actions to the actions table so they can be used in widget
      resource specs */
 
-  XtAppAddActions(appContext, actions, XtNumber(actions));
+	XtAppAddActions(appContext, actions, XtNumber(actions));
 
   /* Check any remaining command-line arguments.  If -listen was specified
      there should be none.  Otherwise the only argument should be the VNC
      server name.  If not given then pop up a dialog box and wait for the
      server name to be entered. */
 
-  if (listenSpecified) {
-    if (argc != 1) {
-      fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n",
-	      programName, argv[1]);
-      usage();
-    }
-    return;
-  }
-
-  if (argc == 1) {
-    vncServerName = DoServerDialog();
-    appData.passwordDialog = True;
-  } else if (argc != 2) {
-    usage();
-  } else {
-    vncServerName = argv[1];
-
-    if (!isatty(0))
-      appData.passwordDialog = True;
-    if (vncServerName[0] == '-')
-      usage();
-  }
-
-  if (strlen(vncServerName) > 255) {
-    fprintf(stderr,"VNC server name too long\n");
-    exit(1);
-  }
-
-  colonPos = strchr(vncServerName, ':');
-  if (colonPos == NULL) {
-    /* No colon -- use default port number */
-    strcpy(vncServerHost, vncServerName);
-    vncServerPort = SERVER_PORT_OFFSET;
-  } else {
-    memcpy(vncServerHost, vncServerName, colonPos - vncServerName);
-    vncServerHost[colonPos - vncServerName] = '\0';
-    len = strlen(colonPos + 1);
-    portOffset = SERVER_PORT_OFFSET;
-    if (colonPos[1] == ':') {
-      /* Two colons -- interpret as a port number */
-      colonPos++;
-      len--;
-      portOffset = 0;
-    }
-    if (!len || strspn(colonPos + 1, "0123456789") != len) {
-      usage();
-    }
-    vncServerPort = atoi(colonPos + 1) + portOffset;
-  }
+	if (listenSpecified) {
+		if (argc != 1) {
+			fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n",
+			programName, argv[1]);
+			usage();
+		}
+		return;
+	}
+
+	if (argc == 1) {
+		vncServerName = DoServerDialog();
+		if (!use_tty()) {
+			appData.passwordDialog = True;
+		}
+	} else if (argc != 2) {
+		usage();
+	} else {
+		vncServerName = argv[1];
+
+		if (!use_tty()) {
+			appData.passwordDialog = True;
+		}
+		if (vncServerName[0] == '-') {
+			usage();
+		}
+	}
+
+	if (strlen(vncServerName) > 255) {
+		fprintf(stderr,"VNC server name too long\n");
+		exit(1);
+	}
+
+	colonPos = strrchr(vncServerName, ':');
+	bracketPos = strrchr(vncServerName, ']');
+	if (strstr(vncServerName, "exec=") == vncServerName) {
+		/* special exec-external-command case */
+		strcpy(vncServerHost, vncServerName);
+		vncServerPort = SERVER_PORT_OFFSET;
+	} else if (strstr(vncServerName, "fd=") == vncServerName) {
+		/* special exec-external-command case */
+		strcpy(vncServerHost, vncServerName);
+		vncServerPort = SERVER_PORT_OFFSET;
+	} else if (colonPos == NULL) {
+		/* No colon -- use default port number */
+		strcpy(vncServerHost, vncServerName);
+		vncServerPort = SERVER_PORT_OFFSET;
+	} else if (bracketPos != NULL && colonPos < bracketPos) {
+		strcpy(vncServerHost, vncServerName);
+		vncServerPort = SERVER_PORT_OFFSET;
+	} else {
+		if (colonPos > vncServerName && *(colonPos - 1) == ':') {
+			colonPos--;
+		}
+		memcpy(vncServerHost, vncServerName, colonPos - vncServerName);
+		vncServerHost[colonPos - vncServerName] = '\0';
+		len = strlen(colonPos + 1);
+		portOffset = SERVER_PORT_OFFSET;
+		if (colonPos[1] == ':') {
+			/* Two colons -- interpret as a port number */
+			colonPos++;
+			len--;
+			portOffset = 0;
+		}
+		if (!len || strspn(colonPos + 1, "0123456789") != (size_t) len) {
+			usage();
+		}
+#if 0
+		vncServerPort = atoi(colonPos + 1) + portOffset;
+#else
+		disp = atoi(colonPos + 1);
+		if (portOffset != 0 && disp >= 100) {
+			portOffset = 0;
+		}
+		vncServerPort = disp + portOffset;
+#endif
+	}
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/colour.c vnc_unixsrc/vncviewer/colour.c
--- vnc_unixsrc.orig/vncviewer/colour.c	2002-04-30 09:07:31.000000000 -0400
+++ vnc_unixsrc/vncviewer/colour.c	2010-02-25 22:02:19.000000000 -0500
@@ -31,9 +31,12 @@
 #define BGR233_SIZE 256
 unsigned long BGR233ToPixel[BGR233_SIZE];
 
+#define BGR565_SIZE 65536
+unsigned long BGR565ToPixel[BGR565_SIZE];
+
 Colormap cmap;
 Visual *vis;
-unsigned int visdepth, visbpp;
+unsigned int visdepth, visbpp, isLSB;
 Bool allocColorFailed = False;
 
 static int nBGR233ColoursAllocated;
@@ -45,6 +48,8 @@
 static void AllocateExactBGR233Colours();
 static Bool AllocateBGR233Colour(int r, int g, int b);
 
+static void SetupBGR565Map(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask);
+
 
 /*
  * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
@@ -97,6 +102,44 @@
   visbpp = GetBPPForDepth(visdepth);
   cmap = DefaultColormap(dpy,DefaultScreen(dpy));
 
+  if (ImageByteOrder(dpy) == LSBFirst) {
+  	isLSB = 1;
+  } else {
+  	isLSB = 0;
+  }
+  if (visbpp == 24) {
+  	if (!appData.useBGR233) {
+  		fprintf(stderr, "Warning: for 24bpp enabling -bgr565 -- Don't use FullColor!\n"); 
+  		appData.useBGR565 = True;
+  	} else {
+  		fprintf(stderr, "Warning: for 24bpp using -bgr233 -- Don't use FullColor!\n"); 
+  	}
+  }
+
+  if (appData.useBGR565) {
+  	if (visdepth < 24 || visbpp < 24 || vis->class != TrueColor) {
+  		fprintf(stderr, "disabling -16bpp BGR565 on non-depth 24 machine\n"); 
+		appData.useBGR565 = False;
+  	} else {
+		myFormat.bitsPerPixel = 16;
+		myFormat.depth = 16;
+		myFormat.trueColour = 1;
+		myFormat.bigEndian = 0;
+		myFormat.redMax   = 31;
+		myFormat.greenMax = 63;
+		myFormat.blueMax  = 31;
+		myFormat.redShift   = 11;
+		myFormat.greenShift = 5;
+		myFormat.blueShift  = 0;
+
+		fprintf(stderr, "Using default colormap and translating from BGR565 (65536 colors).  Pixel format:\n");
+		PrintPixelFormat(&myFormat);
+
+		SetupBGR565Map(vis->red_mask, vis->green_mask, vis->blue_mask);
+		return;
+  	}
+  }
+
   if (!appData.useBGR233 && (vis->class == TrueColor)) {
 
     myFormat.bitsPerPixel = visbpp;
@@ -116,21 +159,42 @@
     return;
   }
 
-  appData.useBGR233 = True;
+  if (appData.useBGR233 == 0) {
+	appData.useBGR233 = 256;
+  }
 
   myFormat.bitsPerPixel = 8;
   myFormat.depth = 8;
   myFormat.trueColour = 1;
   myFormat.bigEndian = 0;
-  myFormat.redMax = 7;
+  myFormat.redMax   = 7;
   myFormat.greenMax = 7;
-  myFormat.blueMax = 3;
-  myFormat.redShift = 0;
+  myFormat.blueMax  = 3;
+  myFormat.redShift   = 0;
   myFormat.greenShift = 3;
-  myFormat.blueShift = 6;
+  myFormat.blueShift  = 6;
+
+	if (appData.useBGR233 == 64) {
+		/* BGR222 */
+		myFormat.redMax   = 3;
+		myFormat.greenMax = 3;
+		myFormat.blueMax  = 3;
+		myFormat.redShift   = 0;
+		myFormat.greenShift = 2;
+		myFormat.blueShift  = 4;
+	}
+	if (appData.useBGR233 == 8) {
+		/* BGR111 */
+		myFormat.redMax   = 2;
+		myFormat.greenMax = 2;
+		myFormat.blueMax  = 2;
+		myFormat.redShift   = 0;
+		myFormat.greenShift = 1;
+		myFormat.blueShift  = 2;
+	}
 
   fprintf(stderr,
-       "Using default colormap and translating from BGR233.  Pixel format:\n");
+       "Using default colormap and translating from BGR233 (%d colors).  Pixel format:\n", appData.useBGR233);
   PrintPixelFormat(&myFormat);
 
   SetupBGR233Map();
@@ -282,8 +346,12 @@
   XFree(format);
 
   if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
-    fprintf(stderr,"Can't cope with %d bits-per-pixel.  Sorry.\n", bpp);
-    exit(1);
+	if (bpp == 24) {
+		fprintf(stderr,"Warning: 24 bits-per-pixel may have problems...\n");
+	} else {
+		fprintf(stderr,"Can't cope with %d bits-per-pixel.  Sorry.\n", bpp);
+		exit(1);
+	}
   }
 
   return bpp;
@@ -374,7 +442,7 @@
 	if (!exactBGR233[i] &&
 	    XAllocColor(dpy, cmap, &cmapEntry[i])) {
 
-	  if (cmapEntry[i].pixel == i) {
+	  if ((long) cmapEntry[i].pixel == i) {
 
 	    shared[i] = True; /* probably shared */
 
@@ -394,16 +462,43 @@
     for (r = 0; r < 8; r++) {
       for (g = 0; g < 8; g++) {
 	for (b = 0; b < 4; b++) {
-	  if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
+		int bs = 6, gs = 3, rs = 0;
+		int bm = 3, gm = 7, rm = 7;
+		if (appData.useBGR233 == 64) {
+			bs = 4; gs = 2; rs = 0;
+			bm = 3; gm = 3; rm = 3;
+		}
+		if (appData.useBGR233 == 8) {
+			bs = 2; gs = 1; rs = 0;
+			bm = 1; gm = 1; rm = 1;
+		}
+		if ((b > bm || g > gm || r > rm)) {
+			continue;
+		}
+	  if (BGR233ToPixel[(b<<bs) | (g<<gs) | (r<<rs)] == INVALID_PIXEL) {
 
 	    unsigned long minDistance = ULONG_MAX;
 
 	    for (i = 0; i < cmapSize; i++) {
 	      if (exactBGR233[i] || shared[i]) {
-		unsigned long distance
-		  = (abs(cmapEntry[i].red - r * 65535 / 7)
-		     + abs(cmapEntry[i].green - g * 65535 / 7)
-		     + abs(cmapEntry[i].blue - b * 65535 / 3));
+		unsigned long distance;
+		int r1, g1, b1;
+		if (appData.useGreyScale) {
+			int ave;
+			ave = (r + g + 2*b)/3;
+			r1 = ave;
+			g1 = ave;
+			b1 = ave/2;
+		} else {
+			r1 = r;
+			g1 = g;
+			b1 = b;
+		}
+		distance
+		  = (  abs(cmapEntry[i].red   - r1 * 65535 / rm)
+		     + abs(cmapEntry[i].green - g1 * 65535 / gm)
+		     + abs(cmapEntry[i].blue  - b1 * 65535 / bm));
+
 
 		if (distance < minDistance) {
 		  minDistance = distance;
@@ -412,7 +507,7 @@
 	      }
 	    }
 
-	    BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
+	    BGR233ToPixel[(b<<bs) | (g<<gs) | (r<<rs)] = nearestPixel;
 	    if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
 	      nSharedUsed++;
 	    usedAsNearest[nearestPixel] = True;
@@ -433,6 +528,59 @@
   }
 }
 
+static void
+SetupBGR565Map(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask)
+{
+  int r, g, b;
+  int r2, g2, b2;
+  long idx;
+  int cnt = 0;
+  unsigned long pixel = 0;
+
+    for (r = 0; r < 32; r++) {
+      for (g = 0; g < 64; g++) {
+	for (b = 0; b < 32; b++) {
+		int bs = 0, gs = 5, rs = 11;
+		int bm = 31, gm = 63, rm = 31;
+		if ((b > bm || g > gm || r > rm)) {
+			continue;
+		}
+		r2 = (255 * r) / rm;
+		g2 = (255 * g) / gm;
+		b2 = (255 * b) / bm;
+
+		pixel = (r2 << 16) | (g2 << 8) | (b2 << 0);
+		if (appData.useGreyScale) {
+			int ave;
+			int r1, g1, b1;
+			ave = (2*r + g + 2*b)/3;
+			r1 = ave/2;
+			g1 = ave;
+			b1 = ave/2;
+
+			r2 = (255 * r1) / rm;
+			g2 = (255 * g1) / gm;
+			b2 = (255 * b1) / bm;
+
+			pixel = (r2 << 16) | (g2 << 8) | (b2 << 0);
+		}
+
+		if (red_mask == 0xff) {
+			idx = (r<<bs) | (g<<gs) | (b<<rs);
+		} else {
+			idx = (b<<bs) | (g<<gs) | (r<<rs);
+		}
+		if (0) fprintf(stderr, "cnt: %5d idx: %lu pixel: 0x%08x\n", cnt, idx, (unsigned int) pixel);
+		BGR565ToPixel[idx] = pixel;
+		cnt++;
+	}
+      }
+    }
+	green_mask = 0;
+	blue_mask = 0;
+}
+
+
 
 /*
  * AllocateExactBGR233Colours() attempts to allocate each of the colours in the
@@ -484,8 +632,13 @@
     ri = rn;
     for (gi = 0; gi < gn; gi++) {
       for (bi = 0; bi < bn; bi++) {
-	if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
-	  return;
+	if (appData.useBGR233 == 64 && (bv[bi] > 3 || gv[gi] > 3 || rv[ri] > 3)) {
+		nBGR233ColoursAllocated++;
+	} else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) {
+		nBGR233ColoursAllocated++;
+	} else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) {
+		return;
+	}
       }
     }
     rn++;
@@ -496,8 +649,13 @@
     gi = gn;
     for (ri = 0; ri < rn; ri++) {
       for (bi = 0; bi < bn; bi++) {
-	if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
-	  return;
+	if (appData.useBGR233 == 64 && (bv[bi] > 3 || gv[gi] > 3 || rv[ri] > 3)) {
+		nBGR233ColoursAllocated++;
+	} else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) {
+		nBGR233ColoursAllocated++;
+	} else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) {
+	  	return;
+	}
       }
     }
     gn++;
@@ -507,8 +665,13 @@
       bi = bn;
       for (ri = 0; ri < rn; ri++) {
 	for (gi = 0; gi < gn; gi++) {
-	  if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
-	    return;
+	  if (appData.useBGR233 == 64 && (bv[bi] > 3 || gv[gi] > 3 || rv[ri] > 3)) {
+		nBGR233ColoursAllocated++;
+	  } else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) {
+		nBGR233ColoursAllocated++;
+	  } else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) {
+	    	return;
+	  }
 	}
       }
       bn++;
@@ -529,18 +692,36 @@
 AllocateBGR233Colour(int r, int g, int b)
 {
   XColor c;
+	int bs = 6, gs = 3, rs = 0;
+	int bm = 3, gm = 7, rm = 7;
 
   if (nBGR233ColoursAllocated >= appData.nColours)
     return False;
 
-  c.red = r * 65535 / 7;
-  c.green = g * 65535 / 7;
-  c.blue = b * 65535 / 3;
+	if (appData.useBGR233 == 64) {
+		bs = 4; gs = 2, rs = 0;
+		bm = 3; gm = 3; rm = 3;
+	}
+	if (appData.useBGR233 == 8) {
+		bs = 2; gs = 1, rs = 0;
+		bm = 1; gm = 1; rm = 1;
+	}
+
+	c.red =   r * 65535 / rm;
+	c.green = g * 65535 / gm;
+	c.blue =  b * 65535 / bm;
+	if (appData.useGreyScale) {
+		int ave;
+		ave = (c.red + c.green + c.blue)/3;
+		c.red   = ave;
+		c.green = ave;
+		c.blue  = ave;
+	}
 
   if (!XAllocColor(dpy, cmap, &c))
     return False;
 
-  BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
+  BGR233ToPixel[(b<<bs) | (g<<gs) | r] = c.pixel;
 
   nBGR233ColoursAllocated++;
 
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/corre.c vnc_unixsrc/vncviewer/corre.c
--- vnc_unixsrc.orig/vncviewer/corre.c	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/vncviewer/corre.c	2008-10-05 15:16:01.000000000 -0400
@@ -29,6 +29,18 @@
 #define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
 #define CARDBPP CONCAT2E(CARD,BPP)
 
+#define FillRectangle(x, y, w, h, color)  \
+	{ \
+		XGCValues _gcv; \
+		_gcv.foreground = color; \
+		if (!appData.useXserverBackingStore) { \
+			FillScreen(x, y, w, h, _gcv.foreground); \
+		} else { \
+			XChangeGC(dpy, gc, GCForeground, &_gcv); \
+			XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \
+		} \
+	}
+
 static Bool
 HandleCoRREBPP (int rx, int ry, int rw, int rh)
 {
@@ -50,11 +62,19 @@
 #if (BPP == 8)
     gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
 #else
+#if (BPP == 16)
+    gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix);
+#else
     gcv.foreground = pix;
 #endif
+#endif
 
+#if 0
     XChangeGC(dpy, gc, GCForeground, &gcv);
     XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
+#else
+    FillRectangle(rx, ry, rw, rh, gcv.foreground);
+#endif
 
     if (!ReadFromRFBServer(buffer, hdr.nSubrects * (4 + (BPP / 8))))
 	return False;
@@ -72,12 +92,22 @@
 #if (BPP == 8)
 	gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
 #else
+#if (BPP == 16)
+	gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix);
+#else
 	gcv.foreground = pix;
 #endif
+#endif
 
+#if 0
 	XChangeGC(dpy, gc, GCForeground, &gcv);
 	XFillRectangle(dpy, desktopWin, gc, rx + x, ry + y, w, h);
+#else
+	FillRectangle(rx + x, ry + y, w, h, gcv.foreground);
+#endif
     }
 
     return True;
 }
+
+#undef FillRectangle
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cp_it vnc_unixsrc/vncviewer/cp_it
--- vnc_unixsrc.orig/vncviewer/cp_it	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/cp_it	2009-03-06 20:02:05.000000000 -0500
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+dest=/dist/bin/vncviewerz-1.3dev5-resize
+suc "cp -p $dest $dest.back; mv $dest $dest.unlink; mv $dest.back $dest; rm $dest.unlink"
+strip ./vncviewer
+cat   ./vncviewer > $dest
+touch -r ./vncviewer $dest 
+yy=/dist/src/apps/VNC/etc/libvncserver_cvs/expts/etv/ssvnc/bin/Linux.i686/vncviewer
+mv $yy $yy.unlink
+cp -p ./vncviewer $yy
+mv $yy.turbovnc $yy.unlink.turbovnc
+cp -p ./vncviewer $HOME/etv_col/Linux.i686
+cp -p ./vncviewer.turbovnc $yy.turbovnc
+cp -p ./vncviewer.turbovnc $HOME/etv_col/Linux.i686/vncviewer.turbovnc
+chmod 755 $yy*
+
+rm -f $yy.unlink*
+ls -l ./vncviewer* $dest $yy* $HOME/etv_col/Linux.i686/vncviewer*
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewer/cursor.c
--- vnc_unixsrc.orig/vncviewer/cursor.c	2003-01-15 04:46:52.000000000 -0500
+++ vnc_unixsrc/vncviewer/cursor.c	2010-02-25 22:04:28.000000000 -0500
@@ -38,8 +38,11 @@
 
 
 static Bool prevSoftCursorSet = False;
-static Pixmap rcSavedArea;
-static CARD8 *rcSource, *rcMask;
+static Pixmap rcSavedArea, rcSavedArea_0;
+static int rcSavedArea_w = -1, rcSavedArea_h = -1;
+static char *rcSavedScale = NULL;
+static int rcSavedScale_len = 0;
+static CARD8 *rcSource = NULL, *rcMask;
 static int rcHotX, rcHotY, rcWidth, rcHeight;
 static int rcCursorX = 0, rcCursorY = 0;
 static int rcLockX, rcLockY, rcLockWidth, rcLockHeight;
@@ -48,8 +51,13 @@
 static Bool SoftCursorInLockedArea(void);
 static void SoftCursorCopyArea(int oper);
 static void SoftCursorDraw(void);
-static void FreeSoftCursor(void);
-static void FreeX11Cursor();
+void FreeSoftCursor(void);
+void FreeX11Cursor();
+
+extern XImage *image;
+extern XImage *image_scale;
+extern int scale_x, scale_y;
+int scale_round(int n, double factor);
 
 /* Copied from Xvnc/lib/font/util/utilbitmap.c */
 static unsigned char _reverse_byte[0x100] = {
@@ -91,6 +99,8 @@
 static Bool prevXCursorSet = False;
 static Cursor prevXCursor;
 
+extern double scale_factor_x;
+extern double scale_factor_y;
 
 Bool HandleXCursor(int xhot, int yhot, int width, int height)
 {
@@ -124,7 +134,7 @@
     XQueryBestCursor(dpy, dr, width, height, &wret, &hret);
   }
 
-  if (width * height == 0 || wret < width || hret < height) {
+  if (width * height == 0 || (int) wret < width || (int) hret < height) {
     /* Free resources */
     if (buf != NULL)
       free(buf);
@@ -139,7 +149,7 @@
   fg.green = (unsigned short)colors.foreGreen << 8 | colors.foreGreen;
   fg.blue  = (unsigned short)colors.foreBlue  << 8 | colors.foreBlue;
 
-  for (i = 0; i < bytesData * 2; i++)
+  for (i = 0; (size_t) i < bytesData * 2; i++)
     buf[i] = (char)_reverse_byte[(int)buf[i] & 0xFF];
 
   source = XCreateBitmapFromData(dpy, dr, buf, width, height);
@@ -167,148 +177,179 @@
 
 Bool HandleCursorShape(int xhot, int yhot, int width, int height, CARD32 enc)
 {
-  int bytesPerPixel;
-  size_t bytesPerRow, bytesMaskData;
-  Drawable dr;
-  rfbXCursorColors rgb;
-  CARD32 colors[2];
-  char *buf;
-  CARD8 *ptr;
-  int x, y, b;
-
-  bytesPerPixel = myFormat.bitsPerPixel / 8;
-  bytesPerRow = (width + 7) / 8;
-  bytesMaskData = bytesPerRow * height;
-  dr = DefaultRootWindow(dpy);
-
-  FreeSoftCursor();
+	int bytesPerPixel;
+	size_t bytesPerRow, bytesMaskData;
+	Drawable dr;
+	rfbXCursorColors rgb;
+	CARD32 colors[2];
+	char *buf;
+	CARD8 *ptr;
+	int x, y, b;
+
+	bytesPerPixel = myFormat.bitsPerPixel / 8;
+	bytesPerRow = (width + 7) / 8;
+	bytesMaskData = bytesPerRow * height;
+	dr = DefaultRootWindow(dpy);
 
-  if (width * height == 0)
-    return True;
-
-  /* Allocate memory for pixel data and temporary mask data. */
+	FreeSoftCursor();
 
-  rcSource = malloc(width * height * bytesPerPixel);
-  if (rcSource == NULL)
-    return False;
-
-  buf = malloc(bytesMaskData);
-  if (buf == NULL) {
-    free(rcSource);
-    return False;
-  }
+	if (width * height == 0) {
+		return True;
+	}
 
-  /* Read and decode cursor pixel data, depending on the encoding type. */
+	/* Allocate memory for pixel data and temporary mask data. */
 
-  if (enc == rfbEncodingXCursor) {
-    if (appData.useX11Cursor) {
-      HandleXCursor(xhot, yhot, width, height);
-      return True;
-    }
+	rcSource = malloc(width * height * bytesPerPixel);
+	if (rcSource == NULL) {
+		return False;
+	}
 
-    /* Read and convert background and foreground colors. */
-    if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) {
-      free(rcSource);
-      free(buf);
-      return False;
-    }
-    colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
-    colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
+	buf = malloc(bytesMaskData);
+	if (buf == NULL) {
+		free(rcSource);
+		rcSource = NULL;
+		return False;
+	}
 
-    /* Read 1bpp pixel data into a temporary buffer. */
-    if (!ReadFromRFBServer(buf, bytesMaskData)) {
-      free(rcSource);
-      free(buf);
-      return False;
-    }
+	/* Read and decode cursor pixel data, depending on the encoding type. */
 
-    /* Convert 1bpp data to byte-wide color indices. */
-    ptr = rcSource;
-    for (y = 0; y < height; y++) {
-      for (x = 0; x < width / 8; x++) {
-	for (b = 7; b >= 0; b--) {
-	  *ptr = buf[y * bytesPerRow + x] >> b & 1;
-	  ptr += bytesPerPixel;
-	}
-      }
-      for (b = 7; b > 7 - width % 8; b--) {
-	*ptr = buf[y * bytesPerRow + x] >> b & 1;
-	ptr += bytesPerPixel;
-      }
-    }
+	if (enc == rfbEncodingXCursor) {
+		if (appData.useX11Cursor) {
+			HandleXCursor(xhot, yhot, width, height);
+			return True;
+		}
+
+		/* Read and convert background and foreground colors. */
+		if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) {
+			free(rcSource);
+			rcSource = NULL;
+			free(buf);
+			return False;
+		}
+		colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
+		colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
+
+		/* Read 1bpp pixel data into a temporary buffer. */
+		if (!ReadFromRFBServer(buf, bytesMaskData)) {
+			free(rcSource);
+			rcSource = NULL;
+			free(buf);
+			return False;
+		}
+
+		/* Convert 1bpp data to byte-wide color indices. */
+		ptr = rcSource;
+		for (y = 0; y < height; y++) {
+			for (x = 0; x < width / 8; x++) {
+				for (b = 7; b >= 0; b--) {
+					*ptr = buf[y * bytesPerRow + x] >> b & 1;
+					ptr += bytesPerPixel;
+				}
+			}
+			for (b = 7; b > 7 - width % 8; b--) {
+				*ptr = buf[y * bytesPerRow + x] >> b & 1;
+				ptr += bytesPerPixel;
+			}
+		}
+
+		/* Convert indices into the actual pixel values. */
+		switch (bytesPerPixel) {
+		case 1:
+			for (x = 0; x < width * height; x++) {
+				rcSource[x] = (CARD8)colors[rcSource[x]];
+			}
+			break;
+		case 2:
+			for (x = 0; x < width * height; x++) {
+				((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]];
+			}
+			break;
+		case 4:
+			for (x = 0; x < width * height; x++) {
+				((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]];
+			}
+			break;
+		}
+
+	} else {	/* enc == rfbEncodingRichCursor */
+		if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) {
+			free(rcSource);
+			rcSource = NULL;
+			free(buf);
+			return False;
+		}
+	}
 
-    /* Convert indices into the actual pixel values. */
-    switch (bytesPerPixel) {
-    case 1:
-      for (x = 0; x < width * height; x++)
-	rcSource[x] = (CARD8)colors[rcSource[x]];
-      break;
-    case 2:
-      for (x = 0; x < width * height; x++)
-	((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]];
-      break;
-    case 4:
-      for (x = 0; x < width * height; x++)
-	((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]];
-      break;
-    }
+	/* Read and decode mask data. */
 
-  } else {			/* enc == rfbEncodingRichCursor */
+	if (!ReadFromRFBServer(buf, bytesMaskData)) {
+		free(rcSource);
+		rcSource = NULL;
+		free(buf);
+		return False;
+	}
 
-    if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) {
-      free(rcSource);
-      free(buf);
-      return False;
-    }
+	rcMask = malloc(width * height);
+	if (rcMask == NULL) {
+		free(rcSource);
+		rcSource = NULL;
+		free(buf);
+		return False;
+	}
 
-  }
+	ptr = rcMask;
+	for (y = 0; y < height; y++) {
+		for (x = 0; x < width / 8; x++) {
+			for (b = 7; b >= 0; b--) {
+				*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
+			}
+		}
+		for (b = 7; b > 7 - width % 8; b--) {
+			*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
+		}
+	}
 
-  /* Read and decode mask data. */
+	free(buf);
 
-  if (!ReadFromRFBServer(buf, bytesMaskData)) {
-    free(rcSource);
-    free(buf);
-    return False;
-  }
+	/* Set remaining data associated with cursor. */
 
-  rcMask = malloc(width * height);
-  if (rcMask == NULL) {
-    free(rcSource);
-    free(buf);
-    return False;
-  }
+	dr = DefaultRootWindow(dpy);
 
-  ptr = rcMask;
-  for (y = 0; y < height; y++) {
-    for (x = 0; x < width / 8; x++) {
-      for (b = 7; b >= 0; b--) {
-	*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
-      }
-    }
-    for (b = 7; b > 7 - width % 8; b--) {
-      *ptr++ = buf[y * bytesPerRow + x] >> b & 1;
-    }
-  }
+	if (scale_x > 0) {
+		int w = scale_round(width,  scale_factor_x) + 2;
+		int h = scale_round(height, scale_factor_y) + 2;
+		rcSavedArea = XCreatePixmap(dpy, dr, w, h, visdepth);
+		rcSavedArea_w = w;
+		rcSavedArea_h = h;
+	} else {
+		rcSavedArea = XCreatePixmap(dpy, dr, width, height, visdepth);
+		rcSavedArea_w = width;
+		rcSavedArea_h = height;
+	}
+	rcSavedArea_0 = XCreatePixmap(dpy, dr, width, height, visdepth);
 
-  free(buf);
+if (0) fprintf(stderr, "rcSavedArea_wh: %d %d scale_x: %d\n", rcSavedArea_w, rcSavedArea_h, scale_x); 
 
-  /* Set remaining data associated with cursor. */
+	if (rcSavedScale_len < 4 * width * height + 4096)  {
+		if (rcSavedScale) {
+			free(rcSavedScale);
+		}
+		rcSavedScale = (char *) malloc(2 * 4 * width * height + 4096);
+	}
 
-  dr = DefaultRootWindow(dpy);
-  rcSavedArea = XCreatePixmap(dpy, dr, width, height, visdepth);
-  rcHotX = xhot;
-  rcHotY = yhot;
-  rcWidth = width;
-  rcHeight = height;
+	rcHotX = xhot;
+	rcHotY = yhot;
+	rcWidth = width;
+	rcHeight = height;
 
-  SoftCursorCopyArea(OPER_SAVE);
-  SoftCursorDraw();
+	SoftCursorCopyArea(OPER_SAVE);
+	SoftCursorDraw();
 
-  rcCursorHidden = False;
-  rcLockSet = False;
+	rcCursorHidden = False;
+	rcLockSet = False;
 
-  prevSoftCursorSet = True;
-  return True;
+	prevSoftCursorSet = True;
+	return True;
 }
 
 /*********************************************************************
@@ -319,20 +360,27 @@
 
 Bool HandleCursorPos(int x, int y)
 {
-  if (appData.useX11Cursor) {
-    if (appData.fullScreen)
-      XWarpPointer(dpy, None, desktopWin, 0, 0, 0, 0, x, y);
-    
-    return True; 
-  }
+	if (x < 0) x = 0;
+	if (y < 0) y = 0;
 
-  if (x >= si.framebufferWidth)
-    x = si.framebufferWidth - 1;
-  if (y >= si.framebufferHeight)
-    y = si.framebufferHeight - 1;
+	/* fprintf(stderr, "xy: %d %d\n", x, y); */
 
-  SoftCursorMove(x, y);
-  return True;
+	if (x >= si.framebufferWidth) {
+		x = si.framebufferWidth - 1;
+	}
+	if (y >= si.framebufferHeight) {
+		y = si.framebufferHeight - 1;
+	}
+
+	if (appData.useX11Cursor) {
+		if (appData.fullScreen) {
+			XWarpPointer(dpy, None, desktopWin, 0, 0, 0, 0, x, y);
+		}
+		return True; 
+	}
+
+	SoftCursorMove(x, y);
+	return True;
 }
 
 /*********************************************************************
@@ -348,30 +396,31 @@
 {
   int newX, newY;
 
-  if (!prevSoftCursorSet)
-    return;
+	if (!prevSoftCursorSet) {
+		return;
+	}
 
-  if (!rcLockSet) {
-    rcLockX = x;
-    rcLockY = y;
-    rcLockWidth = w;
-    rcLockHeight = h;
-    rcLockSet = True;
-  } else {
-    newX = (x < rcLockX) ? x : rcLockX;
-    newY = (y < rcLockY) ? y : rcLockY;
-    rcLockWidth = (x + w > rcLockX + rcLockWidth) ?
-      (x + w - newX) : (rcLockX + rcLockWidth - newX);
-    rcLockHeight = (y + h > rcLockY + rcLockHeight) ?
-      (y + h - newY) : (rcLockY + rcLockHeight - newY);
-    rcLockX = newX;
-    rcLockY = newY;
-  }
+	if (!rcLockSet) {
+		rcLockX = x;
+		rcLockY = y;
+		rcLockWidth = w;
+		rcLockHeight = h;
+		rcLockSet = True;
+	} else {
+		newX = (x < rcLockX) ? x : rcLockX;
+		newY = (y < rcLockY) ? y : rcLockY;
+		rcLockWidth = (x + w > rcLockX + rcLockWidth) ?
+		    (x + w - newX) : (rcLockX + rcLockWidth - newX);
+		rcLockHeight = (y + h > rcLockY + rcLockHeight) ?
+		    (y + h - newY) : (rcLockY + rcLockHeight - newY);
+		rcLockX = newX;
+		rcLockY = newY;
+	}
 
-  if (!rcCursorHidden && SoftCursorInLockedArea()) {
-    SoftCursorCopyArea(OPER_RESTORE);
-    rcCursorHidden = True;
-  }
+	if (!rcCursorHidden && SoftCursorInLockedArea()) {
+		SoftCursorCopyArea(OPER_RESTORE);
+		rcCursorHidden = True;
+	}
 }
 
 /*********************************************************************
@@ -381,15 +430,16 @@
 
 void SoftCursorUnlockScreen(void)
 {
-  if (!prevSoftCursorSet)
-    return;
+	if (!prevSoftCursorSet) {
+		return;
+	}
 
-  if (rcCursorHidden) {
-    SoftCursorCopyArea(OPER_SAVE);
-    SoftCursorDraw();
-    rcCursorHidden = False;
-  }
-  rcLockSet = False;
+	if (rcCursorHidden) {
+		SoftCursorCopyArea(OPER_SAVE);
+		SoftCursorDraw();
+		rcCursorHidden = False;
+	}
+	rcLockSet = False;
 }
 
 /*********************************************************************
@@ -401,19 +451,19 @@
 
 void SoftCursorMove(int x, int y)
 {
-  if (prevSoftCursorSet && !rcCursorHidden) {
-    SoftCursorCopyArea(OPER_RESTORE);
-    rcCursorHidden = True;
-  }
+	if (prevSoftCursorSet && !rcCursorHidden) {
+		SoftCursorCopyArea(OPER_RESTORE);
+		rcCursorHidden = True;
+	}
 
-  rcCursorX = x;
-  rcCursorY = y;
+	rcCursorX = x;
+	rcCursorY = y;
 
-  if (prevSoftCursorSet && !(rcLockSet && SoftCursorInLockedArea())) {
-    SoftCursorCopyArea(OPER_SAVE);
-    SoftCursorDraw();
-    rcCursorHidden = False;
-  }
+	if (prevSoftCursorSet && !(rcLockSet && SoftCursorInLockedArea())) {
+		SoftCursorCopyArea(OPER_SAVE);
+		SoftCursorDraw();
+		rcCursorHidden = False;
+	}
 }
 
 
@@ -429,41 +479,169 @@
 	  rcLockY + rcLockHeight > rcCursorY - rcHotY);
 }
 
-static void SoftCursorCopyArea(int oper)
-{
-  int x, y, w, h;
+void new_pixmap(int w, int h) {
 
-  x = rcCursorX - rcHotX;
-  y = rcCursorY - rcHotY;
-  if (x >= si.framebufferWidth || y >= si.framebufferHeight)
-    return;
-
-  w = rcWidth;
-  h = rcHeight;
-  if (x < 0) {
-    w += x;
-    x = 0;
-  } else if (x + w > si.framebufferWidth) {
-    w = si.framebufferWidth - x;
-  }
-  if (y < 0) {
-    h += y;
-    y = 0;
-  } else if (y + h > si.framebufferHeight) {
-    h = si.framebufferHeight - y;
-  }
+	XFreePixmap(dpy, rcSavedArea);
 
-  if (oper == OPER_SAVE) {
-    /* Save screen area in memory. */
-#ifdef MITSHM
-    if (appData.useShm)
-      XSync(dpy, False);
-#endif
-    XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0);
-  } else {
-    /* Restore screen area. */
-    XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y);
-  }
+	if (w > 0 && h > 0) {
+		rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), w, h, visdepth);
+		rcSavedArea_w = w;
+		rcSavedArea_h = h;
+		
+	} else if (image_scale != NULL && scale_x > 0) {
+		int w2 = scale_round(rcWidth,  scale_factor_x) + 2;
+		int h2 = scale_round(rcHeight, scale_factor_y) + 2;
+		rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), w2, h2, visdepth);
+		rcSavedArea_w = w2;
+		rcSavedArea_h = h2;
+	} else {
+		rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), rcWidth, rcHeight, visdepth);
+		rcSavedArea_w = rcWidth;
+		rcSavedArea_h = rcHeight;
+	}
+}
+
+extern int XError_ign;
+
+static void SoftCursorCopyArea(int oper) {
+	int x, y, w, h;
+	int xs = 0, ys = 0, ws = 0, hs = 0;
+	static int scale_saved = 0, ss_w, ss_h;
+	int db = 0;
+
+	x = rcCursorX - rcHotX;
+	y = rcCursorY - rcHotY;
+	if (x >= si.framebufferWidth || y >= si.framebufferHeight) {
+		return;
+	}
+
+	w = rcWidth;
+	h = rcHeight;
+	if (x < 0) {
+		w += x;
+		x = 0;
+	} else if (x + w > si.framebufferWidth) {
+		w = si.framebufferWidth - x;
+	}
+	if (y < 0) {
+		h += y;
+		y = 0;
+	} else if (y + h > si.framebufferHeight) {
+		h = si.framebufferHeight - y;
+	}
+
+	if (image_scale != NULL && scale_x > 0) {
+		xs = (int) (x * scale_factor_x);
+		ys = (int) (y * scale_factor_y);
+		ws = scale_round(w, scale_factor_x);
+		hs = scale_round(h, scale_factor_y);
+
+		if (xs > 0) xs -= 1;
+		if (ys > 0) ys -= 1;
+		ws += 2;
+		hs += 2;
+	}
+
+	XError_ign = 1;
+
+	if (oper == OPER_SAVE) {
+		/* Save screen area in memory. */
+		scale_saved = 0;
+		if (appData.useXserverBackingStore) {
+			XSync(dpy, False);
+			XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0);
+		} else {
+			if (image_scale != NULL && scale_x > 0) {
+				int Bpp = image_scale->bits_per_pixel / 8;
+				int Bpl = image_scale->bytes_per_line;
+				int i;
+				char *src = image_scale->data + y * Bpl + x * Bpp;
+				char *dst = rcSavedScale;
+
+				if (ws > rcSavedArea_w || hs > rcSavedArea_h) {
+					new_pixmap(0, 0);
+				}
+
+if (db) fprintf(stderr, "save: %dx%d+%d+%d\n", ws, hs, xs, ys);
+
+				XPutImage(dpy, rcSavedArea, gc, image, xs, ys, 0, 0, ws, hs);
+
+				XPutImage(dpy, rcSavedArea_0, gc, image_scale, x, y, 0, 0, w, h);
+
+				scale_saved = 1;
+				ss_w = ws;
+				ss_h = hs;
+
+				for (i=0; i < h; i++) {
+					memcpy(dst, src, Bpp * w);
+					src += Bpl;
+					dst += Bpp * w;
+				}
+			} else {
+if (db) fprintf(stderr, "SAVE: %dx%d+%d+%d\n", w, h, x, y);
+				if (w > rcSavedArea_w || h > rcSavedArea_h) {
+					new_pixmap(0, 0);
+				}
+
+				XPutImage(dpy, rcSavedArea, gc, image, x, y, 0, 0, w, h);
+			}
+		}
+	} else {
+
+#define XE(s) if (XError_ign > 1) {fprintf(stderr, "X-%d\n", (s)); db = 1;}
+
+		/* Restore screen area. */
+		if (appData.useXserverBackingStore) {
+			XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y);
+XE(1)
+			XGetSubImage(dpy, rcSavedArea, 0, 0, w, h, AllPlanes, ZPixmap, image, x, y);
+XE(2)
+
+		} else {
+			if (image_scale != NULL && scale_x > 0) {
+				int Bpp = image_scale->bits_per_pixel / 8;
+				int Bpl = image_scale->bytes_per_line;
+				int i;
+				char *dst = image_scale->data + y * Bpl + x * Bpp;
+				char *src = rcSavedScale;
+
+				XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, ws, hs, xs, ys);
+XE(3)
+				XGetSubImage(dpy, rcSavedArea, 0, 0, ws, hs, AllPlanes, ZPixmap, image, xs, ys);
+XE(4)
+if (db) fprintf(stderr, "rstr: %dx%d+%d+%d\n", ws, hs, xs, ys);
+
+				for (i=0; i < h; i++) {
+					memcpy(dst, src, Bpp * w);
+					src += Bpp * w;
+					dst += Bpl;
+				}
+			} else {
+
+				if (scale_saved) {
+					XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, ss_w, ss_h, x, y);
+XE(5)
+					XGetSubImage(dpy, rcSavedArea, 0, 0, ss_w, ss_h, AllPlanes, ZPixmap, image, x, y);
+XE(6)
+					new_pixmap(w, h);
+				} else {
+					XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y);
+XE(7)
+					XGetSubImage(dpy, rcSavedArea, 0, 0, w, h, AllPlanes, ZPixmap, image, x, y);
+XE(8)
+				}
+
+if (db) fprintf(stderr, "RSTR: %dx%d+%d+%d\n", w, h, x, y);
+
+			}
+		}
+	}
+
+	if (XError_ign > 1) {
+		fprintf(stderr, "XError_ign: %d, oper: %s\n", XError_ign, oper ? "restore" : "save");
+	}
+
+	XError_ign = 0;
 }
 
 static void SoftCursorDraw(void)
@@ -472,43 +650,182 @@
   int offset, bytesPerPixel;
   char *pos;
 
+#define alphahack
+#ifdef alphahack
+  /* hack to have cursor transparency at 32bpp <runge@karlrunge.com> */
+  int alphablend = 0;
+
+  if (!rcSource) {
+  	return;
+  }
+
+  if (appData.useCursorAlpha) {
+  	alphablend = 1;
+  }
+
   bytesPerPixel = myFormat.bitsPerPixel / 8;
 
-  /* FIXME: Speed optimization is possible. */
-  for (y = 0; y < rcHeight; y++) {
-    y0 = rcCursorY - rcHotY + y;
-    if (y0 >= 0 && y0 < si.framebufferHeight) {
-      for (x = 0; x < rcWidth; x++) {
-	x0 = rcCursorX - rcHotX + x;
-	if (x0 >= 0 && x0 < si.framebufferWidth) {
-	  offset = y * rcWidth + x;
-	  if (rcMask[offset]) {
-	    pos = (char *)&rcSource[offset * bytesPerPixel];
-	    CopyDataToScreen(pos, x0, y0, 1, 1);
-	  }
+  if (alphablend && bytesPerPixel == 4) {
+	unsigned long pixel, put, *upos, *upix;
+	int got_alpha = 0, rsX, rsY, rsW, rsH;
+	static XImage *alpha_image = NULL;
+	static int iwidth = 192;
+
+	if (! alpha_image) {
+		/* watch out for tiny fb (rare) */
+		if (iwidth > si.framebufferWidth) {
+			iwidth = si.framebufferWidth;
+		}
+		if (iwidth > si.framebufferHeight) {
+			iwidth = si.framebufferHeight;
+		}
+
+		/* initialize an XImage with a chunk of desktopWin */
+		alpha_image = XGetImage(dpy, desktopWin, 0, 0, iwidth, iwidth,
+		    AllPlanes, ZPixmap);
 	}
-      }
-    }
+
+	/* first check if there is any non-zero alpha channel data at all: */
+	for (y = 0; y < rcHeight; y++) {
+		for (x = 0; x < rcWidth; x++) {
+			int alpha;
+
+			offset = y * rcWidth + x;
+			pos = (char *)&rcSource[offset * bytesPerPixel];
+
+			upos = (unsigned long *) pos;
+			alpha = (*upos & 0xff000000) >> 24;
+			if (alpha) {
+				got_alpha = 1;
+				break;
+			}
+		}
+		if (got_alpha) {
+			break;
+		}
+	}
+
+	if (!got_alpha) {
+		/* no alpha channel data, fallback to the old way */
+		goto oldway;
+	}
+
+	/* load the saved fb patch in to alpha_image (faster way?) */
+	if (image_scale != NULL && scale_x > 0) {
+		XGetSubImage(dpy, rcSavedArea_0, 0, 0, rcWidth, rcHeight, AllPlanes, ZPixmap, alpha_image, 0, 0);
+	} else {
+		XGetSubImage(dpy, rcSavedArea,   0, 0, rcWidth, rcHeight, AllPlanes, ZPixmap, alpha_image, 0, 0);
+	}
+
+	upix = (unsigned long *)alpha_image->data;
+
+	/* if the richcursor is clipped, the fb patch will be smaller */
+	rsW = rcWidth;
+	rsX = 0;	/* used to denote a shift from the left side */
+	x = rcCursorX - rcHotX;
+	if (x < 0) {
+		rsW += x;
+		rsX = -x;
+	} else if (x + rsW > si.framebufferWidth) {
+		rsW = si.framebufferWidth - x;
+	}
+	rsH = rcHeight;
+	rsY = 0;	/* used to denote a shift from the top side */
+	y = rcCursorY - rcHotY;
+	if (y < 0) {
+		rsH += y;
+		rsY = -y;
+	} else if (y + rsH > si.framebufferHeight) {
+		rsH = si.framebufferHeight - y;
+	}
+
+	/*
+	 * now loop over the cursor data, blend in the fb values,
+	 * and then overwrite the fb (CopyDataToScreen())
+	 */
+	for (y = 0; y < rcHeight; y++) {
+		y0 = rcCursorY - rcHotY + y;
+		if (y0 < 0 || y0 >= si.framebufferHeight) {
+			continue;	/* clipped */
+		}
+		for (x = 0; x < rcWidth; x++) {
+			int alpha, color_curs, color_fb, i;
+
+			x0 = rcCursorX - rcHotX + x;
+			if (x0 < 0 || x0 >= si.framebufferWidth) {
+				continue;	/* clipped */
+			}
+
+			offset = y * rcWidth + x;
+			pos = (char *)&rcSource[offset * bytesPerPixel];
+
+			/* extract secret alpha byte from rich cursor: */
+			upos = (unsigned long *) pos;
+			alpha = (*upos & 0xff000000) >> 24;	/* XXX MSB? */
+
+			/* extract the pixel from the fb: */
+			pixel = *(upix + (y-rsY)*iwidth + (x-rsX));
+
+			put = 0;
+			/* for simplicity, blend all 4 bytes */
+			for (i = 0; i < 4; i++) {
+				int sh = i*8;
+				color_curs = ((0xff << sh) & *upos) >> sh;
+				color_fb   = ((0xff << sh) & pixel) >> sh;
+
+				/* XXX assumes pre-multipled color_curs */
+				color_fb = color_curs
+				    + ((0xff - alpha) * color_fb)/0xff;
+				put |= color_fb << sh;
+			}
+			/* place in the fb: */
+	    		CopyDataToScreen((char *)&put, x0, y0, 1, 1);
+		}
+	}
+	return;
   }
+oldway:
+#endif
+
+	bytesPerPixel = myFormat.bitsPerPixel / 8;
+
+	/* FIXME: Speed optimization is possible. */
+	for (y = 0; y < rcHeight; y++) {
+		y0 = rcCursorY - rcHotY + y;
+		if (y0 >= 0 && y0 < si.framebufferHeight) {
+			for (x = 0; x < rcWidth; x++) {
+				x0 = rcCursorX - rcHotX + x;
+				if (x0 >= 0 && x0 < si.framebufferWidth) {
+					offset = y * rcWidth + x;
+					if (rcMask[offset]) {
+						pos = (char *)&rcSource[offset * bytesPerPixel];
+						CopyDataToScreen(pos, x0, y0, 1, 1);
+					}
+				}
+			}
+		}
+	}
+	XSync(dpy, False);
 }
 
-static void FreeSoftCursor(void)
+void FreeSoftCursor(void)
 {
-  if (prevSoftCursorSet) {
-    SoftCursorCopyArea(OPER_RESTORE);
-    XFreePixmap(dpy, rcSavedArea);
-    free(rcSource);
-    free(rcMask);
-    prevSoftCursorSet = False;
-  }
+	if (prevSoftCursorSet) {
+		SoftCursorCopyArea(OPER_RESTORE);
+		XFreePixmap(dpy, rcSavedArea);
+		XFreePixmap(dpy, rcSavedArea_0);
+		free(rcSource);
+		rcSource = NULL;
+		free(rcMask);
+		prevSoftCursorSet = False;
+	}
 }
 
 
-static void FreeX11Cursor()
+void FreeX11Cursor()
 {
-  if (prevXCursorSet) {
-    XFreeCursor(dpy, prevXCursor);
-    prevXCursorSet = False;
-  }
+	if (prevXCursorSet) {
+		XFreeCursor(dpy, prevXCursor);
+		prevXCursorSet = False;
+	}
 }
-
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncviewer/desktop.c
--- vnc_unixsrc.orig/vncviewer/desktop.c	2004-05-28 13:29:29.000000000 -0400
+++ vnc_unixsrc/vncviewer/desktop.c	2010-02-25 22:32:49.000000000 -0500
@@ -28,28 +28,497 @@
 #include <X11/extensions/XShm.h>
 #endif
 
+#include <X11/cursorfont.h>
+
 GC gc;
 GC srcGC, dstGC; /* used for debugging copyrect */
 Window desktopWin;
-Cursor dotCursor;
+Cursor dotCursor3 = None;
+Cursor dotCursor4 = None;
+Cursor bogoCursor = None;
+Cursor waitCursor = None;
 Widget form, viewport, desktop;
 
+int appshare_0_hint = -10000;
+int appshare_x_hint = -10000;
+int appshare_y_hint = -10000;
+
 static Bool modifierPressed[256];
 
-static XImage *image = NULL;
+XImage *image = NULL;
+XImage *image_ycrop = NULL;
+XImage *image_scale = NULL;
+
+int image_is_shm = 0;
 
 static Cursor CreateDotCursor();
 static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height);
 static void HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev,
 				    Boolean *cont);
 
+static void CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width,int height);
+
 static XtResource desktopBackingStoreResources[] = {
   {
-    XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0,
-    XtRImmediate, (XtPointer) Always,
+	XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0,
+	XtRImmediate, (XtPointer) Always,
   },
 };
 
+double scale_factor_x = 0.0;
+double scale_factor_y = 0.0;
+int scale_x = 0, scale_y = 0;
+int scale_round(int len, double fac);
+
+double last_rescale = 0.0;
+double last_fullscreen = 0.0;
+double start_time = 0.0;
+
+int prev_fb_width = -1;
+int prev_fb_height = -1;
+
+void get_scale_values(double *fx, double *fy) {
+	char *s = appData.scale;
+	double f, frac_x = -1.0, frac_y = -1.0;
+	int n, m;
+	int xmax = si.framebufferWidth;
+	int ymax = si.framebufferHeight;
+
+	if (appData.yCrop > 0) {
+		ymax = appData.yCrop;
+	}
+
+	if (sscanf(s, "%d/%d", &n, &m) == 2) {
+		if (m == 0) {
+			frac_x = 1.0;
+		} else {
+			frac_x = ((double) n) / ((double) m);
+		}
+	}
+	if (sscanf(s, "%dx%d", &n, &m) == 2) {
+		frac_x = ((double) n) / ((double) xmax);
+		frac_y = ((double) m) / ((double) ymax);
+	}
+	if (!strcasecmp(s, "fit")) {
+		frac_x = ((double) dpyWidth)  / ((double) xmax);
+		frac_y = ((double) dpyHeight) / ((double) ymax);
+	}
+	if (!strcasecmp(s, "auto")) {
+		Dimension w, h;
+		XtVaGetValues(toplevel, XtNheight, &h, XtNwidth, &w, NULL);
+		fprintf(stderr, "auto: %dx%d\n", w, h);
+		if (w > 32 && h > 32) {
+			frac_x = ((double) w) / ((double) xmax);
+			frac_y = ((double) h) / ((double) ymax);
+		}
+	}
+	if (frac_x < 0.0 && sscanf(s, "%lf", &f) == 1) {
+		if (f > 0.0) {
+			frac_x = f;
+		}
+	}
+
+	if (frac_y < 0.0) {
+		frac_y = frac_x;
+	}
+
+	if (frac_y > 0.0 && frac_x > 0.0) {
+		if (fx != NULL) {
+			*fx = frac_x;
+		}
+		if (fy != NULL) {
+			*fy = frac_y;
+		}
+	} else {
+		if (appData.scale) {
+			fprintf(stderr, "Invalid scale string: '%s'\n", appData.scale); 
+		} else {
+			fprintf(stderr, "Invalid scale string.\n"); 
+		}
+		appData.scale = NULL;
+	}
+}
+
+void try_create_image(void);
+void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, int height, int solid);
+void create_image();
+
+/* toplevel -> form -> viewport -> desktop */
+
+void adjust_Xt_win(int w, int h) {
+	int x, y, dw, dh, h0 = h;
+	int mw = w, mh = h;
+	int autoscale = 0;
+
+	if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) {
+		autoscale = 1;
+		mw = dpyWidth;
+		mh = dpyHeight;
+	}
+
+	if (appData.yCrop > 0) {
+		int ycrop = appData.yCrop; 
+		if (image_scale && scale_factor_y > 0.0) {
+			ycrop = scale_round(ycrop, scale_factor_y);
+			if (!autoscale) {
+				mh = ycrop;
+			}
+		}
+		XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL);
+		XtVaSetValues(form,     XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL);
+		h0 = ycrop;
+	} else {
+		XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, h, NULL);
+	}
+
+	fprintf(stderr, "adjust_Xt_win: %dx%d & %dx%d\n", w, h, w, h0);
+
+	XtVaSetValues(desktop,  XtNwidth, w, XtNheight, h, NULL);
+
+	XtResizeWidget(desktop, w, h, 0);
+
+	if (!autoscale) {
+		dw = appData.wmDecorationWidth;
+		dh = appData.wmDecorationHeight;
+
+		x = (dpyWidth  - w  - dw)/2;
+		y = (dpyHeight - h0 - dh)/2;
+
+		XtConfigureWidget(toplevel, x + dw, y + dh, w, h0, 0);
+	}
+}
+
+void rescale_image(void) {
+	double frac_x, frac_y; 
+	int w, h;
+
+	if (image == NULL) {
+		create_image();
+		return;
+	}
+
+	if (appData.useXserverBackingStore) {
+		create_image();
+		return;
+	}
+
+	if (image == NULL && image_scale == NULL) {
+		create_image();
+		return;
+	}
+
+	if (appData.scale == NULL) {
+		/* switching to not scaled */
+		frac_x = frac_y = 1.0;
+	} else {
+		get_scale_values(&frac_x, &frac_y);
+		if (frac_x < 0.0 || frac_y < 0.0) {
+			create_image();
+			return;
+		}
+	}
+
+	last_rescale = dnow();
+
+	SoftCursorLockArea(0, 0, si.framebufferWidth, si.framebufferHeight);
+
+	if (image_scale == NULL) {
+		/* switching from not scaled */
+		int i;
+		int Bpl = image->bytes_per_line;
+		char *dst, *src = image->data;
+
+		image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+		    si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0);
+
+		image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height);
+
+		fprintf(stderr, "rescale_image: switching from not scaled. created image_scale %dx%d\n", image_scale->width, image_scale->height);
+		fprintf(stderr, "rescale_image: copying image -> image_scale %dx%d -> %dx%d\n", image->width, image->height, image_scale->width, image_scale->height);
+
+		dst = image_scale->data;
+
+		/* copy from image->data */
+		for (i=0; i < image->height; i++) {
+			memcpy(dst, src, Bpl);
+			dst += Bpl;
+			src += Bpl;
+		}
+	}
+
+	/* now destroy image */
+	if (image && image->data) {
+		if (UsingShm()) {
+			ShmDetach();
+		}
+		XDestroyImage(image);
+		fprintf(stderr, "rescale_image: destroyed 'image'\n");
+		if (UsingShm()) {
+			ShmCleanup();
+		}
+		image = NULL;
+	}
+	if (image_ycrop && image_ycrop->data) {
+		XDestroyImage(image_ycrop);
+		fprintf(stderr, "rescale_image: destroyed 'image_ycrop'\n");
+		image_ycrop = NULL;
+	}
+
+	if (frac_x == 1.0 && frac_y == 1.0) {
+		/* switching to not scaled */
+		fprintf(stderr, "rescale_image: switching to not scaled.\n");
+		w = si.framebufferWidth;
+		h = si.framebufferHeight;
+
+		scale_factor_x = 0.0;
+		scale_factor_y = 0.0;
+		scale_x = 0;
+		scale_y = 0;
+	} else {
+		w = scale_round(si.framebufferWidth,  frac_x);
+		h = scale_round(si.framebufferHeight, frac_y);
+
+		scale_factor_x = frac_x;
+		scale_factor_y = frac_y;
+		scale_x = w;
+		scale_y = h;
+	}
+
+	adjust_Xt_win(w, h);
+
+	fprintf(stderr, "rescale: %dx%d  %.4f %.4f\n", w, h, scale_factor_x, scale_factor_y);
+
+	try_create_image();
+
+	if (image && image->data && image_scale && frac_x == 1.0 && frac_y == 1.0) {
+		/* switched to not scaled */
+		int i;
+		int Bpl = image->bytes_per_line;
+		char *dst = image->data;
+		char *src = image_scale->data;
+
+		fprintf(stderr, "rescale_image: switching to not scaled.\n");
+
+		for (i=0; i < image->height; i++) {
+			memcpy(dst, src, Bpl);
+			dst += Bpl;
+			src += Bpl;
+		}
+		XDestroyImage(image_scale);
+		fprintf(stderr, "rescale_image: destroyed 'image_scale'\n");
+		image_scale = NULL;
+	}
+
+	if (appData.yCrop > 0) {
+		int ycrop = appData.yCrop;
+		/* do the top part first so they can see it earlier */
+		put_image(0, 0, 0, 0, si.framebufferWidth, ycrop, 0);
+		if (si.framebufferHeight > ycrop) {
+			/* this is a big fb and so will take a long time */
+			if (waitCursor != None) {
+				XDefineCursor(dpy, desktopWin, waitCursor);
+				XSync(dpy, False);
+			}
+			put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight - ycrop, 0);
+			if (waitCursor != None) {
+				Xcursors(1);
+				if (appData.useX11Cursor) {
+					XSetWindowAttributes attr;
+					unsigned long valuemask = 0;
+					if (appData.viewOnly) {
+						attr.cursor = dotCursor4;    
+					} else {
+						attr.cursor = dotCursor3;    
+					}
+					valuemask |= CWCursor;
+					XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr);
+				}
+			}
+		}
+	} else {
+		put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight, 0);
+	}
+
+	SoftCursorUnlockScreen();
+
+	fprintf(stderr, "rescale: image_scale=%p image=%p image_ycrop=%p\n", (void *) image_scale, (void *) image, (void *) image_ycrop);
+	last_rescale = dnow();
+
+}
+
+void try_create_image(void) {
+	
+	image_is_shm = 0;
+	if (appData.useShm) {
+#ifdef MITSHM
+		image = CreateShmImage(0);
+		if (!image) {
+			if (appData.yCrop > 0) {
+				if (appData.scale != NULL && scale_x > 0) {
+					;
+				} else {
+					image_ycrop = CreateShmImage(1);
+					if (!image_ycrop) {
+						appData.useShm = False;
+					} else {
+						fprintf(stderr, "created smaller image_ycrop shm image: %dx%d\n",
+						    image_ycrop->width, image_ycrop->height);
+					}
+				}
+			} else {
+				appData.useShm = False;
+			}
+		} else {
+			image_is_shm = 1;
+			fprintf(stderr, "created shm image: %dx%d\n", image->width, image->height);
+		}
+#endif
+	}
+
+	if (!image) {
+		fprintf(stderr, "try_create_image: shm image create fail: image == NULL\n");
+		if (scale_x > 0) {
+			image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+			    scale_x, scale_y, BitmapPad(dpy), 0);
+		} else {
+			image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+			    si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0);
+		}
+
+		image->data = malloc(image->bytes_per_line * image->height);
+
+		if (!image->data) {
+			fprintf(stderr, "try_create_image: malloc failed\n");
+			exit(1);
+		} else {
+			fprintf(stderr, "try_create_image: created *non-shm* image: %dx%d\n", image->width, image->height);
+		}
+	}
+	fprintf(stderr, "try_create_image: image->bytes_per_line: %d\n", image->bytes_per_line);
+}
+
+void create_image() {
+	image = NULL;
+	image_ycrop = NULL;
+	image_scale = NULL;
+
+	fprintf(stderr, "create_image()\n");
+
+	if (CreateShmImage(-1) == NULL) {
+		appData.useShm = False;
+	}
+	if (appData.scale != NULL) {
+		if (appData.useXserverBackingStore) {
+			fprintf(stderr, "Cannot scale when using X11 backingstore.\n");
+		} else {
+			double frac_x = -1.0, frac_y = -1.0;
+
+			get_scale_values(&frac_x, &frac_y);
+
+			if (frac_x < 0.0 || frac_y < 0.0) {
+				fprintf(stderr, "Cannot figure out scale factor!\n");
+				goto bork;
+			}
+
+			scale_factor_x = 0.0;
+			scale_factor_y = 0.0;
+			scale_x = 0;
+			scale_y = 0;
+
+
+			if (1) {
+				int w, h, hyc;
+
+				w = scale_round(si.framebufferWidth,  frac_x);
+				h = scale_round(si.framebufferHeight, frac_y);
+				hyc = h;
+				if (appData.yCrop > 0) {
+					hyc = scale_round(appData.yCrop, frac_y);
+				}
+
+				/* image scale is full framebuffer */
+				image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+				    si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0);
+
+				image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height);
+
+				fprintf(stderr, "create_image: created image_scale %dx%d\n", image_scale->width, image_scale->height);
+
+				if (!image_scale->data) {
+					fprintf(stderr, "create_image: malloc failed\n");
+					XDestroyImage(image_scale);
+					fprintf(stderr, "create_image: destroyed 'image_scale'\n");
+					image_scale = NULL;
+				} else {
+					int h2;
+					scale_factor_x = frac_x;
+					scale_factor_y = frac_y;
+					scale_x = w;
+					scale_y = h;
+
+					XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, hyc, NULL);
+
+					h2 = scale_round(si.framebufferHeight, frac_y);
+					XtVaSetValues(desktop,  XtNwidth, w, XtNheight, h2, NULL);
+
+				}
+				fprintf(stderr, "create_image: scale: %dx%d  %.4f %.4f\n", w, h,
+				    scale_factor_x, scale_factor_y);
+			}
+		}
+	}
+	bork:
+	try_create_image();
+}
+
+int old_width = 0;
+int old_height = 0;
+
+int guessCrop(void) {
+	int w = si.framebufferWidth;
+
+	if (w == 320) {
+		return 240;
+	} else if (w == 400) {
+		return 300;
+	} else if (w == 640) {
+		return 480;
+	} else if (w == 800) {
+		return 600;
+	} else if (w == 1024) {
+		return 768;
+	} else if (w == 1152) {
+		return 864;
+	} else if (w == 1280) {
+		return 1024;
+	} else if (w == 1440) {
+		return 900;
+	} else if (w == 1600) {
+		return 1200;
+	} else if (w == 1680) {
+		return 1050;
+	} else if (w == 1920) {
+		return 1200;
+	} else {
+		int h = (3 * w) / 4;
+		return h;
+	}
+}
+
+void check_tall(void) {
+	if (appData.appShare) {
+		return;
+	}
+	if (! appData.yCrop) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		if (h > 2 * w) {
+			fprintf(stderr, "Tall display (%dx%d) suspect 'x11vnc -ncache' mode,\n", w, h);
+			fprintf(stderr, "  setting auto -ycrop detection.\n");
+			appData.yCrop = -1;
+		}
+	}
+}
 
 /*
  * DesktopInitBeforeRealization creates the "desktop" widget and the viewport
@@ -59,91 +528,1023 @@
 void
 DesktopInitBeforeRealization()
 {
-  int i;
+	int i;
+	int h = si.framebufferHeight;
+	int w = si.framebufferWidth;
+	double frac_x = 1.0, frac_y = 1.0;
+
+	start_time = dnow();
+
+	prev_fb_width = si.framebufferWidth;
+	prev_fb_height = si.framebufferHeight;
+
+	if (appData.scale != NULL) {
+		get_scale_values(&frac_x, &frac_y);
+		if (frac_x > 0.0 && frac_y > 0.0) {
+			w = scale_round(w,  frac_x);
+			h = scale_round(h,  frac_y);
+		} else {
+			appData.scale = NULL;
+		}
+	}
 
-  form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel,
-				 XtNborderWidth, 0,
-				 XtNdefaultDistance, 0, NULL);
+	form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel,
+	    XtNborderWidth, 0, XtNdefaultDistance, 0, NULL);
 
-  viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form,
-				     XtNborderWidth, 0,
-				     NULL);
+	viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form,
+	    XtNborderWidth, 0, NULL);
 
-  desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport,
-				    XtNborderWidth, 0,
-				    NULL);
+	desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport,
+	    XtNborderWidth, 0, NULL);
 
-  XtVaSetValues(desktop, XtNwidth, si.framebufferWidth,
-		XtNheight, si.framebufferHeight, NULL);
+	XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL);
 
-  XtAddEventHandler(desktop, LeaveWindowMask|ExposureMask,
-		    True, HandleBasicDesktopEvent, NULL);
+	XtAddEventHandler(desktop, LeaveWindowMask|EnterWindowMask|ExposureMask,
+	    True, HandleBasicDesktopEvent, NULL);
 
-  for (i = 0; i < 256; i++)
-    modifierPressed[i] = False;
+	if (appData.yCrop) {
+		int hm;
+		if (appData.yCrop < 0) {
+			appData.yCrop = guessCrop();
+			fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop);
+		}
+		hm = appData.yCrop;
 
-  image = NULL;
+		fprintf(stderr, "ycrop h: %d -> %d\n", hm, (int) (hm*frac_y));
 
-#ifdef MITSHM
-  if (appData.useShm) {
-    image = CreateShmImage();
-    if (!image)
-      appData.useShm = False;
-  }
+		hm *= frac_y;
+
+		XtVaSetValues(toplevel, XtNmaxHeight, hm, XtNheight, hm, NULL);
+		XtVaSetValues(form,     XtNmaxHeight, hm, XtNheight, hm, NULL);
+		XtVaSetValues(viewport, XtNforceBars, False, NULL);
+		XSync(dpy, False);
+	}
+
+	old_width  = si.framebufferWidth;
+	old_height = si.framebufferHeight;
+
+	for (i = 0; i < 256; i++) {
+		modifierPressed[i] = False;
+	}
+
+	create_image();
+}
+
+#if 0
+static Widget scrollbar_y = NULL;
+static int xsst = 2;
 #endif
 
-  if (!image) {
-    image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
-			 si.framebufferWidth, si.framebufferHeight,
-			 BitmapPad(dpy), 0);
-
-    image->data = malloc(image->bytes_per_line * image->height);
-    if (!image->data) {
-      fprintf(stderr,"malloc failed\n");
-      exit(1);
-    }
-  }
+#include <X11/Xaw/Scrollbar.h>
+
+#if 0
+static XtCallbackProc Scrolled(Widget w, XtPointer closure, XtPointer call_data) {
+	Position x, y;
+	XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL);
+	if (0) fprintf(stderr, "scrolled by %d pixels x=%d y=%d\n", (int) call_data, x, y);
+	if (xsst == 2) {
+		x = 0;
+		y = 0;
+		XtVaSetValues(desktop, XtNx, x, XtNy, y, NULL);
+	} else if (xsst) {
+		XawScrollbarSetThumb(w, 0.0, 0.0);
+	} else {
+		float t = 0.0;
+		XtVaSetValues(w, XtNtopOfThumb, &t, NULL);
+	}
+	if (closure) {}
 }
 
+static XtCallbackProc Jumped(Widget w, XtPointer closure, XtPointer call_data) {
+	float top = *((float *) call_data);
+	Position x, y;
+	XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL);
+	if (0) fprintf(stderr, "thumb value: %.4f x=%d y=%d\n", top, x, y);
+	if (top > 0.01) {
+		if (xsst == 2) {
+			x = 0;
+			y = 0;
+			XtVaSetValues(desktop, XtNx, x, XtNy, y, NULL);
+		} else if (xsst) {
+			XawScrollbarSetThumb(w, 0.0, 0.0);
+		} else {
+			float t = 0.0, s = 1.0;
+			XtVaSetValues(w, XtNtopOfThumb, *(XtArgVal*)&t, XtNshown, *(XtArgVal*)&s, NULL);
+		}
+	}
+	if (closure) {}
+}
+#endif
+
+extern double dnow(void);
+
+void check_things() {
+	static int first = 1;
+	static double last_scrollbar = 0.0;
+	int w = si.framebufferWidth;
+	int h = si.framebufferHeight;
+	double now = dnow();
+	static double last = 0;
+	double fac = image_scale ? scale_factor_y : 1.0;
+
+	if (first) {
+		first = 0;
+		SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False);
+	}
+	if (appData.yCrop > 0 && appData.yCrop * fac < dpyHeight && h > 2*w && now > last_scrollbar + 0.25) {
+		Widget wv, wh, wc;
+		Position x0, y0;
+		Position x1, y1;
+		Dimension w0, h0, b0;
+		Dimension w1, h1, b1;
+		Dimension w2, h2, b2;
+		
+		wc = XtNameToWidget(viewport, "clip");
+		wv = XtNameToWidget(viewport, "vertical");
+		wh = XtNameToWidget(viewport, "horizontal");
+		if (wc && wv && wh) {
+			int sb = appData.sbWidth;
+			XtVaGetValues(wv, XtNwidth, &w0, XtNheight, &h0, XtNborderWidth, &b0, XtNx, &x0, XtNy, &y0, NULL);
+			XtVaGetValues(wh, XtNwidth, &w1, XtNheight, &h1, XtNborderWidth, &b1, XtNx, &x1, XtNy, &y1, NULL);
+			XtVaGetValues(wc, XtNwidth, &w2, XtNheight, &h2, XtNborderWidth, &b2, NULL);
+			if (!sb) {
+				sb = 2;
+			}
+			if (w0 != sb || h1 != sb) {
+				fprintf(stderr, "Very tall (-ncache) fb, setting scrollbar thickness to: %d pixels (%d/%d)\n\n", sb, w0, h1);
+				
+				XtUnmanageChild(wv);
+				XtUnmanageChild(wh);
+				XtUnmanageChild(wc);
+
+				XtVaSetValues(wv, XtNwidth,  sb, XtNx, x0 + (w0 - sb), NULL);
+				XtVaSetValues(wh, XtNheight, sb, XtNy, y1 + (h1 - sb), NULL);
+				w2 = w2 + (w0 - sb);
+				h2 = h2 + (h1 - sb);
+				if (w2 > 10 && h2 > 10) {
+					XtVaSetValues(wc, XtNwidth, w2, XtNheight, h2, NULL);
+				}
+
+				XtManageChild(wv);
+				XtManageChild(wh);
+				XtManageChild(wc);
+
+				appData.sbWidth = sb;
+			}
+		}
+		last_scrollbar = dnow();
+	}
+	
+	if (now <= last + 0.25) {
+		return;
+	}
+
+	if (image_scale) {
+		scale_check_zrle();
+	}
+
+	/* e.g. xrandr resize */
+	dpyWidth  = WidthOfScreen(DefaultScreenOfDisplay(dpy));
+	dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
+
+	if (appData.scale != NULL) {
+		static Dimension last_w = 0, last_h = 0;
+		static double last_resize = 0.0;
+		Dimension w, h;
+		if (last_w == 0) {
+			XtVaGetValues(toplevel, XtNwidth, &last_w, XtNheight, &last_h, NULL);
+			last_resize = now;
+		}
+		if (now < last_resize + 0.5) {
+			;
+		} else if (appData.fullScreen) {
+			;
+		} else if (!strcmp(appData.scale, "auto")) {
+			XtVaGetValues(toplevel, XtNwidth, &w, XtNheight, &h, NULL);
+			if (w < 32 || h < 32)  {
+				;
+			} else if (last_w != w || last_h != h) {
+				Window rr, cr, r = DefaultRootWindow(dpy);
+				int rx, ry, wx, wy;
+				unsigned int mask;
+				/* make sure mouse buttons not pressed */
+				if (XQueryPointer(dpy, r, &rr, &cr, &rx, &ry, &wx, &wy, &mask)) {
+					if (mask == 0) {
+						rescale_image();
+						last_w = w;
+						last_h = h;
+						last_resize = dnow();
+					}
+				}
+			}
+		}
+	}
+
+	last = dnow();
+}
 
 /*
  * DesktopInitAfterRealization does things which require the X windows to
  * exist.  It creates some GCs and sets the dot cursor.
  */
 
+void Xcursors(int set) {
+	if (dotCursor3 == None) {
+		dotCursor3 = CreateDotCursor(3);
+	}
+	if (dotCursor4 == None) {
+		dotCursor4 = CreateDotCursor(4);
+	}
+	if (set) {
+		XSetWindowAttributes attr;
+		unsigned long valuemask = 0;
+
+		if (!appData.useX11Cursor) {
+			if (appData.viewOnly) {
+				attr.cursor = dotCursor4;    
+			} else {
+				attr.cursor = dotCursor3;    
+			}
+			valuemask |= CWCursor;
+			XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr);
+		}
+	}
+}
+
 void
 DesktopInitAfterRealization()
 {
-  XGCValues gcv;
-  XSetWindowAttributes attr;
-  unsigned long valuemask;
-
-  desktopWin = XtWindow(desktop);
-
-  gc = XCreateGC(dpy,desktopWin,0,NULL);
-
-  gcv.function = GXxor;
-  gcv.foreground = 0x0f0f0f0f;
-  srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
-  gcv.foreground = 0xf0f0f0f0;
-  dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
-
-  XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
-		 NULL, 0);
-
-  XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store,
-			      desktopBackingStoreResources, 1, NULL);
-  valuemask = CWBackingStore;
-
-  if (!appData.useX11Cursor) {
-    dotCursor = CreateDotCursor();
-    attr.cursor = dotCursor;    
-    valuemask |= CWCursor;
-  }
+	XGCValues gcv;
+	XSetWindowAttributes attr;
+	XWindowAttributes gattr;
+	unsigned long valuemask = 0;
+
+	desktopWin = XtWindow(desktop);
+
+	gc = XCreateGC(dpy,desktopWin,0,NULL);
+
+	gcv.function = GXxor;
+	gcv.foreground = 0x0f0f0f0f;
+	srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
+	gcv.foreground = 0xf0f0f0f0;
+	dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
+
+	XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+	    NULL, 0);
+
+	if (appData.useXserverBackingStore) {
+		Screen *s = DefaultScreenOfDisplay(dpy);
+		if (DoesBackingStore(s) != Always) {
+			fprintf(stderr, "X server does not do backingstore, disabling it.\n");
+			appData.useXserverBackingStore = False;
+		}
+	}
+
+	if (appData.useXserverBackingStore) {
+		XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store,
+		    desktopBackingStoreResources, 1, NULL);
+		valuemask |= CWBackingStore;
+	} else {
+		attr.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
+		valuemask |= CWBackPixel;
+	}
+
+	Xcursors(0);
+	if (!appData.useX11Cursor) {
+		if (appData.viewOnly) {
+			attr.cursor = dotCursor4;    
+		} else {
+			attr.cursor = dotCursor3;    
+		}
+		valuemask |= CWCursor;
+	}
+	bogoCursor = XCreateFontCursor(dpy, XC_bogosity);
+	waitCursor = XCreateFontCursor(dpy, XC_watch);
+
+	XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr);
+
+	if (XGetWindowAttributes(dpy, desktopWin, &gattr)) {
+#if 0
+		fprintf(stderr, "desktopWin backingstore: %d save_under: %d\n", gattr.backing_store, gattr.save_under);
+#endif
+	}
+	fprintf(stderr, "\n");
+}
+
+extern void FreeX11Cursor(void);
+extern void FreeSoftCursor(void);
 
-  XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr);
+void
+DesktopCursorOff()
+{
+	if (dotCursor3 == None) {
+		dotCursor3 = CreateDotCursor(3);
+		dotCursor4 = CreateDotCursor(4);
+	}
+	if (appData.viewOnly) {
+		XDefineCursor(dpy, desktopWin, dotCursor4);
+	} else {
+		XDefineCursor(dpy, desktopWin, dotCursor3);
+	}
+	FreeX11Cursor();
+	FreeSoftCursor();
+}
+
+
+#define CEIL(x)  ( (double) ((int) (x)) == (x) ? \
+	(double) ((int) (x)) : (double) ((int) (x) + 1) )
+#define FLOOR(x) ( (double) ((int) (x)) )
+
+#if 0
+static int nfix(int i, int n) {
+	if (i < 0) {
+		i = 0;
+	} else if (i >= n) {
+		i = n - 1;
+	}
+	return i;
 }
+#else
+#define nfix(i, n) ( i < 0 ? 0 : ( (i >= n) ? (n - 1) : i  ) )
+#endif
+
+int scale_round(int len, double fac) {
+        double eps = 0.000001;
+
+        len = (int) (len * fac + eps);
+        if (len < 1) {
+                len = 1;
+        }
+        return len;
+}
+
+static void scale_rect(double factor_x, double factor_y, int blend, int interpolate,
+    int *px, int *py, int *pw, int *ph, int solid) {
+
+	int i, j, i1, i2, j1, j2;       /* indices for scaled fb (dest) */
+	int I, J, I1, I2, J1, J2;       /* indices for main fb   (source) */
+
+	double w, wx, wy, wtot; /* pixel weights */
+
+	double x1 = 0, y1, x2 = 0, y2;  /* x-y coords for destination pixels edges */
+	double dx, dy;          /* size of destination pixel */
+	double ddx=0, ddy=0;    /* for interpolation expansion */
+
+	char *src, *dest;       /* pointers to the two framebuffers */
+
+	unsigned short us = 0;
+	unsigned char  uc = 0;
+	unsigned int   ui = 0;
+
+	int use_noblend_shortcut = 1;
+	int shrink;             /* whether shrinking or expanding */
+	static int constant_weights = -1, mag_int = -1;
+	static int last_Nx = -1, last_Ny = -1, cnt = 0;
+	static double last_factor = -1.0;
+	int b, k;
+	double pixave[4];       /* for averaging pixel values */
+
+	/* internal */
+
+	int X1, X2, Y1, Y2;
 
+	int Nx = si.framebufferWidth;
+	int Ny = si.framebufferHeight;
+
+	int nx = scale_round(Nx, factor_x);
+	int ny = scale_round(Ny, factor_y);
+
+	int Bpp = image->bits_per_pixel / 8;
+	int dst_bytes_per_line = image->bytes_per_line;
+	int src_bytes_per_line = image_scale->bytes_per_line;
+
+	unsigned long main_red_mask = image->red_mask;
+	unsigned long main_green_mask = image->green_mask;
+	unsigned long main_blue_mask = image->blue_mask;
+	int mark = 1;
+
+	char *src_fb = image_scale->data;
+	char *dst_fb = image->data;
+
+	static int nosolid = -1;
+	int sbdy = 3;
+	double fmax = factor_x > factor_y ? factor_x : factor_y;
+#if 0
+	double fmin = factor_x < factor_y ? factor_x : factor_y;
+#endif
+
+	X1 = *px;
+	X2 = *px + *pw;
+	Y1 = *py;
+	Y2 = *py + *ph;
+
+	if (fmax > 1.0) {
+		/* try to avoid problems with bleeding... */
+		sbdy = (int) (2.0 * fmax * sbdy);
+	}
+
+	/* fprintf(stderr, "scale_rect: %dx%d+%d+%d\n", *pw, *ph, *px, *py); */
+
+	*px = (int) (*px * factor_x);
+	*py = (int) (*py * factor_y);
+	*pw = scale_round(*pw, factor_x);
+	*ph = scale_round(*ph, factor_y);
+
+	if (nosolid < 0) {
+		if (getenv("SSVNC_NOSOLID")) {
+			nosolid = 1;
+		} else {
+			nosolid = 0;
+		}
+	}
+	if (nosolid) solid = 0;
+
+#define rfbLog printf
+/* Begin taken from x11vnc scale: */
+
+	if (factor_x <= 1.0 || factor_y <= 1.0) {
+		shrink = 1;
+	} else {
+		shrink = 0;
+		interpolate = 1;
+	}
+
+	/*
+	 * N.B. width and height (real numbers) of a scaled pixel.
+	 * both are > 1   (e.g. 1.333 for -scale 3/4)
+	 * they should also be equal but we don't assume it.
+	 *
+	 * This new way is probably the best we can do, take the inverse
+	 * of the scaling factor to double precision.
+	 */
+	dx = 1.0/factor_x;
+	dy = 1.0/factor_y;
+
+	/*
+	 * There is some speedup if the pixel weights are constant, so
+	 * let's special case these.
+	 *
+	 * If scale = 1/n and n divides Nx and Ny, the pixel weights
+	 * are constant (e.g. 1/2 => equal on 2x2 square).
+	 */
+	if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) {
+		constant_weights = -1;
+		mag_int = -1;
+		last_Nx = Nx;
+		last_Ny = Ny;
+		last_factor = factor_x;
+	}
+
+	if (constant_weights < 0 && factor_x != factor_y) {
+		constant_weights = 0;
+		mag_int = 0;
+	} else if (constant_weights < 0) {
+		int n = 0;
+		double factor = factor_x;
+
+		constant_weights = 0;
+		mag_int = 0;
+
+		for (i = 2; i<=128; i++) {
+			double test = ((double) 1)/ i;
+			double diff, eps = 1.0e-7;
+			diff = factor - test;
+			if (-eps < diff && diff < eps) {
+				n = i;
+				break;
+			}
+		}
+		if (! blend || ! shrink || interpolate) {
+			;
+		} else if (n != 0) {
+			if (Nx % n == 0 && Ny % n == 0) {
+				static int didmsg = 0;
+				if (mark && ! didmsg) {
+					didmsg = 1;
+					rfbLog("scale_and_mark_rect: using "
+					    "constant pixel weight speedup "
+					    "for 1/%d\n", n);
+				}
+				constant_weights = 1;
+			}
+		}
+
+		n = 0;
+		for (i = 2; i<=32; i++) {
+			double test = (double) i;
+			double diff, eps = 1.0e-7;
+			diff = factor - test;
+			if (-eps < diff && diff < eps) {
+				n = i;
+				break;
+			}
+		}
+		if (! blend && factor > 1.0 && n) {
+			mag_int = n;
+		}
+	}
+if (0) fprintf(stderr, "X1: %d Y1: %d X2: %d Y2: %d\n", X1, Y1, X2, Y2);
+
+	if (mark && !shrink && blend) {
+		/*
+		 * kludge: correct for interpolating blurring leaking
+		 * up or left 1 destination pixel.
+		 */
+		if (X1 > 0) X1--;
+		if (Y1 > 0) Y1--;
+	}
+
+	/*
+	 * find the extent of the change the input rectangle induces in
+	 * the scaled framebuffer.
+	 */
+
+	/* Left edges: find largest i such that i * dx <= X1  */
+	i1 = FLOOR(X1/dx);
+
+	/* Right edges: find smallest i such that (i+1) * dx >= X2+1  */
+	i2 = CEIL( (X2+1)/dx ) - 1;
+
+	/* To be safe, correct any overflows: */
+	i1 = nfix(i1, nx);
+	i2 = nfix(i2, nx) + 1;	/* add 1 to make a rectangle upper boundary */
+
+	/* Repeat above for y direction: */
+	j1 = FLOOR(Y1/dy);
+	j2 = CEIL( (Y2+1)/dy ) - 1;
+
+	j1 = nfix(j1, ny);
+	j2 = nfix(j2, ny) + 1;
+
+	/*
+	 * special case integer magnification with no blending.
+	 * vision impaired magnification usage is interested in this case.
+	 */
+	if (mark && ! blend && mag_int && Bpp != 3) {
+		int jmin, jmax, imin, imax;
+
+		/* outer loop over *source* pixels */
+		for (J=Y1; J < Y2; J++) {
+		    jmin = J * mag_int;
+		    jmax = jmin + mag_int;
+		    for (I=X1; I < X2; I++) {
+			/* extract value */
+			src = src_fb + J*src_bytes_per_line + I*Bpp;
+			if (Bpp == 4) {
+				ui = *((unsigned int *)src);
+			} else if (Bpp == 2) {
+				us = *((unsigned short *)src);
+			} else if (Bpp == 1) {
+				uc = *((unsigned char *)src);
+			}
+			imin = I * mag_int;
+			imax = imin + mag_int;
+			/* inner loop over *dest* pixels */
+			for (j=jmin; j<jmax; j++) {
+			    dest = dst_fb + j*dst_bytes_per_line + imin*Bpp;
+			    for (i=imin; i<imax; i++) {
+				if (Bpp == 4) {
+					*((unsigned int *)dest) = ui;
+				} else if (Bpp == 2) {
+					*((unsigned short *)dest) = us;
+				} else if (Bpp == 1) {
+					*((unsigned char *)dest) = uc;
+				}
+				dest += Bpp;
+			    }
+			}
+		    }
+		}
+		goto markit;
+	}
+
+	/* set these all to 1.0 to begin with */
+	wx = 1.0;
+	wy = 1.0;
+	w  = 1.0;
+
+	/*
+	 * Loop over destination pixels in scaled fb:
+	 */
+	for (j=j1; j<j2; j++) {
+		int jbdy = 1, I1_solid = 0;
+
+		y1 =  j * dy;	/* top edge */
+		if (y1 > Ny - 1) {
+			/* can go over with dy = 1/scale_fac */
+			y1 = Ny - 1;
+		}
+		y2 = y1 + dy;	/* bottom edge */
+
+		/* Find main fb indices covered by this dest pixel: */
+		J1 = (int) FLOOR(y1);
+		J1 = nfix(J1, Ny);
+
+		if (shrink && ! interpolate) {
+			J2 = (int) CEIL(y2) - 1;
+			J2 = nfix(J2, Ny);
+		} else {
+			J2 = J1 + 1;	/* simple interpolation */
+			ddy = y1 - J1;
+		}
+
+		/* destination char* pointer: */
+		dest = dst_fb + j*dst_bytes_per_line + i1*Bpp;
+
+		if (solid) {
+			if (j1+sbdy <= j && j < j2-sbdy) {
+				jbdy = 0;
+				x1 = (i1+sbdy) * dx;
+				if (x1 > Nx - 1) {
+					x1 = Nx - 1;
+				}
+				I1_solid = (int) FLOOR(x1);
+				if (I1_solid >= Nx) I1_solid = Nx - 1;
+			}
+		}
+		
+		for (i=i1; i<i2; i++) {
+			int solid_skip = 0;
+
+			if (solid) {
+				/* if the region is solid, we can use the noblend speedup */
+				if (!jbdy && i1+sbdy <= i && i < i2-sbdy) {
+					solid_skip = 1;
+					/* pixels all the same so use X1: */
+					I1 = I1_solid;
+					goto jsolid;
+				}
+			}
+
+			x1 =  i * dx;	/* left edge */
+			if (x1 > Nx - 1) {
+				/* can go over with dx = 1/scale_fac */
+				x1 = Nx - 1;
+			}
+			x2 = x1 + dx;	/* right edge */
+
+			/* Find main fb indices covered by this dest pixel: */
+			I1 = (int) FLOOR(x1);
+			if (I1 >= Nx) I1 = Nx - 1;
+
+			jsolid:
+			cnt++;
+
+			if ((!blend && use_noblend_shortcut) || solid_skip) {
+				/*
+				 * The noblend case involves no weights,
+				 * and 1 pixel, so just copy the value
+				 * directly.
+				 */
+				src = src_fb + J1*src_bytes_per_line + I1*Bpp;
+				if (Bpp == 4) {
+					*((unsigned int *)dest)
+					    = *((unsigned int *)src);
+				} else if (Bpp == 2) {
+					*((unsigned short *)dest)
+					    = *((unsigned short *)src);
+				} else if (Bpp == 1) {
+					*(dest) = *(src);
+				} else if (Bpp == 3) {
+					/* rare case */
+					for (k=0; k<=2; k++) {
+						*(dest+k) = *(src+k);
+					}
+				}
+				dest += Bpp;
+				continue;
+			}
+			
+			if (shrink && ! interpolate) {
+				I2 = (int) CEIL(x2) - 1;
+				if (I2 >= Nx) I2 = Nx - 1;
+			} else {
+				I2 = I1 + 1;	/* simple interpolation */
+				ddx = x1 - I1;
+			}
+#if 0
+if (first) fprintf(stderr, "  I1=%d I2=%d J1=%d J2=%d\n", I1, I2, J1, J2);
+#endif
+
+			/* Zero out accumulators for next pixel average: */
+			for (b=0; b<4; b++) {
+				pixave[b] = 0.0; /* for RGB weighted sums */
+			}
+
+			/*
+			 * wtot is for accumulating the total weight.
+			 * It should always sum to 1/(scale_fac * scale_fac).
+			 */
+			wtot = 0.0;
+
+			/*
+			 * Loop over source pixels covered by this dest pixel.
+			 * 
+			 * These "extra" loops over "J" and "I" make
+			 * the cache/cacheline performance unclear.
+			 * For example, will the data brought in from
+			 * src for j, i, and J=0 still be in the cache
+			 * after the J > 0 data have been accessed and
+			 * we are at j, i+1, J=0?  The stride in J is
+			 * main_bytes_per_line, and so ~4 KB.
+			 *
+			 * Typical case when shrinking are 2x2 loop, so
+			 * just two lines to worry about.
+			 */
+			for (J=J1; J<=J2; J++) {
+			    /* see comments for I, x1, x2, etc. below */
+			    if (constant_weights) {
+				;
+			    } else if (! blend) {
+				if (J != J1) {
+					continue;
+				}
+				wy = 1.0;
+
+				/* interpolation scheme: */
+			    } else if (! shrink || interpolate) {
+				if (J >= Ny) {
+					continue;
+				} else if (J == J1) {
+					wy = 1.0 - ddy;
+				} else if (J != J1) {
+					wy = ddy;
+				}
+
+				/* integration scheme: */
+			    } else if (J < y1) {
+				wy = J+1 - y1;
+			    } else if (J+1 > y2) {
+				wy = y2 - J;
+			    } else {
+				wy = 1.0;
+			    }
+
+			    src = src_fb + J*src_bytes_per_line + I1*Bpp;
+
+			    for (I=I1; I<=I2; I++) {
+
+				/* Work out the weight: */
+
+				if (constant_weights) {
+					;
+				} else if (! blend) {
+					/*
+					 * Ugh, PseudoColor colormap is
+					 * bad news, to avoid random
+					 * colors just take the first
+					 * pixel.  Or user may have
+					 * specified :nb to fraction.
+					 * The :fb will force blending
+					 * for this case.
+					 */
+					if (I != I1) {
+						continue;
+					}
+					wx = 1.0;
+
+					/* interpolation scheme: */
+				} else if (! shrink || interpolate) {
+					if (I >= Nx) {
+						continue;	/* off edge */
+					} else if (I == I1) {
+						wx = 1.0 - ddx;
+					} else if (I != I1) {
+						wx = ddx;
+					}
+
+					/* integration scheme: */
+				} else if (I < x1) {
+					/* 
+					 * source left edge (I) to the
+					 * left of dest left edge (x1):
+					 * fractional weight
+					 */
+					wx = I+1 - x1;
+				} else if (I+1 > x2) {
+					/* 
+					 * source right edge (I+1) to the
+					 * right of dest right edge (x2):
+					 * fractional weight
+					 */
+					wx = x2 - I;
+				} else {
+					/* 
+					 * source edges (I and I+1) completely
+					 * inside dest edges (x1 and x2):
+					 * full weight
+					 */
+					wx = 1.0;
+				}
+
+				w = wx * wy;
+				wtot += w;
+
+				/* 
+				 * We average the unsigned char value
+				 * instead of char value: otherwise
+				 * the minimum (char 0) is right next
+				 * to the maximum (char -1)!  This way
+				 * they are spread between 0 and 255.
+				 */
+				if (Bpp == 4) {
+					/* unroll the loops, can give 20% */
+					pixave[0] += w * ((unsigned char) *(src  ));
+					pixave[1] += w * ((unsigned char) *(src+1));
+					pixave[2] += w * ((unsigned char) *(src+2));
+					pixave[3] += w * ((unsigned char) *(src+3));
+				} else if (Bpp == 2) {
+					/*
+					 * 16bpp: trickier with green
+					 * split over two bytes, so we
+					 * use the masks:
+					 */
+					us = *((unsigned short *) src);
+					pixave[0] += w*(us & main_red_mask);
+					pixave[1] += w*(us & main_green_mask);
+					pixave[2] += w*(us & main_blue_mask);
+				} else if (Bpp == 1) {
+					pixave[0] += w *
+					    ((unsigned char) *(src));
+				} else {
+					for (b=0; b<Bpp; b++) {
+						pixave[b] += w *
+						    ((unsigned char) *(src+b));
+					}
+				}
+				src += Bpp;
+			    }
+			}
+
+			if (wtot <= 0.0) {
+				wtot = 1.0;
+			}
+			wtot = 1.0/wtot;	/* normalization factor */
+
+			/* place weighted average pixel in the scaled fb: */
+			if (Bpp == 4) {
+				*(dest  ) = (char) (wtot * pixave[0]);
+				*(dest+1) = (char) (wtot * pixave[1]);
+				*(dest+2) = (char) (wtot * pixave[2]);
+				*(dest+3) = (char) (wtot * pixave[3]);
+			} else if (Bpp == 2) {
+				/* 16bpp / 565 case: */
+				pixave[0] *= wtot;
+				pixave[1] *= wtot;
+				pixave[2] *= wtot;
+				us =  (main_red_mask   & (int) pixave[0])
+				    | (main_green_mask & (int) pixave[1])
+				    | (main_blue_mask  & (int) pixave[2]);
+				*( (unsigned short *) dest ) = us;
+			} else if (Bpp == 1) {
+				*(dest) = (char) (wtot * pixave[0]);
+			} else {
+				for (b=0; b<Bpp; b++) {
+					*(dest+b) = (char) (wtot * pixave[b]);
+				}
+			}
+			dest += Bpp;
+		}
+	}
+	markit:
+/* End taken from x11vnc scale: */
+	if (0) {}
+}
+
+void do_scale_stats(int width, int height) {
+	static double calls = 0.0, sum = 0.0, var = 0.0, last = 0.0;
+	double A = width * height;
+
+	if (last == 0.0) {
+		last = dnow();
+	}
+
+	calls += 1.0;
+	sum += A;
+	var += A*A;
+
+	if (dnow() > last + 4.0) {
+		double cnt = calls;
+		if (cnt <= 0.0) cnt = 1.0;
+		var /= cnt;
+		sum /= cnt;
+		var = var - sum * sum;
+		if (sum > 0.0) {
+			var = var / (sum*sum);
+		}
+		fprintf(stderr, "scale_rect stats: %10d %10.1f ave: %10.3f var-rat: %10.3f\n", (int) calls, sum * cnt, sum, var); 
+
+		calls = 0.0;
+		sum = 0.0;
+		var = 0.0;
+		last = dnow();
+	}
+}
+
+void put_image(int src_x, int src_y, int dst_x, int dst_y, int width,
+    int height, int solid) {
+	int db = 0;
+	int xmax = si.framebufferWidth;
+	int ymax = si.framebufferHeight;
+
+if (db || 0) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height);
+
+	if (image_scale) {
+		int i;
+		static int scale_stats = -1;
+
+		for (i=0; i < 2; i++) {
+			if (src_x > 0) src_x--;
+			if (src_y > 0) src_y--;
+		}
+		for (i=0; i < 4; i++) {
+			if (src_x + width  < xmax) width++;
+			if (src_y + height < ymax) height++;
+		}
+
+		if (db) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height);
+		if (db) fprintf(stderr, "scale_rect(%d %d %d %d)\n", src_x, src_y, width, height);
+
+		if (scale_stats < 0) {
+			if (getenv("SSVNC_SCALE_STATS")) {
+				scale_stats = 1;
+			} else {
+				scale_stats = 0;
+			}
+		}
+		if (scale_stats) {
+			do_scale_stats(width, height);
+		}
+
+		scale_rect(scale_factor_x, scale_factor_y, 1, 0, &src_x, &src_y, &width, &height, solid);
+		dst_x = src_x;
+		dst_y = src_y;
+	}
+	
+#ifdef MITSHM
+	if (appData.useShm) {
+		double fac = image_scale ? scale_factor_y : 1.0;
+		if (image_ycrop == NULL) {
+			if (image_is_shm) {
+				XShmPutImage(dpy, desktopWin, gc, image, src_x, src_y,
+				    dst_x, dst_y, width, height, False);
+			} else {
+				XPutImage(dpy, desktopWin, gc, image, src_x, src_y,
+				    dst_x, dst_y, width, height);
+			}
+		} else if ((width < 32 && height < 32) || height > appData.yCrop * fac) {
+			XPutImage(dpy, desktopWin, gc, image, src_x, src_y,
+			    dst_x, dst_y, width, height);
+		} else {
+			char *src, *dst;
+			int Bpp = image->bits_per_pixel / 8;
+			int Bpl  = image->bytes_per_line, h;
+			int Bpl2 = image_ycrop->bytes_per_line;
+			src = image->data + src_y * Bpl + src_x * Bpp;
+			dst = image_ycrop->data;
+			for (h = 0; h < height; h++) {
+				memcpy(dst, src, width * Bpp);
+				src += Bpl;
+				dst += Bpl2;
+			}
+			XShmPutImage(dpy, desktopWin, gc, image_ycrop, 0, 0,
+			    dst_x, dst_y, width, height, False);
+		}
+	} else
+#endif
+	{
+		XPutImage(dpy, desktopWin, gc, image, src_x, src_y,
+		   dst_x, dst_y, width, height);
+	}
+}
+
+#if 0
+fprintf(stderr, "non-shmB image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height);
+fprintf(stderr, "shm image_ycrop %d %d %d %d %d %d\n", 0, 0, dst_x, dst_y, width, height);
+fprintf(stderr, "non-shmA image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height);
+#endif
+
+void releaseAllPressedModifiers(void) {
+	int i;
+	static int debug_release = -1;
+	if (debug_release < 0) {
+		if (getenv("SSVNC_DEBUG_RELEASE")) {
+			debug_release = 1;
+		} else {
+			debug_release = 0;
+		}
+	}
+	if (debug_release) fprintf(stderr, "into releaseAllPressedModifiers()\n");
+	for (i = 0; i < 256; i++) {
+		if (modifierPressed[i]) {
+			SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False);
+			modifierPressed[i] = False;
+			if (debug_release) fprintf(stderr, "releasing[%d] %s\n", i, XKeysymToString(XKeycodeToKeysym(dpy, i, 0)));
+		}
+	}
+}
+
+#define PR_EXPOSE fprintf(stderr, "Expose: %04dx%04d+%04d+%04d %04d/%04d/%04d now: %8.4f rescale: %8.4f fullscreen: %8.4f\n", width, height, x, y, si.framebufferWidth, appData.yCrop, si.framebufferHeight, now - start_time, now - last_rescale, now - last_fullscreen);
 
 /*
  * HandleBasicDesktopEvent - deal with expose and leave events.
@@ -152,42 +1553,529 @@
 static void
 HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont)
 {
-  int i;
+	int x, y, width, height;
+	double now = dnow();
 
-  switch (ev->type) {
+	if (w || ptr || cont) {}
+
+	if (0) {
+		PR_EXPOSE;
+	}
 
+
+  switch (ev->type) {
   case Expose:
   case GraphicsExpose:
     /* sometimes due to scrollbars being added/removed we get an expose outside
        the actual desktop area.  Make sure we don't pass it on to the RFB
        server. */
+	x = ev->xexpose.x;
+	y = ev->xexpose.y;
+	width  = ev->xexpose.width;
+	height = ev->xexpose.height;
+
+	if (image_scale) {
+		int i;
+		x /= scale_factor_x;
+		y /= scale_factor_y;
+		width  /= scale_factor_x;
+		height /= scale_factor_y;
+		/* make them a little wider to avoid painting errors */
+		for (i=0; i < 3; i++) {
+			if (x > 0) x--;
+			if (y > 0) y--;
+		}
+		for (i=0; i < 6; i++) {
+			if (x + width  < si.framebufferWidth)   width++;
+			if (y + height < si.framebufferHeight)  height++;
+		}
+	}
 
-    if (ev->xexpose.x + ev->xexpose.width > si.framebufferWidth) {
-      ev->xexpose.width = si.framebufferWidth - ev->xexpose.x;
-      if (ev->xexpose.width <= 0) break;
-    }
-
-    if (ev->xexpose.y + ev->xexpose.height > si.framebufferHeight) {
-      ev->xexpose.height = si.framebufferHeight - ev->xexpose.y;
-      if (ev->xexpose.height <= 0) break;
-    }
-
-    SendFramebufferUpdateRequest(ev->xexpose.x, ev->xexpose.y,
-				 ev->xexpose.width, ev->xexpose.height, False);
-    break;
+	if (x + width > si.framebufferWidth) {
+		width = si.framebufferWidth - x;
+		if (width <= 0) {
+			break;
+		}
+	}
+
+	if (y + height > si.framebufferHeight) {
+		height = si.framebufferHeight - y;
+		if (height <= 0) {
+			break;
+		}
+	}
+
+	if (appData.useXserverBackingStore) {
+		SendFramebufferUpdateRequest(x, y, width, height, False);
+	} else {
+		int ok = 1;
+		double delay = 2.5;
+		if (appData.fullScreen && now < last_fullscreen + delay) {
+			int xmax = si.framebufferWidth;
+			int ymax = si.framebufferHeight;
+			if (appData.yCrop > 0) {
+				ymax = appData.yCrop;
+			}
+			xmax = scale_round(xmax, scale_factor_x);
+			ymax = scale_round(ymax, scale_factor_y);
+			if (dpyWidth < xmax) {
+				xmax = dpyWidth;
+			}
+			if (dpyHeight < ymax) {
+				ymax = dpyHeight;
+			}
+			if (x != 0 && y != 0) {
+				ok = 0;
+			}
+			if (width < 0.9 * xmax) {
+				ok = 0;
+			}
+			if (height < 0.9 * ymax) {
+				ok = 0;
+			}
+		}
+		if (appData.yCrop > 0) {
+			if (now < last_fullscreen + delay || now < last_rescale + delay) {
+				if (y + height > appData.yCrop) {
+					height = appData.yCrop - y;
+				}
+			}
+		}
+		if (ok) {
+			put_image(x, y, x, y, width, height, 0);
+			XSync(dpy, False);
+		} else {
+			fprintf(stderr, "Skip ");
+			PR_EXPOSE;
+		}
+	}
+	break;
 
   case LeaveNotify:
-    for (i = 0; i < 256; i++) {
-      if (modifierPressed[i]) {
-	SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False);
-	modifierPressed[i] = False;
-      }
-    }
-    break;
+	releaseAllPressedModifiers();
+	if (appData.fullScreen) {
+		fs_ungrab(1);
+	}
+	break;
+  case EnterNotify:
+	if (appData.fullScreen) {
+		fs_grab(1);
+	}
+	break;
+  case ClientMessage:
+	if (ev->xclient.window == XtWindow(desktop) && ev->xclient.message_type == XA_INTEGER &&
+	    ev->xclient.format == 8 && !strcmp(ev->xclient.data.b, "SendRFBUpdate")) {
+		SendIncrementalFramebufferUpdateRequest();
+	}
+	break;
   }
+	check_things();
+}
+
+extern Position desktopX, desktopY;
+
+void x11vnc_appshare(char *cmd) {
+	char send[200], str[100];
+	char *id = "cmd=id_cmd";
+	int m_big = 80, m_fine = 15;
+	int resize = 100, db = 0;
+
+	if (getenv("X11VNC_APPSHARE_DEBUG")) {
+		db = atoi(getenv("X11VNC_APPSHARE_DEBUG"));
+	}
+
+	if (db) fprintf(stderr, "x11vnc_appshare: cmd=%s\n", cmd);
+
+	str[0] = '\0';
+
+	if (!strcmp(cmd, "left")) {
+		sprintf(str, "%s:move:-%d+0", id, m_big);
+	} else if (!strcmp(cmd, "right")) {
+		sprintf(str, "%s:move:+%d+0", id, m_big);
+	} else if (!strcmp(cmd, "up")) {
+		sprintf(str, "%s:move:+0-%d", id, m_big);
+	} else if (!strcmp(cmd, "down")) {
+		sprintf(str, "%s:move:+0+%d", id, m_big);
+	} else if (!strcmp(cmd, "left-fine")) {
+		sprintf(str, "%s:move:-%d+0", id, m_fine);
+	} else if (!strcmp(cmd, "right-fine")) {
+		sprintf(str, "%s:move:+%d+0", id, m_fine);
+	} else if (!strcmp(cmd, "up-fine")) {
+		sprintf(str, "%s:move:+0-%d", id, m_fine);
+	} else if (!strcmp(cmd, "down-fine")) {
+		sprintf(str, "%s:move:+0+%d", id, m_fine);
+	} else if (!strcmp(cmd, "taller")) {
+		sprintf(str, "%s:resize:+0+%d", id, resize);
+	} else if (!strcmp(cmd, "shorter")) {
+		sprintf(str, "%s:resize:+0-%d", id, resize);
+	} else if (!strcmp(cmd, "wider")) {
+		sprintf(str, "%s:resize:+%d+0", id, resize);
+	} else if (!strcmp(cmd, "narrower")) {
+		sprintf(str, "%s:resize:-%d+0", id, resize);
+	} else if (!strcmp(cmd, "lower")) {
+		sprintf(str, "%s:lower", id);
+	} else if (!strcmp(cmd, "raise")) {
+		sprintf(str, "%s:raise", id);
+	} else if (!strcmp(cmd, "delete")) {
+		sprintf(str, "%s:wm_delete", id);
+	} else if (!strcmp(cmd, "position")) {
+		Position x, y;
+		int xi, yi;
+
+		XtVaGetValues(toplevel, XtNx, &x, XtNy, &y, NULL);
+		xi = (int) x;
+		yi = (int) y;
+		if (appData.scale) {
+			double fx = 1.0, fy = 1.0;
+			get_scale_values(&fx, &fy);
+			if (fx > 0.0 && fy > 0.0) {
+				xi /= fx;
+				yi /= fx;
+			}
+		}
+		sprintf(str, "%s:geom:0x0+%d+%d", id, xi, yi);
+		fprintf(stderr, "str=%s\n", str);
+	}
+	if (strcmp(str, "")) {
+		Bool vo = appData.viewOnly;
+		strcpy(send, "X11VNC_APPSHARE_CMD:");
+		strcat(send, str);
+		if (db) fprintf(stderr, "x11vnc_appshare: send=%s\n", send);
+		if (vo) appData.viewOnly = False;
+		SendClientCutText(send, strlen(send));
+		if (vo) appData.viewOnly = True;
+	}
+}
+
+void scroll_desktop(int horiz, int vert, double amount) {
+	Dimension h, w;
+	Position x, y;
+	Position x2, y2;
+	static int db = -1;
+
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+
+	XtVaGetValues(form, XtNheight, &h, XtNwidth, &w, NULL);
+	XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL);
+
+	x2 = -x;
+	y2 = -y;
+
+	if (amount == -1.0) {
+		int dx = horiz;
+		int dy = vert;
+		if (dx == 0 && dy == 0) {
+			return;
+		}
+		x2 -= dx;
+		y2 -= dy;
+	} else {
+		if (horiz) {
+			int dx = (int) (amount * w);
+			if (dx < 0) dx = -dx;
+			if (amount == 0.0) dx = 1;
+			if (horiz > 0) {
+				x2 += dx;
+			} else {
+				x2 -= dx;
+			}
+			if (x2 < 0) x2 = 0;
+		}
+		if (vert) {
+			int dy = (int) (amount * h);
+			if (amount == 0.0) dy = 1;
+			if (dy < 0) dy = -dy;
+			if (vert < 0) {
+				y2 += dy;
+			} else {
+				y2 -= dy;
+			}
+			if (y2 < 0) y2 = 0;
+		}
+	}
+
+	if (db) fprintf(stderr, "%d %d %f viewport(%dx%d): %d %d -> %d %d\n", horiz, vert, amount, w, h, -x, -y, x2, y2); 
+	XawViewportSetCoordinates(viewport, x2, y2);
+
+	if (appData.fullScreen) {
+		XSync(dpy, False);
+		XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL);
+		desktopX = -x;
+		desktopY = -y;
+	} else if (amount == -1.0) {
+		XSync(dpy, False);
+	}
 }
 
+void scale_desktop(int bigger, double frac) {
+	double current, new;
+	char tmp[100];
+	char *s;
+	int fs;
+
+	if (appData.scale == NULL) {
+		s = "1.0";
+	} else {
+		s = appData.scale;
+	}
+	if (!strcmp(s, "auto")) {
+		fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s);
+		return;
+	} else if (!strcmp(s, "fit")) {
+		fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s);
+		return;
+	} else if (strstr(s, "x")) {
+		fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s);
+		return;
+	} else if (!strcmp(s, "none")) {
+		s = "1.0";
+	}
+
+	if (sscanf(s, "%lf", &current) != 1) {
+		fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s);
+		return;
+	}
+	if (bigger) {
+		new = current * (1.0 + frac);
+	} else {
+		new = current / (1.0 + frac);
+	}
+	if (0.99 < new && new < 1.01) {
+		new = 1.0;
+	}
 
+	if (new > 5.0) {
+		fprintf(stderr, "scale_desktop: not scaling > 5.0: %f\n", new);
+		return;
+	} else if (new < 0.05) {
+		fprintf(stderr, "scale_desktop: not scaling < 0.05: %f\n", new);
+		return;
+	}
+	sprintf(tmp, "%.16f", new);
+	appData.scale = strdup(tmp);
+
+	fs = 0;
+	if (appData.fullScreen) {
+		fs = 1;
+		FullScreenOff();
+	}
+	if (1) {
+		double fx, fy;
+		get_scale_values(&fx, &fy);
+		if (fx > 0.0 && fy > 0.0) {
+			rescale_image();
+		}
+	}
+	if (fs) {
+		FullScreenOn();
+	}
+}
+
+static int escape_mods[8];
+static int escape_drag_in_progress = 0, last_x = 0, last_y = 0;
+static double last_drag = 0.0;
+static double last_key  = 0.0;
+
+static int escape_sequence_pressed(void) {
+	static char *prev = NULL;
+	char *str = "default";
+	int sum, i, init = 0, pressed;
+	static int db = -1;
+
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+
+	if (appData.escapeKeys != NULL) {
+		str = appData.escapeKeys;
+	}
+	if (prev == NULL) {
+		init = 1;
+		prev = strdup(str);
+	} else {
+		if (strcmp(prev, str)) 	{
+			init = 1;
+			free(prev);
+			prev = strdup(str);
+		}
+	}
+	if (db) fprintf(stderr, "str: %s\n", str);
+
+	if (init) {
+		char *p, *s;
+		KeySym ks;
+		int k = 0, failed = 0;
+
+		for (i = 0; i < 8; i++) {
+			escape_mods[i] = -1;
+		}
+
+		if (!strcasecmp(str, "default")) {
+#if (defined(__MACH__) && defined(__APPLE__))
+			s = strdup("Control_L,Meta_L");
+#else
+			s = strdup("Alt_L,Super_L");
+#endif
+		} else {
+			s = strdup(str);
+		}
+		
+		p = strtok(s, ",+ ");
+		while (p) {
+			ks = XStringToKeysym(p);
+			if (ks == XK_Shift_L || ks == XK_Shift_R) {
+				putenv("NO_X11VNC_APPSHARE=1");
+			}
+			if (k >= 8) {
+				fprintf(stderr, "EscapeKeys: more than 8 modifier keys.\n");
+				failed = 1;
+				break;
+			}
+			if (ks == NoSymbol) {
+				fprintf(stderr, "EscapeKeys: failed lookup for '%s'\n", p);
+				failed = 1;
+				break;
+			} else if (!IsModifierKey(ks)) {
+				fprintf(stderr, "EscapeKeys: not a modifier key '%s'\n", p);
+				failed = 1;
+				break;
+			} else {
+				KeyCode kc = XKeysymToKeycode(dpy, ks);
+				if (kc == NoSymbol) {
+					fprintf(stderr, "EscapeKeys: no keycode for modifier key '%s'\n", p);
+					failed = 1;
+					break;
+				}
+				if (db) fprintf(stderr, "set: %d %d\n", k, kc);
+				escape_mods[k++] = kc; 
+			}
+			
+			p = strtok(NULL, ",+ ");
+		}
+		free(s);
+
+		if (failed) {
+			for (i = 0; i < 8; i++) {
+				escape_mods[i] = -1;
+			}
+		}
+	}
+
+	pressed = 1;
+	sum = 0;
+	for (i = 0; i < 8; i++) {
+		int kc = escape_mods[i];
+		if (kc != -1 && kc < 256) {
+			if (db) fprintf(stderr, "try1: %d %d = %d\n", i, kc, modifierPressed[kc]);
+			if (!modifierPressed[kc]) {
+				pressed = 0;
+				break;
+			} else {
+				sum++;
+			}
+		}
+	}
+	if (sum == 0) pressed = 0;
+
+	if (!pressed) {
+		/* user may have dragged mouse outside of toplevel window */
+		int i, k;
+		int keystate[256];
+		char keys[32];
+
+		/* so query server instead of modifierPressed[] */
+		XQueryKeymap(dpy, keys);
+		for (i=0; i<32; i++) {
+			char c = keys[i];
+
+			for (k=0; k < 8; k++) {
+				if (c & 0x1) {
+					keystate[8*i + k] = 1;
+				} else {
+					keystate[8*i + k] = 0;
+				}
+				c = c >> 1;
+			}
+		}
+
+		/* check again using keystate[] */
+		pressed = 2;
+		sum = 0;
+		for (i = 0; i < 8; i++) {
+			int kc = escape_mods[i];
+			if (kc != -1 && kc < 256) {
+				if (db) fprintf(stderr, "try2: %d %d = %d\n", i, kc, keystate[kc]);
+				if (!keystate[kc]) {
+					pressed = 0;
+					break;
+				} else {
+					sum++;
+				}
+			}
+		}
+		if (sum == 0) pressed = 0;
+	}
+
+	return pressed;
+}
+
+static int shift_is_down(void) {
+	int shift_down = 0;
+	KeyCode kc;
+
+	if (appData.viewOnly) {
+		int i, k;
+		char keys[32];
+		int keystate[256];
+
+		XQueryKeymap(dpy, keys);
+		for (i=0; i<32; i++) {
+			char c = keys[i];
+
+			for (k=0; k < 8; k++) {
+				if (c & 0x1) {
+					keystate[8*i + k] = 1;
+				} else {
+					keystate[8*i + k] = 0;
+				}
+				c = c >> 1;
+			}
+		}
+
+		kc = XKeysymToKeycode(dpy, XK_Shift_L);
+		if (kc != NoSymbol && keystate[kc]) {
+			shift_down = 1;
+		} else {
+			kc = XKeysymToKeycode(dpy, XK_Shift_R);
+			if (kc != NoSymbol && keystate[kc]) {
+				shift_down = 1;
+			}
+		}
+		return shift_down;
+	} else {
+		kc = XKeysymToKeycode(dpy, XK_Shift_L);
+		if (kc != NoSymbol && modifierPressed[kc]) {
+			shift_down = 1;
+		} else {
+			kc = XKeysymToKeycode(dpy, XK_Shift_R);
+			if (kc != NoSymbol && modifierPressed[kc]) {
+				shift_down = 1;
+			}
+		}
+		return shift_down;
+	}
+}
+			
 /*
  * SendRFBEvent is an action which sends an RFB event.  It can be used in two
  * ways.  Without any parameters it simply sends an RFB event corresponding to
@@ -201,127 +2089,406 @@
  * button2 down, 3 for both, etc).
  */
 
+extern Bool selectingSingleWindow;
+
+extern Cursor dotCursor3;
+extern Cursor dotCursor4;
+
+extern void set_server_scale(int);
+
 void
 SendRFBEvent(Widget w, XEvent *ev, String *params, Cardinal *num_params)
 {
-  KeySym ks;
-  char keyname[256];
-  int buttonMask, x, y;
-
-  if (appData.fullScreen && ev->type == MotionNotify) {
-    if (BumpScroll(ev))
-      return;
-  }
+	KeySym ks;
+	char keyname[256];
+	int buttonMask, x, y;
+	int do_escape;
+	static int db = -1;
+	char *ek = appData.escapeKeys;
+
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+
+	if (ev->type == MotionNotify || ev->type == KeyRelease) {
+		static double last = 0.0;
+		double now = dnow();
+		if (now > last + 0.25) {
+			check_things();
+			last = now;
+		}
+	}
+
+	if (selectingSingleWindow && ev->type == ButtonPress) {
+		selectingSingleWindow = False;
+		SendSingleWindow(ev->xbutton.x, ev->xbutton.y);
+		if (appData.viewOnly) {
+			XDefineCursor(dpy, desktopWin, dotCursor4);
+		} else {
+			XDefineCursor(dpy, desktopWin, dotCursor3);
+		}
+		return;
+	}
 
-  if (appData.viewOnly) return;
+	if (appData.fullScreen && ev->type == MotionNotify && !escape_drag_in_progress) {
+		if (BumpScroll(ev)) {
+			return;
+		}
+	}
+
+	do_escape = 0;
+	if (ek != NULL && (ek[0] == 'n' || ek[0] == 'N') && !strcasecmp(ek, "never")) {
+		;
+	} else if (appData.viewOnly) {
+		do_escape = 1;
+	} else if (appData.escapeActive) {
+		int skip = 0, is_key = 0;
+
+		if (ev->type == KeyPress || ev->type == KeyRelease) {
+			is_key = 1;
+			XLookupString(&ev->xkey, keyname, 256, &ks, NULL);
+			if (IsModifierKey(ks)) {
+				skip = 1;
+			}
+		}
+		if (!skip) {
+			int es = escape_sequence_pressed();
+			if (es == 1) {
+				do_escape = 1;
+			} else if (es == 2) {
+				if (is_key) {
+					if (dnow() < last_key + 5.0) {
+						do_escape = 1;
+					}
+				} else {
+					if (dnow() < last_drag + 5.0) {
+						do_escape = 1;
+					}
+				}
+			}
+		}
+	}
+	if (!do_escape) {
+		escape_drag_in_progress = 0;
+	}
+	if (db) fprintf(stderr, "do_escape: %d\n", do_escape);
+
+	if (do_escape) {
+		int W = si.framebufferWidth;
+		int H = si.framebufferHeight;
+		int shift_down = 0;
+
+		if (!getenv("NO_X11VNC_APPSHARE")) {
+			shift_down = shift_is_down();
+		}
+		if (db) fprintf(stderr, "shift_down: %d\n", shift_down);
+
+		if (*num_params != 0) {
+			if (strcasecmp(params[0],"fbupdate") == 0) {
+				SendFramebufferUpdateRequest(0, 0, W, H, False);
+			}
+		}
+		if (ev->type == ButtonRelease) {
+			XButtonEvent *b = (XButtonEvent *) ev;
+			if (db) fprintf(stderr, "ButtonRelease: %d %d %d\n", b->x_root, b->y_root, b->state); 
+			if (b->button == 3) {
+				if (shift_down) {
+					x11vnc_appshare("delete");
+				} else {
+					ShowPopup(w, ev, params, num_params);
+				}
+			} else if (escape_drag_in_progress && b->button == 1) {
+				escape_drag_in_progress = 0;
+			}
+		} else if (ev->type == ButtonPress) {
+			XButtonEvent *b = (XButtonEvent *) ev;
+			if (db) fprintf(stderr, "ButtonPress:   %d %d %d\n", b->x_root, b->y_root, b->state); 
+			if (b->button == 1) {
+				if (shift_down) {
+					x11vnc_appshare("position");
+				} else {
+					escape_drag_in_progress = 1;
+					last_x = b->x_root;
+					last_y = b->y_root;
+				}
+			} else {
+				escape_drag_in_progress = 0;
+			}
+		} else if (ev->type == MotionNotify) {
+			XMotionEvent *m = (XMotionEvent *) ev;
+			if (escape_drag_in_progress) {
+				if (db) fprintf(stderr, "MotionNotify:   %d %d %d\n", m->x_root, m->y_root, m->state); 
+				scroll_desktop(m->x_root - last_x, m->y_root - last_y, -1.0);
+				last_x = m->x_root;
+				last_y = m->y_root;
+			}
+		} else if (ev->type == KeyRelease) {
+			int did = 1;
+
+			XLookupString(&ev->xkey, keyname, 256, &ks, NULL);
+			if (ks == XK_1 || ks == XK_KP_1) {
+				set_server_scale(1);
+			} else if (ks == XK_2 || ks == XK_KP_2) {
+				set_server_scale(2);
+			} else if (ks == XK_3 || ks == XK_KP_3) {
+				set_server_scale(3);
+			} else if (ks == XK_4 || ks == XK_KP_4) {
+				set_server_scale(4);
+			} else if (ks == XK_5 || ks == XK_KP_5) {
+				set_server_scale(5);
+			} else if (ks == XK_6 || ks == XK_KP_6) {
+				set_server_scale(6);
+			} else if (ks == XK_r || ks == XK_R) {
+				SendFramebufferUpdateRequest(0, 0, W, H, False);
+			} else if (ks == XK_b || ks == XK_B) {
+				ToggleBell(w, ev, params, num_params);
+			} else if (ks == XK_c || ks == XK_C) {
+				Toggle8bpp(w, ev, params, num_params);
+			} else if (ks == XK_x || ks == XK_X) {
+				ToggleX11Cursor(w, ev, params, num_params);
+			} else if (ks == XK_z || ks == XK_Z) {
+				ToggleTightZRLE(w, ev, params, num_params);
+			} else if (ks == XK_h || ks == XK_H) {
+				ToggleTightHextile(w, ev, params, num_params);
+			} else if (ks == XK_f || ks == XK_F) {
+				ToggleFileXfer(w, ev, params, num_params);
+			} else if (ks == XK_V) {
+				ToggleViewOnly(w, ev, params, num_params);
+			} else if (ks == XK_Q) {
+				Quit(w, ev, params, num_params);
+			} else if (ks == XK_l || ks == XK_L) {
+				ToggleFullScreen(w, ev, params, num_params);
+			} else if (ks == XK_a || ks == XK_A) {
+				ToggleCursorAlpha(w, ev, params, num_params);
+			} else if (ks == XK_s || ks == XK_S) {
+				SetScale(w, ev, params, num_params);
+			} else if (ks == XK_t || ks == XK_T) {
+				ToggleTextChat(w, ev, params, num_params);
+			} else if (ks == XK_e || ks == XK_E) {
+				SetEscapeKeys(w, ev, params, num_params);
+			} else if (ks == XK_g || ks == XK_G) {
+				ToggleXGrab(w, ev, params, num_params);
+			} else if (ks == XK_D) {
+				if (shift_down || appData.appShare) {
+					x11vnc_appshare("delete");
+				}
+			} else if (ks == XK_M) {
+				if (shift_down || appData.appShare) {
+					x11vnc_appshare("position");
+				}
+			} else if (ks == XK_Left) {
+				if (shift_down) {
+					x11vnc_appshare("left");
+				} else {
+					scroll_desktop(-1, 0, 0.1);
+				}
+			} else if (ks == XK_Right) {
+				if (shift_down) {
+					x11vnc_appshare("right");
+				} else {
+					scroll_desktop(+1, 0, 0.1);
+				}
+			} else if (ks == XK_Up) {
+				if (shift_down) {
+					x11vnc_appshare("up");
+				} else {
+					scroll_desktop(0, +1, 0.1);
+				}
+			} else if (ks == XK_Down) {
+				if (shift_down) {
+					x11vnc_appshare("down");
+				} else {
+					scroll_desktop(0, -1, 0.1);
+				}
+			} else if (ks == XK_KP_Left) {
+				if (shift_down) {
+					x11vnc_appshare("left-fine");
+				} else {
+					scroll_desktop(-1, 0, 0.0);
+				}
+			} else if (ks == XK_KP_Right) {
+				if (shift_down) {
+					x11vnc_appshare("right-fine");
+				} else {
+					scroll_desktop(+1, 0, 0.0);
+				}
+			} else if (ks == XK_KP_Up) {
+				if (shift_down) {
+					x11vnc_appshare("up-fine");
+				} else {
+					scroll_desktop(0, +1, 0.0);
+				}
+			} else if (ks == XK_KP_Down) {
+				if (shift_down) {
+					x11vnc_appshare("down-fine");
+				} else {
+					scroll_desktop(0, -1, 0.0);
+				}
+			} else if (ks == XK_Next || ks == XK_KP_Next) {
+				if (shift_down && ks == XK_Next) {
+					x11vnc_appshare("shorter");
+				} else {
+					scroll_desktop(0, -1, 1.0);
+				}
+			} else if (ks == XK_Prior || ks == XK_KP_Prior) {
+				if (shift_down && ks == XK_Prior) {
+					x11vnc_appshare("taller");
+				} else {
+					scroll_desktop(0, +1, 1.0);
+				}
+			} else if (ks == XK_End || ks == XK_KP_End) {
+				if (shift_down && ks == XK_End) {
+					x11vnc_appshare("narrower");
+				} else {
+					scroll_desktop(+1, 0, 1.0);
+				}
+			} else if (ks == XK_Home || ks == XK_KP_Home) {
+				if (shift_down && ks == XK_Home) {
+					x11vnc_appshare("wider");
+				} else {
+					scroll_desktop(-1, 0, 1.0);
+				}
+			} else if (ks == XK_equal || ks == XK_plus) {
+				if (shift_down) {
+					x11vnc_appshare("raise");
+				} else {
+					scale_desktop(1, 0.1);
+				}
+			} else if (ks == XK_underscore || ks == XK_minus) {
+				if (shift_down) {
+					x11vnc_appshare("lower");
+				} else {
+					scale_desktop(0, 0.1);
+				}
+			} else {
+				did = 0;
+			}
+			if (did) {
+				last_key = dnow();
+			}
+		}
+		if (escape_drag_in_progress) {
+			last_drag = dnow();
+		}
+		return;
+	}
+	if (appData.viewOnly) {
+		return;
+	}
+
+	if (*num_params != 0) {
+		if (strncasecmp(params[0],"key",3) == 0) {
+			if (*num_params != 2) {
+				fprintf(stderr, "Invalid params: "
+				    "SendRFBEvent(key|keydown|keyup,<keysym>)\n");
+				return;
+			}
+			ks = XStringToKeysym(params[1]);
+			if (ks == NoSymbol) {
+				fprintf(stderr,"Invalid keysym '%s' passed to "
+				    "SendRFBEvent\n", params[1]);
+				return;
+			}
+			if (strcasecmp(params[0],"keydown") == 0) {
+				SendKeyEvent(ks, 1);
+			} else if (strcasecmp(params[0],"keyup") == 0) {
+				SendKeyEvent(ks, 0);
+			} else if (strcasecmp(params[0],"key") == 0) {
+				SendKeyEvent(ks, 1);
+				SendKeyEvent(ks, 0);
+			} else {
+				fprintf(stderr,"Invalid event '%s' passed to "
+				    "SendRFBEvent\n", params[0]);
+				return;
+			}
+		} else if (strcasecmp(params[0],"fbupdate") == 0) {
+			if (*num_params != 1) {
+				fprintf(stderr, "Invalid params: "
+				    "SendRFBEvent(fbupdate)\n");
+				return;
+			}
+			SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+			    si.framebufferHeight, False);
+
+		} else if (strcasecmp(params[0],"ptr") == 0) {
+			if (*num_params == 4) {
+				x = atoi(params[1]);
+				y = atoi(params[2]);
+				buttonMask = atoi(params[3]);
+				SendPointerEvent(x, y, buttonMask);
+			} else if (*num_params == 2) {
+				switch (ev->type) {
+				case ButtonPress:
+				case ButtonRelease:
+					x = ev->xbutton.x;
+					y = ev->xbutton.y;
+					break;
+				case KeyPress:
+				case KeyRelease:
+					x = ev->xkey.x;
+					y = ev->xkey.y;
+					break;
+				default:
+					fprintf(stderr, "Invalid event caused "
+					    "SendRFBEvent(ptr,<buttonMask>)\n");
+					return;
+				}
+				buttonMask = atoi(params[1]);
+				SendPointerEvent(x, y, buttonMask);
+			} else {
+				fprintf(stderr, "Invalid params: "
+				    "SendRFBEvent(ptr,<x>,<y>,<buttonMask>)\n"
+				    "             or SendRFBEvent(ptr,<buttonMask>)\n");
+				return;
+			}
+		} else {
+			fprintf(stderr,"Invalid event '%s' passed to "
+			    "SendRFBEvent\n", params[0]);
+		}
+		return;
+	}
 
-  if (*num_params != 0) {
-    if (strncasecmp(params[0],"key",3) == 0) {
-      if (*num_params != 2) {
-	fprintf(stderr,
-		"Invalid params: SendRFBEvent(key|keydown|keyup,<keysym>)\n");
-	return;
-      }
-      ks = XStringToKeysym(params[1]);
-      if (ks == NoSymbol) {
-	fprintf(stderr,"Invalid keysym '%s' passed to SendRFBEvent\n",
-		params[1]);
-	return;
-      }
-      if (strcasecmp(params[0],"keydown") == 0) {
-	SendKeyEvent(ks, 1);
-      } else if (strcasecmp(params[0],"keyup") == 0) {
-	SendKeyEvent(ks, 0);
-      } else if (strcasecmp(params[0],"key") == 0) {
-	SendKeyEvent(ks, 1);
-	SendKeyEvent(ks, 0);
-      } else {
-	fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n",
-		params[0]);
-	return;
-      }
-    } else if (strcasecmp(params[0],"fbupdate") == 0) {
-      if (*num_params != 1) {
-	fprintf(stderr, "Invalid params: SendRFBEvent(fbupdate)\n");
-	return;
-      }
-      SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
-				   si.framebufferHeight, False);
-    } else if (strcasecmp(params[0],"ptr") == 0) {
-      if (*num_params == 4) {
-	x = atoi(params[1]);
-	y = atoi(params[2]);
-	buttonMask = atoi(params[3]);
-	SendPointerEvent(x, y, buttonMask);
-      } else if (*num_params == 2) {
 	switch (ev->type) {
+	case MotionNotify:
+		while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev)) {
+			;	/* discard all queued motion notify events */
+		}
+
+		SendPointerEvent(ev->xmotion.x, ev->xmotion.y,
+			     (ev->xmotion.state & 0x1f00) >> 8);
+		return;
+
 	case ButtonPress:
+		SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
+			     (((ev->xbutton.state & 0x1f00) >> 8) |
+			      (1 << (ev->xbutton.button - 1))));
+		return;
+
 	case ButtonRelease:
-	  x = ev->xbutton.x;
-	  y = ev->xbutton.y;
-	  break;
+		SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
+			     (((ev->xbutton.state & 0x1f00) >> 8) &
+			      ~(1 << (ev->xbutton.button - 1))));
+		return;
+
 	case KeyPress:
 	case KeyRelease:
-	  x = ev->xkey.x;
-	  y = ev->xkey.y;
-	  break;
-	default:
-	  fprintf(stderr,
-		  "Invalid event caused SendRFBEvent(ptr,<buttonMask>)\n");
-	  return;
-	}
-	buttonMask = atoi(params[1]);
-	SendPointerEvent(x, y, buttonMask);
-      } else {
-	fprintf(stderr,
-		"Invalid params: SendRFBEvent(ptr,<x>,<y>,<buttonMask>)\n"
-		"             or SendRFBEvent(ptr,<buttonMask>)\n");
-	return;
-      }
-
-    } else {
-      fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n", params[0]);
-    }
-    return;
-  }
-
-  switch (ev->type) {
+		XLookupString(&ev->xkey, keyname, 256, &ks, NULL);
 
-  case MotionNotify:
-    while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev))
-      ;	/* discard all queued motion notify events */
-
-    SendPointerEvent(ev->xmotion.x, ev->xmotion.y,
-		     (ev->xmotion.state & 0x1f00) >> 8);
-    return;
-
-  case ButtonPress:
-    SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
-		     (((ev->xbutton.state & 0x1f00) >> 8) |
-		      (1 << (ev->xbutton.button - 1))));
-    return;
-
-  case ButtonRelease:
-    SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
-		     (((ev->xbutton.state & 0x1f00) >> 8) &
-		      ~(1 << (ev->xbutton.button - 1))));
-    return;
-
-  case KeyPress:
-  case KeyRelease:
-    XLookupString(&ev->xkey, keyname, 256, &ks, NULL);
-
-    if (IsModifierKey(ks)) {
-      ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0);
-      modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress);
-    }
+		if (IsModifierKey(ks)) {
+			ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0);
+			modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress);
+		}
 
-    SendKeyEvent(ks, (ev->type == KeyPress));
-    return;
+		SendKeyEvent(ks, (ev->type == KeyPress));
+		return;
 
-  default:
-    fprintf(stderr,"Invalid event passed to SendRFBEvent\n");
-  }
+	default:
+		fprintf(stderr,"Invalid event passed to SendRFBEvent\n");
+	}
 }
 
 
@@ -329,68 +2496,255 @@
  * CreateDotCursor.
  */
 
+#ifndef very_small_dot_cursor
 static Cursor
-CreateDotCursor()
+CreateDotCursor(int which)
 {
-  Cursor cursor;
-  Pixmap src, msk;
-  static char srcBits[] = { 0, 14,14,14, 0 };
-  static char mskBits[] = { 14,31,31,31,14 };
-  XColor fg, bg;
-
-  src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 5, 5);
-  msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 5, 5);
-  XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black",
-		   &fg, &fg);
-  XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white",
-		   &bg, &bg);
-  cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 2, 2);
-  XFreePixmap(dpy, src);
-  XFreePixmap(dpy, msk);
+	Cursor cursor;
+	Pixmap src, msk;
+	static char srcBits3[] = { 0x00, 0x02, 0x00 };
+	static char mskBits3[] = { 0x02, 0x07, 0x02 };
+	static char srcBits4[] = { 0x00, 0x06, 0x06, 0x00 };
+	static char mskBits4[] = { 0x06, 0x0f, 0x0f, 0x06 };
+	XColor fg, bg;
+
+	if (which == 3) {
+		src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits3, 3, 3);
+		msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits3, 3, 3);
+	} else {
+		src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits4, 4, 4);
+		msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits4, 4, 4);
+	}
+	XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black",
+	    &fg, &fg);
+	XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white",
+	    &bg, &bg);
+	cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1);
+	XFreePixmap(dpy, src);
+	XFreePixmap(dpy, msk);
 
-  return cursor;
+	return cursor;
 }
+#else
+static Cursor
+CreateDotCursor()
+{
+	Cursor cursor;
+	Pixmap src, msk;
+	static char srcBits[] = { 0, 14, 0 };
+	static char mskBits[] = { 14,31,14 };
+	XColor fg, bg;
+
+	src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 3, 3);
+	msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 3, 3);
+	XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black",
+	    &fg, &fg);
+	XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white",
+	    &bg, &bg);
+	cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1);
+	XFreePixmap(dpy, src);
+	XFreePixmap(dpy, msk);
 
+	return cursor;
+}
+#endif
 
+int skip_maybe_sync = 0;
+void maybe_sync(int width, int height) {
+	static int singles = 0, always_skip = -1;
+	int singles_max = 64;
+
+	if (always_skip < 0) {
+		if (getenv("SSVNC_NO_MAYBE_SYNC")) {
+			always_skip = 1;
+		} else {
+			always_skip = 0;
+		}
+	}
+	if (skip_maybe_sync || always_skip) {
+		return;
+	}
+#if 0
+	if (width > 1 || height > 1) {
+		XSync(dpy, False);
+		singles = 0;
+	} else {
+		if (++singles >= singles_max) {
+			singles = 0;
+			XSync(dpy, False);
+		}
+	}
+#else
+	if (width * height >= singles_max) {
+		XSync(dpy, False);
+		singles = 0;
+	} else {
+		singles += width * height;
+		if (singles >= singles_max) {
+			XSync(dpy, False);
+			singles = 0;
+		}
+	}
+#endif
+}
 /*
- * CopyDataToScreen.
+ * FillImage.
  */
 
 void
-CopyDataToScreen(char *buf, int x, int y, int width, int height)
+FillScreen(int x, int y, int width, int height, unsigned long fill)
 {
-  if (appData.rawDelay != 0) {
-    XFillRectangle(dpy, desktopWin, gc, x, y, width, height);
+	XImage *im = image_scale ? image_scale : image;
+	int bpp = im->bits_per_pixel;
+	int Bpp = im->bits_per_pixel / 8;
+	int Bpl = im->bytes_per_line;
+	int h, widthInBytes = width * Bpp;
+	static char *buf = NULL;
+	static int buflen = 0;
+	unsigned char  *ucp;
+	unsigned short *usp;
+	unsigned int   *uip;
+	char *scr;
+	int b0, b1, b2;
 
-    XSync(dpy,False);
+#if 0
+fprintf(stderr, "FillImage bpp=%d %04dx%04d+%04d+%04d -- 0x%x\n", bpp, width, height, x, y, fill);
+#endif
+	if (appData.chatOnly) {
+		return;
+	}
 
-    usleep(appData.rawDelay * 1000);
-  }
+	if (widthInBytes > buflen || !buf)  {
+		if (buf) {
+			free(buf);
+		}
+		buflen = widthInBytes * 2;
+		buf = (char *)malloc(buflen); 
+	}
+	ucp = (unsigned char*) buf;
+	usp = (unsigned short*) buf;
+	uip = (unsigned int*) buf;
+
+	if (isLSB) {
+		b0 = 0; b1 = 1; b2 = 2;
+	} else {
+		b0 = 2; b1 = 1; b2 = 0;
+	}
 
-  if (!appData.useBGR233) {
-    int h;
-    int widthInBytes = width * myFormat.bitsPerPixel / 8;
-    int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8;
-
-    char *scr = (image->data + y * scrWidthInBytes
-		 + x * myFormat.bitsPerPixel / 8);
-
-    for (h = 0; h < height; h++) {
-      memcpy(scr, buf, widthInBytes);
-      buf += widthInBytes;
-      scr += scrWidthInBytes;
-    }
-  } else {
-    CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height);
-  }
+	for (h = 0; h < width; h++) {
+		if (bpp == 8) {
+			*(ucp+h) = (unsigned char)  fill;
+		} else if (bpp == 16) {
+			*(usp+h) = (unsigned short) fill;
+		} else if (bpp == 24) {
+			*(ucp + 3*h + b0) = (unsigned char) ((fill & 0x0000ff) >> 0);
+			*(ucp + 3*h + b1) = (unsigned char) ((fill & 0x00ff00) >> 8);
+			*(ucp + 3*h + b2) = (unsigned char) ((fill & 0xff0000) >> 16);
+		} else if (bpp == 32) {
+			*(uip+h) = (unsigned int)   fill;
+		}
+	}
 
-#ifdef MITSHM
-  if (appData.useShm) {
-    XShmPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height, False);
-    return;
-  }
+	scr = im->data + y * Bpl + x * Bpp;
+
+	for (h = 0; h < height; h++) {
+		memcpy(scr, buf, widthInBytes);
+		scr += Bpl;
+	}
+	put_image(x, y, x, y, width, height, 1);
+	maybe_sync(width, height);
+}
+
+void copy_rect(int x, int y, int width, int height, int src_x, int src_y) {
+	char *src, *dst;
+	int i;
+	XImage *im = image_scale ? image_scale : image;
+	int Bpp = im->bits_per_pixel / 8;
+	int Bpl = im->bytes_per_line;
+	int did2 = 0;
+
+#if 0
+fprintf(stderr, "copy_rect: %04dx%04d+%04d+%04d -- %04d %04d Bpp=%d Bpl=%d\n", width, height, x, y, src_x, src_y, Bpp, Bpl);
 #endif
-  XPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height);
+	copyrect2:
+
+	if (y < src_y) {
+		src = im->data + src_y * Bpl + src_x * Bpp;
+		dst = im->data +     y * Bpl +     x * Bpp;
+		for (i = 0; i < height; i++)  {
+			memmove(dst, src, Bpp * width); 
+			src += Bpl;
+			dst += Bpl;
+		}
+	} else {
+		src = im->data + (src_y + height - 1) * Bpl + src_x * Bpp;
+		dst = im->data + (y     + height - 1) * Bpl +     x * Bpp;
+		for (i = 0; i < height; i++)  {
+			memmove(dst, src, Bpp * width); 
+			src -= Bpl;
+			dst -= Bpl;
+		}
+	}
+
+	if (image_scale && !did2) {
+		im = image;
+		Bpp = im->bits_per_pixel / 8;
+		Bpl = im->bytes_per_line;
+
+		x *= scale_factor_x;
+		y *= scale_factor_y;
+		src_x *= scale_factor_x;
+		src_y *= scale_factor_y;
+		width  = scale_round(width,  scale_factor_x);
+		height = scale_round(height, scale_factor_y);
+
+		did2 = 1;
+		goto copyrect2;
+	}
+}
+
+
+/*
+ * CopyDataToScreen.
+ */
+
+void
+CopyDataToScreen(char *buf, int x, int y, int width, int height)
+{
+	if (appData.chatOnly) {
+		return;
+	}
+	if (appData.rawDelay != 0) {
+		XFillRectangle(dpy, desktopWin, gc, x, y, width, height);
+		XSync(dpy,False);
+		usleep(appData.rawDelay * 1000);
+	}
+
+	if (appData.useBGR233) {
+		CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height);
+	} else if (appData.useBGR565) {
+		CopyBGR565ToScreen((CARD16 *)buf, x, y, width, height);
+	} else {
+		int h;
+		int widthInBytes = width * myFormat.bitsPerPixel / 8;
+		int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8;
+		char *scr;
+		XImage *im = image_scale ? image_scale : image;
+
+		if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line;
+
+		scr = (im->data + y * scrWidthInBytes
+		    + x * myFormat.bitsPerPixel / 8);
+
+		for (h = 0; h < height; h++) {
+			memcpy(scr, buf, widthInBytes);
+			buf += widthInBytes;
+			scr += scrWidthInBytes;
+		}
+	}
+
+	put_image(x, y, x, y, width, height, 0);
+	maybe_sync(width, height);
 }
 
 
@@ -401,62 +2755,338 @@
 static void
 CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height)
 {
-  int p, q;
-  int xoff = 7 - (x & 7);
-  int xcur;
-  int fbwb = si.framebufferWidth / 8;
-  CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8;
-  CARD8 *scrt;
-  CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x;
-  CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x;
-  CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x;
+	XImage *im = image_scale ? image_scale : image;
+	int p, q;
+	int xoff = 7 - (x & 7);
+	int xcur;
+	int fbwb = si.framebufferWidth / 8;
+	int src_width8  = im->bytes_per_line/1;
+	int src_width16 = im->bytes_per_line/2;
+	int src_width32 = im->bytes_per_line/4;
+	CARD8 *src1 = ((CARD8 *)im->data) + y * fbwb + x / 8;
+	CARD8 *srct;
+	CARD8  *src8  = ( (CARD8 *)im->data) + y * src_width8  + x;
+	CARD16 *src16 = ((CARD16 *)im->data) + y * src_width16 + x;
+	CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x;
+	int b0, b1, b2;
 
-  switch (visbpp) {
+	switch (visbpp) {
 
     /* thanks to Chris Hooper for single bpp support */
 
-  case 1:
-    for (q = 0; q < height; q++) {
-      xcur = xoff;
-      scrt = scr1;
-      for (p = 0; p < width; p++) {
-	*scrt = ((*scrt & ~(1 << xcur))
-		 | (BGR233ToPixel[*(buf++)] << xcur));
-
-	if (xcur-- == 0) {
-	  xcur = 7;
-	  scrt++;
-	}
-      }
-      scr1 += fbwb;
-    }
-    break;
-
-  case 8:
-    for (q = 0; q < height; q++) {
-      for (p = 0; p < width; p++) {
-	*(scr8++) = BGR233ToPixel[*(buf++)];
-      }
-      scr8 += si.framebufferWidth - width;
-    }
-    break;
-
-  case 16:
-    for (q = 0; q < height; q++) {
-      for (p = 0; p < width; p++) {
-	*(scr16++) = BGR233ToPixel[*(buf++)];
-      }
-      scr16 += si.framebufferWidth - width;
-    }
-    break;
-
-  case 32:
-    for (q = 0; q < height; q++) {
-      for (p = 0; p < width; p++) {
-	*(scr32++) = BGR233ToPixel[*(buf++)];
-      }
-      scr32 += si.framebufferWidth - width;
-    }
-    break;
-  }
+	case 1:
+		for (q = 0; q < height; q++) {
+			xcur = xoff;
+			srct = src1;
+			for (p = 0; p < width; p++) {
+				*srct = ((*srct & ~(1 << xcur))
+					 | (BGR233ToPixel[*(buf++)] << xcur));
+
+				if (xcur-- == 0) {
+					xcur = 7;
+					srct++;
+				}
+			}
+			src1 += fbwb;
+		}
+		break;
+
+	case 8:
+		for (q = 0; q < height; q++) {
+			for (p = 0; p < width; p++) {
+				*(src8++) = BGR233ToPixel[*(buf++)];
+			}
+			src8 += src_width8 - width;
+		}
+		break;
+
+	case 16:
+		for (q = 0; q < height; q++) {
+			for (p = 0; p < width; p++) {
+				*(src16++) = BGR233ToPixel[*(buf++)];
+			}
+			src16 += src_width16 - width;
+		}
+		break;
+
+	case 24:
+		if (isLSB) {
+			b0 = 0; b1 = 1; b2 = 2;
+		} else {
+			b0 = 2; b1 = 1; b2 = 0;
+		}
+		src8  = ((CARD8 *)im->data) + (y * si.framebufferWidth + x) * 3;
+		for (q = 0; q < height; q++) {
+			for (p = 0; p < width; p++) {
+				CARD32 v = BGR233ToPixel[*(buf++)];
+				*(src8 + b0) = (unsigned char) ((v & 0x0000ff) >> 0);
+				*(src8 + b1) = (unsigned char) ((v & 0x00ff00) >> 8);
+				*(src8 + b2) = (unsigned char) ((v & 0xff0000) >> 16);
+				src8 += 3;
+			}
+			src8 += (si.framebufferWidth - width) * 3;
+		}
+		break;
+
+	case 32:
+		for (q = 0; q < height; q++) {
+			for (p = 0; p < width; p++) {
+				*(src32++) = BGR233ToPixel[*(buf++)];
+			}
+			src32 += src_width32 - width;
+		}
+		break;
+	}
+}
+
+static void
+BGR565_24bpp(CARD16 *buf, int x, int y, int width, int height)
+{
+	int p, q;
+	int b0, b1, b2;
+	XImage *im = image_scale ? image_scale : image;
+	unsigned char *src= (unsigned char *)im->data + (y * si.framebufferWidth + x) * 3;
+
+	if (isLSB) {
+		b0 = 0; b1 = 1; b2 = 2;
+	} else {
+		b0 = 2; b1 = 1; b2 = 0;
+	}
+
+	/*  case 24: */
+	for (q = 0; q < height; q++) {
+		for (p = 0; p < width; p++) {
+			CARD32 v = BGR565ToPixel[*(buf++)];
+			*(src + b0) = (unsigned char) ((v & 0x0000ff) >> 0);
+			*(src + b1) = (unsigned char) ((v & 0x00ff00) >> 8);
+			*(src + b2) = (unsigned char) ((v & 0xff0000) >> 16);
+			src += 3;
+		}
+		src += (si.framebufferWidth - width) * 3;
+	}
+}
+
+static void
+CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width, int height)
+{
+	int p, q;
+	XImage *im = image_scale ? image_scale : image;
+	int src_width32 = im->bytes_per_line/4;
+	CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x;
+
+	if (visbpp == 24) {
+		BGR565_24bpp(buf, x, y, width, height);
+		return;
+	}
+
+	/*  case 32: */
+	for (q = 0; q < height; q++) {
+		for (p = 0; p < width; p++) {
+			*(src32++) = BGR565ToPixel[*(buf++)];
+		}
+		src32 += src_width32 - width;
+	}
+}
+
+static void reset_image(void) {
+	if (UsingShm()) {
+		ShmDetach();
+	}
+	if (image && image->data) {
+		XDestroyImage(image);
+		fprintf(stderr, "reset_image: destroyed 'image'\n");
+	}
+	image = NULL;
+	if (image_ycrop && image_ycrop->data) {
+		XDestroyImage(image_ycrop);
+		fprintf(stderr, "reset_image: destroyed 'image_ycrop'\n");
+	}
+	image_ycrop = NULL;
+	if (image_scale && image_scale->data) {
+		XDestroyImage(image_scale);
+		fprintf(stderr, "reset_image: destroyed 'image_scale'\n");
+	}
+	image_scale = NULL;
+
+	if (UsingShm()) {
+		ShmCleanup();
+	}
+	create_image();
+	XFlush(dpy);
+}
+
+void ReDoDesktop(void) {
+	int w, w0, h, h0, x, y, dw, dh;
+	int fs = 0;
+	int autoscale = 0;
+	Position x_orig, y_orig;
+	Dimension w_orig, h_orig;
+
+	if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) {
+		autoscale = 1;
+	}
+
+	fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop);
+
+	XtVaGetValues(toplevel, XtNx, &x_orig, XtNy, &y_orig, NULL);
+	XtVaGetValues(toplevel, XtNheight, &h_orig, XtNwidth, &w_orig, NULL);
+
+	check_tall();
+
+	if (appData.yCrop) {
+		if (appData.yCrop < 0 || old_width <= 0) {
+			appData.yCrop = guessCrop();
+			fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop);
+		} else {
+			int w1 = si.framebufferWidth;
+			appData.yCrop = (w1 * appData.yCrop) / old_width;
+			if (appData.yCrop <= 100)  {
+				appData.yCrop = guessCrop();
+				fprintf(stderr, "Set small -ycrop to: %d\n", appData.yCrop);
+			}
+		}
+		fprintf(stderr, "Using -ycrop: %d\n", appData.yCrop);
+	}
+
+	old_width  = si.framebufferWidth;
+	old_height = si.framebufferHeight;
+
+	if (appData.fullScreen) {
+		if (prev_fb_width != si.framebufferWidth || prev_fb_height != si.framebufferHeight) {
+			int xmax = si.framebufferWidth;
+			int ymax = si.framebufferHeight;
+			if (appData.yCrop > 0) {
+				ymax = appData.yCrop;
+			}
+			if (scale_x > 0) {
+				xmax = scale_round(xmax, scale_factor_x);
+				ymax = scale_round(ymax, scale_factor_y);
+			}
+			if (xmax < dpyWidth || ymax < dpyHeight) {
+				FullScreenOff();
+				fs = 1;
+			}
+		}
+	}
+
+	prev_fb_width  = si.framebufferWidth;
+	prev_fb_height = si.framebufferHeight;
+
+	if (appData.fullScreen) {
+
+		int xmax = si.framebufferWidth;
+		int ymax = si.framebufferHeight;
+		if (scale_x > 0) {
+			xmax = scale_round(xmax, scale_factor_x);
+			ymax = scale_round(ymax, scale_factor_y);
+		}
+
+		if (image && image->data) {
+			int len;
+			int h = image->height;
+			int w = image->width;
+			len = image->bytes_per_line * image->height;
+			/* black out window first: */
+			memset(image->data, 0, len);
+  			XPutImage(dpy, XtWindow(desktop), gc, image, 0, 0, 0, 0, w, h);
+			XFlush(dpy);
+		}
+
+		/* XXX scaling?? */
+		XtResizeWidget(desktop, xmax, ymax, 0);
+
+		XSync(dpy, False);
+		usleep(100*1000);
+		FullScreenOn();
+		XSync(dpy, False);
+		usleep(100*1000);
+		reset_image();
+		return;
+	}
+
+	dw = appData.wmDecorationWidth;
+	dh = appData.wmDecorationHeight;
+
+	w = si.framebufferWidth;
+	h = si.framebufferHeight;
+	w0 = w;
+	h0 = h;
+	if (appData.yCrop > 0) {
+		h = appData.yCrop;
+	}
+	if (image_scale) {
+		w = scale_round(w, scale_factor_x);
+		h = scale_round(h, scale_factor_y);
+		w0 = scale_round(w0, scale_factor_x);
+		h0 = scale_round(h0, scale_factor_y);
+	}
+
+	if (w + dw >= dpyWidth) {
+		w = dpyWidth - dw;
+	}
+	if (h + dh >= dpyHeight) {
+		h = dpyHeight - dh;
+	}
+
+	if (!autoscale) {
+		XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL);
+	} else {
+		XtVaSetValues(toplevel, XtNmaxWidth, dpyWidth, XtNmaxHeight, dpyHeight, NULL);
+	}
+
+	XtVaSetValues(desktop, XtNwidth, w0, XtNheight, h0, NULL);
+
+	XtResizeWidget(desktop, w0, h0, 0);
+
+	if (appData.yCrop > 0) {
+		int ycrop = appData.yCrop;
+		if (image_scale) {
+			ycrop *= scale_factor_y;
+		}
+		XtVaSetValues(toplevel, XtNmaxHeight, ycrop, NULL);
+		XtVaSetValues(form,     XtNmaxHeight, ycrop, NULL);
+	}
+
+	x = (dpyWidth  - w - dw)/2;
+	y = (dpyHeight - h - dh)/2;
+
+	if (!autoscale) {
+
+		if (!getenv("VNCVIEWER_ALWAYS_RECENTER")) {
+			int x_cm_old, y_cm_old;
+			int x_cm_new, y_cm_new;
+			int x_try, y_try;
+
+			x_cm_old = (int) x_orig + ((int) w_orig)/2;
+			y_cm_old = (int) y_orig + ((int) h_orig)/2;
+
+			x_cm_new = dpyWidth/2;
+			y_cm_new = dpyHeight/2;
+
+			x_try = x + (x_cm_old - x_cm_new);
+			y_try = y + (y_cm_old - y_cm_new);
+			if (x_try < 0) {
+				x_try = 0;
+			}
+			if (y_try < 0) {
+				y_try = 0;
+			}
+			if (x_try + w + dw > dpyWidth) {
+				x_try = dpyWidth - w - dw;
+			}
+			if (y_try + h + dh > dpyHeight) {
+				y_try = dpyHeight - h - dh;
+			}
+			x = x_try;
+			y = y_try;
+		}
+
+		XtConfigureWidget(toplevel, x + dw, y + dh, w, h, 0);
+	}
+
+	reset_image();
+
+	if (fs) {
+		FullScreenOn();
+	}
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncviewer/dialogs.c
--- vnc_unixsrc.orig/vncviewer/dialogs.c	2000-10-26 15:19:19.000000000 -0400
+++ vnc_unixsrc/vncviewer/dialogs.c	2010-02-25 22:33:06.000000000 -0500
@@ -25,75 +25,564 @@
 #include <X11/Xaw/Dialog.h>
 
 static Bool serverDialogDone = False;
+static Bool userDialogDone = False;
 static Bool passwordDialogDone = False;
+static Bool ycropDialogDone = False;
+static Bool scaleDialogDone = False;
+static Bool escapeDialogDone = False;
+static Bool scbarDialogDone = False;
+static Bool scaleNDialogDone = False;
+static Bool qualityDialogDone = False;
+static Bool compressDialogDone = False;
+
+extern void popupFixer(Widget wid);
+
+int use_tty(void) {
+	if (appData.notty) {
+		return 0;
+	} else if (!isatty(0)) {
+		return 0;
+	}
+	return 1;
+}
+
+void
+ScaleDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	scaleDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+void
+EscapeDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	escapeDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+void dialog_over(Widget wid) {
+	if (appData.fullScreen) {
+		if (!net_wm_supported()) {
+			XtVaSetValues(wid, XtNoverrideRedirect, True, NULL);
+			XSync(dpy, True);
+		}
+	}	
+}
+
+extern int XError_ign;
+
+void dialog_input(Widget wid) {
+	XError_ign = 1;
+	XSetInputFocus(dpy, XtWindow(wid), RevertToParent, CurrentTime);
+	XSync(dpy, False);
+	usleep(30 * 1000);
+	XSync(dpy, False);
+	usleep(20 * 1000);
+	XSync(dpy, False);
+	XError_ign = 0;
+}
+
+static void rmNL(char *s) {
+	int len;
+	if (s == NULL) {
+		return;
+	}
+	len = strlen(s);
+	if (len > 0 && s[len-1] == '\n') {
+		s[len-1] = '\0';
+	}
+}
+
+static void wm_delete(Widget w, char *func) {
+	char str[1024];
+	Atom wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+	XSetWMProtocols(dpy, XtWindow(w), &wmDeleteWindow, 1);
+	if (func) {
+		sprintf(str, "<Message>WM_PROTOCOLS: %s", func);
+		XtOverrideTranslations(w, XtParseTranslationTable (str));
+	}
+}
+
+static void xtmove(Widget w) {
+	XtMoveWidget(w, WidthOfScreen(XtScreen(w))*2/5, HeightOfScreen(XtScreen(w))*2/5);
+}
+
+char *
+DoScaleDialog()
+{
+	Widget pshell, dialog;
+	char *scaleValue;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if (0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (appData.scale != NULL) {
+		String label;
+		char tmp[410];
+		XtVaGetValues(dialog, XtNlabel, &label, NULL);
+		if (strlen(label) + strlen(appData.scale) < 400) {
+			sprintf(tmp, "%s %s", label, appData.scale);
+			XtVaSetValues(dialog, XtNlabel, tmp, NULL);
+		}
+	}
+
+
+	if (1 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "ScaleDialogDone()");
+
+	scaleDialogDone = False;
+
+	while (!scaleDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	scaleValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return scaleValue;
+}
+
+char *
+DoEscapeKeysDialog()
+{
+	Widget pshell, dialog;
+	char *escapeValue;
+	char *valueString;
+	char *curr = appData.escapeKeys ? appData.escapeKeys : "default";
+
+	pshell = XtVaCreatePopupShell("escapeDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (curr != NULL) {
+		String label;
+		char tmp[3010];
+		XtVaGetValues(dialog, XtNlabel, &label, NULL);
+		if (strlen(label) + strlen(curr) < 3000) {
+			sprintf(tmp, "%s %s", label, curr);
+			XtVaSetValues(dialog, XtNlabel, tmp, NULL);
+		}
+	}
+
+	if (appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		/* too big */
+		if (0) xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "EscapeDialogDone()");
+
+	escapeDialogDone = False;
+
+	while (!escapeDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	escapeValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return escapeValue;
+}
+
+void
+YCropDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	ycropDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+char *
+DoYCropDialog()
+{
+	Widget pshell, dialog;
+	char *ycropValue;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("ycropDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (1 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "YCropDialogDone()");
+
+	ycropDialogDone = False;
+
+	while (!ycropDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	ycropValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return ycropValue;
+}
+
+void
+ScbarDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	scbarDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+char *
+DoScbarDialog()
+{
+	Widget pshell, dialog;
+	char *scbarValue;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("scbarDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (1 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "ScbarDialogDone()");
+
+	scbarDialogDone = False;
+
+	while (!scbarDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	scbarValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return scbarValue;
+}
+
+void
+ScaleNDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	scaleNDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+char *
+DoScaleNDialog()
+{
+	Widget pshell, dialog;
+	char *scaleNValue;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("scaleNDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+	wm_delete(pshell, "ScaleNDialogDone()");
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "ScaleNDialogDone()");
+
+	scaleNDialogDone = False;
+
+	while (!scaleNDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	scaleNValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return scaleNValue;
+}
+
+void
+QualityDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	qualityDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+char *
+DoQualityDialog()
+{
+	Widget pshell, dialog;
+	char *qualityValue;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("qualityDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (1 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "QualityDialogDone() HideQuality()");
+
+	qualityDialogDone = False;
+
+	while (!qualityDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	qualityValue = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return qualityValue;
+}
+
+void
+CompressDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	compressDialogDone = True;
+	if (w || event || params || num_params) {}
+}
+
+char *
+DoCompressDialog()
+{
+	Widget pshell, dialog;
+	char *compressValue;
+	char *valueString;
+
+	fprintf(stderr, "compress start:\n");
+
+	pshell = XtVaCreatePopupShell("compressDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (1 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+	dialog_input(pshell);
+	wm_delete(pshell, "CompressDialogDone() HideCompress()");
+
+	compressDialogDone = False;
+
+	while (!compressDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	compressValue = XtNewString(valueString);
+
+	fprintf(stderr, "compress done: %s\n", compressValue);
+
+	XtPopdown(pshell);
+	return compressValue;
+}
 
 void
 ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
 {
-  serverDialogDone = True;
+	serverDialogDone = True;
+	if (w || event || params || num_params) {}
 }
 
 char *
 DoServerDialog()
 {
-  Widget pshell, dialog;
-  char *vncServerName;
-  char *valueString;
+	Widget pshell, dialog;
+	char *vncServerName;
+	char *valueString;
 
-  pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass,
+	pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass,
 				toplevel, NULL);
-  dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
 
-  XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5,
-	       HeightOfScreen(XtScreen(pshell))*2/5);
-  XtPopup(pshell, XtGrabNonexclusive);
-  XtRealizeWidget(pshell);
+	dialog_over(pshell);
 
-  serverDialogDone = False;
+	if (0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (0 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+#if 0
+	dialog_input(pshell);
+#endif
+	wm_delete(pshell, "ServerDialogDone()");
+
+	serverDialogDone = False;
+
+	while (!serverDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	vncServerName = XtNewString(valueString);
 
-  while (!serverDialogDone) {
-    XtAppProcessEvent(appContext, XtIMAll);
-  }
+	XtPopdown(pshell);
+	return vncServerName;
+}
 
-  valueString = XawDialogGetValueString(dialog);
-  vncServerName = XtNewString(valueString);
+void
+UserDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	userDialogDone = True;
+	if (w || event || params || num_params) {}
+}
 
-  XtPopdown(pshell);
-  return vncServerName;
+char *
+DoUserDialog()
+{
+	Widget pshell, dialog;
+	char *userName;
+	char *valueString;
+
+	pshell = XtVaCreatePopupShell("userDialog", transientShellWidgetClass,
+				toplevel, NULL);
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
+
+	dialog_over(pshell);
+
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (0 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+#if 0
+	dialog_input(pshell);
+#endif
+	wm_delete(pshell, "UserDialogDone()");
+
+	userDialogDone = False;
+
+	while (!userDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	userName = XtNewString(valueString);
+
+	XtPopdown(pshell);
+	return userName;
 }
 
 void
-PasswordDialogDone(Widget w, XEvent *event, String *params,
-		   Cardinal *num_params)
+PasswordDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params)
 {
-  passwordDialogDone = True;
+	passwordDialogDone = True;
+	if (w || event || params || num_params) {}
 }
 
 char *
 DoPasswordDialog()
 {
-  Widget pshell, dialog;
-  char *password;
-  char *valueString;
+	Widget pshell, dialog;
+	char *password;
+	char *valueString;
 
-  pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass,
+	pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass,
 				toplevel, NULL);
-  dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
-
-  XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5,
-	       HeightOfScreen(XtScreen(pshell))*2/5);
-  XtPopup(pshell, XtGrabNonexclusive);
-  XtRealizeWidget(pshell);
-
-  passwordDialogDone = False;
+	dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL);
 
-  while (!passwordDialogDone) {
-    XtAppProcessEvent(appContext, XtIMAll);
-  }
+	dialog_over(pshell);
 
-  valueString = XawDialogGetValueString(dialog);
-  password = XtNewString(valueString);
+	if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5);
+	XtPopup(pshell, XtGrabNonexclusive);
+	XtRealizeWidget(pshell);
+
+	if (0 && appData.popupFix) {
+		popupFixer(pshell);
+	} else {
+		xtmove(pshell);
+	}
+#if 0
+	dialog_input(pshell);
+#endif
+	wm_delete(pshell, "PasswordDialogDone()");
+
+	passwordDialogDone = False;
+
+	while (!passwordDialogDone) {
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+
+	valueString = XawDialogGetValueString(dialog);
+	rmNL(valueString);
+	password = XtNewString(valueString);
 
-  XtPopdown(pshell);
-  return password;
+	XtPopdown(pshell);
+	return password;
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncviewer/fullscreen.c
--- vnc_unixsrc.orig/vncviewer/fullscreen.c	2003-10-09 05:23:49.000000000 -0400
+++ vnc_unixsrc/vncviewer/fullscreen.c	2010-02-25 22:37:49.000000000 -0500
@@ -22,20 +22,24 @@
  */
 
 #include <vncviewer.h>
+#include <time.h>
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/Viewport.h>
 #include <X11/Xaw/Toggle.h>
 
 static Bool DoBumpScroll();
+static Bool DoJumpScroll();
 static void BumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id);
+static void JumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id);
 static XtIntervalId timer;
 static Bool timerSet = False;
 static Bool scrollLeft, scrollRight, scrollUp, scrollDown;
-static Position desktopX, desktopY;
+Position desktopX, desktopY;
 static Dimension viewportWidth, viewportHeight;
 static Dimension scrollbarWidth, scrollbarHeight;
 
 
+int scale_round(int len, double fac);
 
 /*
  * FullScreenOn goes into full-screen mode.  It makes the toplevel window
@@ -78,112 +82,456 @@
  * variables so that FullScreenOff can use them.
  */
 
-void
-FullScreenOn()
-{
-  Dimension toplevelWidth, toplevelHeight;
-  Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight;
-  Position viewportX, viewportY;
-
-  appData.fullScreen = True;
-
-  if (si.framebufferWidth > dpyWidth || si.framebufferHeight > dpyHeight) {
-
-    XtVaSetValues(viewport, XtNforceBars, True, NULL);
-    XtVaGetValues(viewport, XtNwidth, &oldViewportWidth,
-		  XtNheight, &oldViewportHeight, NULL);
-    XtVaGetValues(XtNameToWidget(viewport, "clip"),
-		  XtNwidth, &clipWidth, XtNheight, &clipHeight, NULL);
-
-    scrollbarWidth = oldViewportWidth - clipWidth;
-    scrollbarHeight = oldViewportHeight - clipHeight;
-
-    if (si.framebufferWidth > dpyWidth) {
-      viewportWidth = toplevelWidth = dpyWidth + scrollbarWidth;
-    } else {
-      viewportWidth = si.framebufferWidth + scrollbarWidth;
-      toplevelWidth = dpyWidth;
-    }
-
-    if (si.framebufferHeight > dpyHeight) {
-      viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight;
-    } else {
-      viewportHeight = si.framebufferHeight + scrollbarHeight;
-      toplevelHeight = dpyHeight;
-    }
-
-  } else {
-    viewportWidth = si.framebufferWidth;
-    viewportHeight = si.framebufferHeight;
-    toplevelWidth = dpyWidth;
-    toplevelHeight = dpyHeight;
-  }
+int net_wm_supported(void) {
+	unsigned char *data;
+	unsigned long items_read, items_left, i;
+	int ret, format; 
+	Window wm;
+	Atom type;
+	Atom _NET_SUPPORTING_WM_CHECK;
+	Atom _NET_SUPPORTED;
+	Atom _NET_WM_STATE;
+	Atom _NET_WM_STATE_FULLSCREEN;
+
+	static time_t last_check = 0;
+	static int fs_supported = -1;
+
+	if (fs_supported >= 0 && time(NULL) < last_check + 600) {
+		static int first = 1;
+		if (first) {
+			fprintf(stderr, "fs_supported: %d\n", fs_supported);
+		}
+		first = 0;
+		return fs_supported;
+	}
+	last_check = time(NULL);
+
+	fs_supported = 0;
+
+	_NET_SUPPORTING_WM_CHECK = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
+	_NET_SUPPORTED = XInternAtom(dpy, "_NET_SUPPORTED", False);
+	_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
+	_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+
+	ret = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTING_WM_CHECK,
+	    0L, 1L, False, XA_WINDOW, &type, &format, &items_read, &items_left, &data); 
+
+	if (ret != Success || !items_read) {
+		if (ret == Success) {
+			XFree(data);
+		}
+		return fs_supported;
+	}
+
+	wm = ((Window*) data)[0];
+	XFree(data);
+
+	ret = XGetWindowProperty(dpy, wm, _NET_SUPPORTING_WM_CHECK,
+	    0L, 1L, False, XA_WINDOW, &type, &format, &items_read, &items_left, &data); 
+
+	if (ret != Success || !items_read) {
+		if (ret == Success) {
+			XFree(data);
+		}
+		return fs_supported;
+	}
+
+	if (wm != ((Window*) data)[0]) {
+		XFree(data);
+		return fs_supported;
+	}
+
+	ret = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTED,
+	    0L, 8192L, False, XA_ATOM, &type, &format, &items_read, &items_left, &data); 
+
+	if (ret != Success || !items_read) {
+		if (ret == Success) {
+			XFree(data);
+		}
+		return fs_supported;
+	}
+
+	for (i=0; i < items_read; i++) {
+		if ( ((Atom*) data)[i] == _NET_WM_STATE_FULLSCREEN) {
+			fs_supported = 1;
+		}
+	}
+	XFree(data);
 
-  viewportX = (toplevelWidth - viewportWidth) / 2;
-  viewportY = (toplevelHeight - viewportHeight) / 2;
+	return fs_supported;
+}
 
+static void net_wm_fullscreen(int to_fs) {
+	
+	int _NET_WM_STATE_REMOVE = 0;
+	int _NET_WM_STATE_ADD = 1;
+#if 0
+	int _NET_WM_STATE_TOGGLE = 2;
+#endif
+	Atom _NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
+	Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+	XEvent xev;	
+
+	if (to_fs == 2) {
+		XChangeProperty(dpy, XtWindow(toplevel), _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char*)&_NET_WM_STATE_FULLSCREEN, 1);
+	} else {
+		xev.xclient.type = ClientMessage;
+		xev.xclient.window = XtWindow(toplevel);
+		xev.xclient.message_type = _NET_WM_STATE;
+		xev.xclient.serial = 0;
+		xev.xclient.display = dpy;
+		xev.xclient.send_event = True;
+		xev.xclient.format = 32;
+		xev.xclient.data.l[0] = to_fs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+		xev.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
+		xev.xclient.data.l[2] = 0;
+		xev.xclient.data.l[3] = 0;
+		xev.xclient.data.l[4] = 0;
+		XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+	}
 
-  /* We want to stop the window manager from managing our toplevel window.
-     This is not really a nice thing to do, so may not work properly with every
-     window manager.  We do this simply by setting overrideRedirect and
-     reparenting our window to the root.  The window manager will get a
-     ReparentNotify and hopefully clean up its frame window. */
+	XSync(dpy, False);
+}
 
-  XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL);
+time_t main_grab = 0;
 
-  XReparentWindow(dpy, XtWindow(toplevel), DefaultRootWindow(dpy), 0, 0);
+void fs_ungrab(int check) {
+	if (check) {
+		if (time(NULL) <= main_grab + 2) {
+			return;
+		}
+		if (net_wm_supported()) {
+			return;
+		}
+	}
+	fprintf(stderr, "calling fs_ungrab()\n");
+	if (appData.grabAll) { /* runge top of FullScreenOff */
+		fprintf(stderr, "calling XUngrabServer(dpy)\n");
+		XUngrabServer(dpy);     
+	}
+	if (appData.grabKeyboard) {
+		fprintf(stderr, "calling XUngrabKeyboard(dpy)\n");
+		XtUngrabKeyboard(desktop, CurrentTime);
+	}
+}
 
-  /* Some WMs does not obey x,y values of XReparentWindow; the window
-     is not placed in the upper, left corner. The code below fixes
-     this: It manually moves the window, after the Xserver is done
-     with XReparentWindow. The last XSync seems to prevent losing
-     focus, but I don't know why. */
-  XSync(dpy, False);
-  XMoveWindow(dpy, XtWindow(toplevel), 0, 0);
-  XSync(dpy, False);
-
-  /* Now we want to fix the size of "viewport".  We shouldn't just change it
-     directly.  Instead we set "toplevel" to the required size (which should
-     propagate through "form" to "viewport").  Then we remove "viewport" from
-     being managed by "form", change its resources to position it and make sure
-     that "form" won't attempt to resize it, then ask "form" to manage it
-     again. */
-
-  XtResizeWidget(toplevel, viewportWidth, viewportHeight, 0);
-
-  XtUnmanageChild(viewport);
-
-  XtVaSetValues(viewport,
-		XtNhorizDistance, viewportX,
-		XtNvertDistance, viewportY,
-		XtNleft, XtChainLeft,
-		XtNright, XtChainLeft,
-		XtNtop, XtChainTop,
-		XtNbottom, XtChainTop,
-		NULL);
+void fs_grab(int check) {
+	if (check) {
+		if (time(NULL) <= main_grab + 2) {
+			return;
+		}
+		if (net_wm_supported()) {
+			return;
+		}
+	}
+
+	main_grab = time(NULL);
+
+	fprintf(stderr, "calling fs_grab()\n");
+	
+#define FORCE_UP \
+	XSync(dpy, False); \
+	XUnmapWindow(dpy, XtWindow(toplevel)); \
+	XSync(dpy, False); \
+	XMapWindow(dpy, XtWindow(toplevel)); \
+	XRaiseWindow(dpy, XtWindow(toplevel)); \
+	XSync(dpy, False);
+
+	if (appData.grabKeyboard && XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) {
+		fprintf(stderr, "XtGrabKeyboard() failed.\n");
+		XSync(dpy, False);
+		usleep(100 * 1000);
+		FORCE_UP
+
+		if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) {
+			fprintf(stderr, "XtGrabKeyboard() failed again.\n");
+			usleep(200 * 1000);
+			XSync(dpy, False);
+			if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) {
+				fprintf(stderr, "XtGrabKeyboard() failed 3rd time.\n");
+			} else {
+				fprintf(stderr, "XtGrabKeyboard() OK 3rd try.\n");
+			}
+		} else {
+			fprintf(stderr, "XtGrabKeyboard() OK 2nd try.\n");
+		}
+		XRaiseWindow(dpy, XtWindow(toplevel));
+	} 
+
+	if (appData.grabAll) {
+		fprintf(stderr, "calling XGrabServer(dpy)\n");
+		if (! XGrabServer(dpy)) {
+			XSync(dpy, False);
+			usleep(100 * 1000);
+			fprintf(stderr, "calling XGrabServer(dpy) 2nd time\n");
+			if (!XGrabServer(dpy)) {
+				XSync(dpy, False);
+				usleep(200 * 1000);
+				fprintf(stderr, "calling XGrabServer(dpy) 3rd time\n");
+				if (XGrabServer(dpy)) {
+					fprintf(stderr, "XGrabServer(dpy) OK 3rd time\n");
+				}
+			} else {
+				fprintf(stderr, "XGrabServer(dpy) OK 2nd time\n");
+			}
+			XSync(dpy, False);
+		}
+		if (getenv("VNCVIEWER_FORCE_UP")) {
+			fprintf(stderr, "FORCE_UP\n");
+			FORCE_UP
+		}
+	}
+}
+
+extern int fullscreen_startup;
+extern double last_fullscreen;
+
+#define set_size_hints() \
+{ \
+	long supplied; \
+	XSizeHints *sizehints = XAllocSizeHints(); \
+	XGetWMSizeHints(dpy, topwin, sizehints, &supplied, XA_WM_NORMAL_HINTS); \
+	if (sizehints->base_width < toplevelWidth) { \
+		sizehints->base_width = toplevelWidth; \
+	} \
+	if (sizehints->base_height < toplevelHeight) { \
+		sizehints->base_height = toplevelHeight; \
+	} \
+	if (sizehints->max_width < toplevelWidth) { \
+		sizehints->max_width = toplevelWidth; \
+	} \
+	if (sizehints->max_height < toplevelHeight) { \
+		sizehints->max_height = toplevelHeight; \
+	} \
+	XSetWMSizeHints(dpy, topwin, sizehints, XA_WM_NORMAL_HINTS); \
+	XFree(sizehints); \
+}
 
-  XtManageChild(viewport);
+extern int scale_x, scale_y;
+extern double scale_factor_y;
+
+void
+FullScreenOn()
+{
+	Dimension toplevelWidth, toplevelHeight;
+	Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight;
+	Position viewportX, viewportY;
+	int do_net_wm = net_wm_supported();
+	int fbW = si.framebufferWidth;
+	int fbH = si.framebufferHeight;
+	int eff_height;
+
+	Bool fsAlready = appData.fullScreen, toobig = False;
+	Window topwin = XtWindow(toplevel);
+
+	appData.fullScreen = True;
+
+	last_fullscreen = dnow();
+
+	if (scale_x > 0) {
+		fbW = scale_x;
+		fbH = scale_y;
+	}
+
+	eff_height = fbH;
+	if (appData.yCrop > 0) {
+		eff_height = appData.yCrop;
+		if (scale_y > 0) {
+			eff_height = scale_round(eff_height, scale_factor_y);
+		}
+	}
+
+	if (fbW > dpyWidth || eff_height > dpyHeight) {
+
+		toobig = True;
+
+		/*
+		 * This is a crazy thing to have the scrollbars hang
+		 * just a bit offscreen to the right and below.  the user
+		 * will not see them and bumpscroll will work.
+		 */
+	
+		XtVaSetValues(viewport, XtNforceBars, True, NULL);
+		XtVaGetValues(viewport, XtNwidth, &oldViewportWidth, XtNheight, &oldViewportHeight, NULL);
+		XtVaGetValues(XtNameToWidget(viewport, "clip"), XtNwidth, &clipWidth, XtNheight, &clipHeight, NULL);
+
+		scrollbarWidth  = oldViewportWidth  - clipWidth;
+		scrollbarHeight = oldViewportHeight - clipHeight;
+
+		if (fbW > dpyWidth) {
+			viewportWidth = toplevelWidth = dpyWidth + scrollbarWidth;
+		} else {
+			viewportWidth = fbW + scrollbarWidth;
+			toplevelWidth = dpyWidth;
+		}
+
+		if (eff_height > dpyHeight) {
+			viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight;
+		} else {
+			viewportHeight = eff_height + scrollbarHeight;
+			toplevelHeight = dpyHeight;
+		}
+		if (do_net_wm) {
+			/* but for _NET_WM we make toplevel be correct dpy size */
+			toplevelWidth  = dpyWidth;
+			toplevelHeight = dpyHeight;
+		}
+
+	} else {
+		viewportWidth = fbW;
+		viewportHeight = eff_height;
+		toplevelWidth  = dpyWidth;
+		toplevelHeight = dpyHeight;
+	}
 
-  /* Now we can set "toplevel" to its proper size. */
+	viewportX = (toplevelWidth - viewportWidth) / 2;
+	viewportY = (toplevelHeight - viewportHeight) / 2;
 
-  XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0);
+	if (viewportX < 0) viewportX = 0;
+	if (viewportY < 0) viewportY = 0;
 
-  /* Set the popup to overrideRedirect too */
 
-  XtVaSetValues(popup, XtNoverrideRedirect, True, NULL);
+  /* We want to stop the window manager from managing our toplevel window.
+     This is not really a nice thing to do, so may not work properly with every
+     window manager.  We do this simply by setting overrideRedirect and
+     reparenting our window to the root.  The window manager will get a
+     ReparentNotify and hopefully clean up its frame window. */
 
-  /* Try to get the input focus. */
+	if (! fsAlready) {
+		if (!do_net_wm) {
+			/* added to try to raise it on top for some cirumstances */
+			XUnmapWindow(dpy, topwin);
+
+			XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL);
+#if 0
+			XtVaSetValues(viewport, XtNoverrideRedirect, True, NULL);
+			XtVaSetValues(desktop,  XtNoverrideRedirect, True, NULL);
+#endif
+			XtVaSetValues(popup,    XtNoverrideRedirect, True, NULL);
+
+			XReparentWindow(dpy, topwin, DefaultRootWindow(dpy), 0, 0);
+
+		  /* Some WMs does not obey x,y values of XReparentWindow; the window
+		     is not placed in the upper, left corner. The code below fixes
+		     this: It manually moves the window, after the Xserver is done
+		     with XReparentWindow. The last XSync seems to prevent losing
+		     focus, but I don't know why. */
+
+			XSync(dpy, False);
+
+			/* added to try to raise it on top for some cirumstances */
+			XMapRaised(dpy, topwin);
+
+			XMoveWindow(dpy, topwin, 0, 0);
+			XSync(dpy, False);
+		}
+
+		  /* Now we want to fix the size of "viewport".  We shouldn't just change it
+		     directly.  Instead we set "toplevel" to the required size (which should
+		     propagate through "form" to "viewport").  Then we remove "viewport" from
+		     being managed by "form", change its resources to position it and make sure
+		     that "form" won't attempt to resize it, then ask "form" to manage it
+		     again. */
+
+		XtResizeWidget(toplevel, viewportWidth, viewportHeight, 0);
+
+		XtUnmanageChild(viewport);
+
+		XtVaSetValues(viewport,
+			XtNhorizDistance, viewportX,
+			XtNvertDistance, viewportY,
+			XtNleft, XtChainLeft,
+			XtNright, XtChainLeft,
+			XtNtop, XtChainTop,
+			XtNbottom, XtChainTop,
+			NULL);
+
+		XtManageChild(viewport);
+		XSync(dpy, False);
+	} else {
+		XSync(dpy, False);
+	}
+
+	/* Now we can set "toplevel" to its proper size. */
+
+#if 0
+	XtVaSetValues(toplevel, XtNwidth, toplevelWidth, XtNheight, toplevelHeight, NULL);
+	XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0);
+#endif
+	XResizeWindow(dpy, topwin, toplevelWidth, toplevelHeight);
+
+	if (do_net_wm) {
+		XWindowAttributes attr;
+		int ok = 0, i, delay = 20;
+
+		usleep(delay * 1000);
+
+#define GSIZE() \
+	XGetWindowAttributes(dpy, topwin, &attr);
+
+#define PSIZE(s) \
+	XSync(dpy, False); \
+	XGetWindowAttributes(dpy, topwin, &attr); \
+	fprintf(stderr, "%s %dx%d+%d+%d\n", s, attr.width, attr.height, attr.x, attr.y);
+
+		PSIZE("size-A:");
+
+		set_size_hints();
+
+		net_wm_fullscreen(1);
+
+		PSIZE("size-B:");
+
+		for (i=0; i < 30; i++) {
+			usleep(delay * 1000);
+			GSIZE();
+			fprintf(stderr, "size[%d] %dx%d+%d+%d\n", i, attr.width, attr.height, attr.x, attr.y);
+			if (attr.width == toplevelWidth && attr.height == toplevelHeight) {
+				ok = 1;
+				fprintf(stderr, "size ok.\n");
+				XSync(dpy, False);
+				break;
+			}
+			set_size_hints();
+			XResizeWindow(dpy, topwin, toplevelWidth, toplevelHeight);
+			XMoveWindow(dpy, topwin, 0, 0);
+			XSync(dpy, False);
+		}
+
+		PSIZE("size-C:");
+	}
+
+	fprintf(stderr, "\ntoplevel: %dx%d viewport: %dx%d\n", toplevelWidth, toplevelHeight, viewportWidth, viewportHeight);
+
+#if defined (__SVR4) && defined (__sun)
+	if (!do_net_wm) {
+		/* CDE */
+		XSync(dpy, False);
+		usleep(200 * 1000);
+		XMoveWindow(dpy, topwin, 0, 0);
+		XMapRaised(dpy, topwin);
+		XSync(dpy, False);
+	}
+#endif
+
+	if (fsAlready) {
+		XtResizeWidget(viewport, viewportWidth, viewportHeight, 0);
+		if (! toobig) {
+			XtVaSetValues(viewport, XtNforceBars, False, NULL);
+		}
+		XMoveWindow(dpy, topwin, viewportX, viewportY);
+		XSync(dpy, False);
+	}
+
+	/* Try to get the input focus. */
 
-  XSetInputFocus(dpy, DefaultRootWindow(dpy), RevertToPointerRoot,
-		 CurrentTime);
+	/* original vnc: DefaultRootWindow(dpy) instead of PointerRoot */
+	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
 
-  /* Optionally, grab the keyboard. */
+	/* Optionally, grab the keyboard. */
+	fs_grab(0);
 
-  if (appData.grabKeyboard &&
-      XtGrabKeyboard(desktop, True, GrabModeAsync,
-		     GrabModeAsync, CurrentTime) != GrabSuccess) {
-    fprintf(stderr, "XtGrabKeyboard() failed.\n");
-  }
+	/* finally done. */
 }
 
 
@@ -205,28 +553,52 @@
 void
 FullScreenOff()
 {
-  int toplevelWidth = si.framebufferWidth;
-  int toplevelHeight = si.framebufferHeight;
-
-  appData.fullScreen = False;
+	int toplevelWidth, toplevelHeight;
+	int do_net_wm = net_wm_supported();
+	int fbW = si.framebufferWidth;
+	int fbH = si.framebufferHeight;
+	int eff_height;
+
+	appData.fullScreen = False;
+
+	last_fullscreen = dnow();
+
+	if (scale_x > 0) {
+		fbW = scale_x;
+		fbH = scale_y;
+	}
+
+	eff_height = fbH;
+	if (appData.yCrop > 0) {
+		eff_height = appData.yCrop;
+		if (scale_y > 0) {
+			eff_height = scale_round(eff_height, scale_factor_y);
+		}
+	}
+
+	toplevelWidth = fbW;
+	toplevelHeight = eff_height;
+
+	fs_ungrab(0);
+
+	if (do_net_wm) {
+		net_wm_fullscreen(0);
+	} else {
+		XtUnmapWidget(toplevel);
+	}
 
-  if (appData.grabKeyboard)
-    XtUngrabKeyboard(desktop, CurrentTime);
-
-  XtUnmapWidget(toplevel);
-
-  XtResizeWidget(toplevel,
+	XtResizeWidget(toplevel,
 		 viewportWidth - scrollbarWidth,
 		 viewportHeight - scrollbarHeight, 0);
-  XtResizeWidget(viewport,
+	XtResizeWidget(viewport,
 		 viewportWidth - scrollbarWidth,
 		 viewportHeight - scrollbarHeight, 0);
 
-  XtVaSetValues(viewport, XtNforceBars, False, NULL);
+	XtVaSetValues(viewport, XtNforceBars, False, NULL);
 
-  XtUnmanageChild(viewport);
+	XtUnmanageChild(viewport);
 
-  XtVaSetValues(viewport,
+	XtVaSetValues(viewport,
 		XtNhorizDistance, 0,
 		XtNvertDistance, 0,
 		XtNleft, XtChainLeft,
@@ -235,24 +607,42 @@
 		XtNbottom, XtChainBottom,
 		NULL);
 
-  XtManageChild(viewport);
-
-  XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL);
-
-  if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth)
-    toplevelWidth = dpyWidth - appData.wmDecorationWidth;
-
-  if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight)
-    toplevelHeight = dpyHeight - appData.wmDecorationHeight;
-
-  XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0);
-
-  XtMapWidget(toplevel);
-  XSync(dpy, False);
+	XtManageChild(viewport);
 
-  /* Set the popup back to non-overrideRedirect */
-
-  XtVaSetValues(popup, XtNoverrideRedirect, False, NULL);
+	if (!do_net_wm) {
+		XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL);
+#if 0
+		XtVaSetValues(viewport, XtNoverrideRedirect, False, NULL);
+		XtVaSetValues(desktop,  XtNoverrideRedirect, False, NULL);
+#endif
+		XtVaSetValues(popup,    XtNoverrideRedirect, False, NULL);
+	}
+
+	if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth)
+		toplevelWidth = dpyWidth - appData.wmDecorationWidth;
+
+	if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight)
+		toplevelHeight = dpyHeight - appData.wmDecorationHeight;
+
+	XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0);
+
+	if (!do_net_wm) {
+		XtMapWidget(toplevel);
+	}
+	XSync(dpy, False);
+
+	/* Set the popup back to non-overrideRedirect */
+
+	XtVaSetValues(popup, XtNoverrideRedirect, False, NULL);
+
+	if (!do_net_wm) {
+		int x = (dpyWidth  - toplevelWidth)  / 2;
+		int y = (dpyHeight - toplevelHeight) / 2;
+		if (x > 0 && y > 0) {
+			XSync(dpy, False);
+			XMoveWindow(dpy, XtWindow(toplevel), x, y);
+		}
+	}
 }
 
 
@@ -264,10 +654,12 @@
 void
 SetFullScreenState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
 {
-  if (appData.fullScreen)
-    XtVaSetValues(w, XtNstate, True, NULL);
-  else
-    XtVaSetValues(w, XtNstate, False, NULL);
+	if (appData.fullScreen) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
 }
 
 
@@ -278,11 +670,12 @@
 void
 ToggleFullScreen(Widget w, XEvent *ev, String *params, Cardinal *num_params)
 {
-  if (appData.fullScreen) {
-    FullScreenOff();
-  } else {
-    FullScreenOn();
-  }
+	if (appData.fullScreen) {
+		FullScreenOff();
+	} else {
+		FullScreenOn();
+	}
+	if (w || ev || params || num_params) {}
 }
 
 
@@ -294,84 +687,226 @@
 Bool
 BumpScroll(XEvent *ev)
 {
-  scrollLeft = scrollRight = scrollUp = scrollDown = False;
+	scrollLeft = scrollRight = scrollUp = scrollDown = False;
 
-  if (ev->xmotion.x_root >= dpyWidth - 3)
-    scrollRight = True;
-  else if (ev->xmotion.x_root <= 2)
-    scrollLeft = True;
-
-  if (ev->xmotion.y_root >= dpyHeight - 3)
-    scrollDown = True;
-  else if (ev->xmotion.y_root <= 2)
-    scrollUp = True;
-
-  if (scrollLeft || scrollRight || scrollUp || scrollDown) {
-    if (timerSet)
-      return True;
-
-    XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL);
-    desktopX = -desktopX;
-    desktopY = -desktopY;
-
-    return DoBumpScroll();
-  }
-
-  if (timerSet) {
-    XtRemoveTimeOut(timer);
-    timerSet = False;
-  }
+	if (ev->xmotion.x_root >= dpyWidth - 3)
+		scrollRight = True;
+	else if (ev->xmotion.x_root <= 2)
+		scrollLeft = True;
+
+	if (ev->xmotion.y_root >= dpyHeight - 3)
+		scrollDown = True;
+	else if (ev->xmotion.y_root <= 2)
+		scrollUp = True;
+
+	if (scrollLeft || scrollRight || scrollUp || scrollDown) {
+		if (timerSet)
+			return True;
+
+		XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL);
+		desktopX = -desktopX;
+		desktopY = -desktopY;
+
+		return DoBumpScroll();
+	}
+
+	if (timerSet) {
+		XtRemoveTimeOut(timer);
+		timerSet = False;
+	}
 
-  return False;
+	return False;
 }
 
 static Bool
 DoBumpScroll()
 {
-  int oldx = desktopX, oldy = desktopY;
-
-  if (scrollRight) {
-    if (desktopX < si.framebufferWidth - dpyWidth) {
-      desktopX += appData.bumpScrollPixels;
-      if (desktopX > si.framebufferWidth - dpyWidth)
-	desktopX = si.framebufferWidth - dpyWidth;
-    }
-  } else if (scrollLeft) {
-    if (desktopX > 0) {
-      desktopX -= appData.bumpScrollPixels;
-      if (desktopX < 0)
-	desktopX = 0;
-    }
-  }
-
-  if (scrollDown) {
-    if (desktopY < si.framebufferHeight - dpyHeight) {
-      desktopY += appData.bumpScrollPixels;
-      if (desktopY > si.framebufferHeight - dpyHeight)
-	desktopY = si.framebufferHeight - dpyHeight;
-    }
-  } else if (scrollUp) {
-    if (desktopY > 0) {
-      desktopY -= appData.bumpScrollPixels;
-      if (desktopY < 0)
-	desktopY = 0;
-    }
-  }
-
-  if (oldx != desktopX || oldy != desktopY) {
-    XawViewportSetCoordinates(viewport, desktopX, desktopY);
-    timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime,
-			    BumpScrollTimerCallback, NULL);
-    timerSet = True;
-    return True;
-  }
+	int oldx = desktopX, oldy = desktopY;
+	int fbW = si.framebufferWidth;
+	int fbH = si.framebufferHeight;
+
+	if (scale_x > 0) {
+		fbW = scale_x;
+		fbH = scale_y;
+	}
+
+	if (scrollRight) {
+		if (desktopX < fbW - dpyWidth) {
+			desktopX += appData.bumpScrollPixels;
+			if (desktopX > fbW - dpyWidth) {
+				desktopX = fbW - dpyWidth;
+			}
+		}
+	} else if (scrollLeft) {
+		if (desktopX > 0) {
+			desktopX -= appData.bumpScrollPixels;
+			if (desktopX < 0) {
+				desktopX = 0;
+			}
+		}
+	}
+
+	if (scrollDown) {
+		int ycrop = appData.yCrop;
+		if (scale_y > 0)  {
+			ycrop = scale_round(ycrop, scale_factor_y);
+		}
+		if (ycrop > 0 && desktopY + dpyHeight >= ycrop) {
+			;
+		} else if (desktopY < fbH - dpyHeight) {
+			desktopY += appData.bumpScrollPixels;
+			if (desktopY > fbH - dpyHeight) {
+				desktopY = fbH - dpyHeight;
+			}
+		}
+	} else if (scrollUp) {
+		if (desktopY > 0) {
+			desktopY -= appData.bumpScrollPixels;
+			if (desktopY < 0) {
+				desktopY = 0;
+			}
+		}
+	}
+
+	if (oldx != desktopX || oldy != desktopY) {
+		XawViewportSetCoordinates(viewport, desktopX, desktopY);
+		timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime, BumpScrollTimerCallback, NULL);
+		timerSet = True;
+		return True;
+	}
 
-  timerSet = False;
-  return False;
+	timerSet = False;
+	return False;
 }
 
 static void
 BumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id)
 {
-  DoBumpScroll();
+	DoBumpScroll();
+	if (clientData || id) {}
+}
+
+/* not working: */
+
+Bool
+JumpScroll(int up, int vert) {
+	scrollLeft = scrollRight = scrollUp = scrollDown = False;
+
+	
+	if (appData.fullScreen) {
+		return True;
+	}
+	fprintf(stderr, "JumpScroll(%d, %d)\n", up, vert);
+
+	if (vert) {
+		if (up) {
+			scrollUp = True;
+		} else {
+			scrollDown = True;
+		}
+	} else {
+		if (up) {
+			scrollRight = True;
+		} else {
+			scrollLeft = True;
+		}
+	}
+
+	if (scrollLeft || scrollRight || scrollUp || scrollDown) {
+		if (timerSet) {
+			return True;
+		}
+
+		XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL);
+		desktopX = -desktopX;
+		desktopY = -desktopY;
+		return DoJumpScroll();
+	}
+
+	if (timerSet) {
+		XtRemoveTimeOut(timer);
+		timerSet = False;
+	}
+
+	return False;
+}
+
+static Bool
+DoJumpScroll() {
+	int oldx = desktopX, oldy = desktopY;
+	int jumpH, jumpV; 
+	int fbW = si.framebufferWidth;
+	int fbH = si.framebufferHeight;
+
+	if (scale_x > 0) {
+		fbW = scale_x;
+		fbH = scale_y;
+	}
+	jumpH = fbW / 4;
+	jumpV = fbH / 4;
+
+	if (scrollRight) {
+		if (desktopX < fbW - dpyWidth) {
+			desktopX += jumpH;
+			if (desktopX > fbW - dpyWidth)
+				desktopX = fbW - dpyWidth;
+		}
+	} else if (scrollLeft) {
+		if (desktopX > 0) {
+			desktopX -= jumpH;
+			if (desktopX < 0)
+				desktopX = 0;
+		}
+	}
+
+	if (scrollDown) {
+		if (appData.yCrop > 0 && desktopY + dpyHeight >= appData.yCrop) {
+			;
+		} else if (desktopY < fbH - dpyHeight) {
+			desktopY += jumpV;
+			if (desktopY > fbH - dpyHeight)
+				desktopY = fbH - dpyHeight;
+		}
+	} else if (scrollUp) {
+		if (desktopY > 0) {
+			desktopY -= jumpV;
+			if (desktopY < 0)
+				desktopY = 0;
+		}
+	}
+
+	if (oldx != desktopX || oldy != desktopY) {
+		XawViewportSetCoordinates(viewport, desktopX, desktopY);
+		timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime,
+				    JumpScrollTimerCallback, NULL);
+		timerSet = True;
+		return True;
+	}
+
+	timerSet = False;
+	return False;
+}
+
+static void
+JumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id) {
+	DoJumpScroll();
+	if (clientData || id) {}
+}
+void JumpRight(Widget w, XEvent *ev, String *params, Cardinal *num_params) {
+	JumpScroll(1, 0); 
+	if (w || ev || params || num_params) {}
+}
+void JumpLeft(Widget w, XEvent *ev, String *params, Cardinal *num_params) {
+	JumpScroll(0, 0); 
+	if (w || ev || params || num_params) {}
+}
+void JumpUp(Widget w, XEvent *ev, String *params, Cardinal *num_params) {
+	JumpScroll(1, 1); 
+	if (w || ev || params || num_params) {}
 }
+void JumpDown(Widget w, XEvent *ev, String *params, Cardinal *num_params) {
+	JumpScroll(0, 1); 
+	if (w || ev || params || num_params) {}
+}
+
+
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/h2html.pl vnc_unixsrc/vncviewer/h2html.pl
--- vnc_unixsrc.orig/vncviewer/h2html.pl	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/h2html.pl	2008-08-30 20:34:45.000000000 -0400
@@ -0,0 +1,10 @@
+#!/usr/bin/perl
+
+open(HELP, "./vncviewer -help|");
+
+while (<HELP>) {
+	$_ =~ s/&/&amp;/g;
+	$_ =~ s/</&lt;/g;
+	$_ =~ s/>/&gt;/g;
+	print;
+}
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/hextile.c vnc_unixsrc/vncviewer/hextile.c
--- vnc_unixsrc.orig/vncviewer/hextile.c	2007-02-17 22:33:46.000000000 -0500
+++ vnc_unixsrc/vncviewer/hextile.c	2009-10-16 22:54:40.000000000 -0400
@@ -30,6 +30,21 @@
 #define CARDBPP CONCAT2E(CARD,BPP)
 #define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
 
+#define FillRectangle(x, y, w, h, color)  \
+	{ \
+		XGCValues _gcv; \
+		_gcv.foreground = color; \
+		if (!appData.useXserverBackingStore) { \
+			FillScreen(x, y, w, h, _gcv.foreground); \
+		} else { \
+			XChangeGC(dpy, gc, GCForeground, &_gcv); \
+			XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \
+		} \
+	}
+
+extern int skip_maybe_sync;
+extern void maybe_sync(int w, int h);
+
 static Bool
 HandleHextileBPP (int rx, int ry, int rw, int rh)
 {
@@ -41,21 +56,43 @@
   int sx, sy, sw, sh;
   CARD8 subencoding;
   CARD8 nSubrects;
+  int irect = 0, nrects = (rw * rh) / (16 * 16);
+  static int nosync_ycrop = -1;
+
+	if (nosync_ycrop < 0) {
+		nosync_ycrop = 0;
+		if (getenv("HEXTILE_YCROP_TOO")) {
+			nosync_ycrop = 1;
+		}
+	}
 
   for (y = ry; y < ry+rh; y += 16) {
     for (x = rx; x < rx+rw; x += 16) {
       w = h = 16;
-      if (rx+rw - x < 16)
+      if (rx+rw - x < 16) {
 	w = rx+rw - x;
-      if (ry+rh - y < 16)
+      }
+      if (ry+rh - y < 16) {
 	h = ry+rh - y;
+      }
+
+	if (nrects > 400 && (appData.yCrop == 0 || nosync_ycrop)) {
+		skip_maybe_sync = 0;	
+		if (irect++ % 2000 != 0) {
+			if (x < rx+rw-16 || y < ry+rh-16) {
+				skip_maybe_sync	= 1;
+			}
+		}
+	}
 
-      if (!ReadFromRFBServer((char *)&subencoding, 1))
+      if (!ReadFromRFBServer((char *)&subencoding, 1)) {
 	return False;
+      }
 
       if (subencoding & rfbHextileRaw) {
-	if (!ReadFromRFBServer(buffer, w * h * (BPP / 8)))
+	if (!ReadFromRFBServer(buffer, w * h * (BPP / 8))) {
 	  return False;
+        }
 
 	CopyDataToScreen(buffer, x, y, w, h);
 	continue;
@@ -66,14 +103,25 @@
 	  return False;
 
 #if (BPP == 8)
-      if (appData.useBGR233)
+      if (appData.useBGR233) {
 	gcv.foreground = BGR233ToPixel[bg];
-      else
+      } else
+#endif
+#if (BPP == 16)
+      if (appData.useBGR565) {
+	gcv.foreground = BGR565ToPixel[bg];
+      } else
 #endif
+      {
 	gcv.foreground = bg;
+      }
 
-      XChangeGC(dpy, gc, GCForeground, &gcv);
-      XFillRectangle(dpy, desktopWin, gc, x, y, w, h);
+#if 0
+	XChangeGC(dpy, gc, GCForeground, &gcv);
+	XFillRectangle(dpy, desktopWin, gc, x, y, w, h);
+#else
+	FillRectangle(x, y, w, h, gcv.foreground);
+#endif
 
       if (subencoding & rfbHextileForegroundSpecified)
 	if (!ReadFromRFBServer((char *)&fg, sizeof(fg)))
@@ -101,14 +149,25 @@
 	  sh = rfbHextileExtractH(*ptr);
 	  ptr++;
 #if (BPP == 8)
-	  if (appData.useBGR233)
+	  if (appData.useBGR233) {
 	    gcv.foreground = BGR233ToPixel[fg];
-	  else
+	  } else
 #endif
+#if (BPP == 16)
+	  if (appData.useBGR565) {
+	    gcv.foreground = BGR565ToPixel[fg];
+	  } else
+#endif
+	  {
 	    gcv.foreground = fg;
+	  }
 
-	  XChangeGC(dpy, gc, GCForeground, &gcv);
-	  XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh);
+#if 0
+          XChangeGC(dpy, gc, GCForeground, &gcv);
+          XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh);
+#else
+	  FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground);
+#endif
 	}
 
       } else {
@@ -116,13 +175,22 @@
 	  return False;
 
 #if (BPP == 8)
-	if (appData.useBGR233)
+	if (appData.useBGR233) {
 	  gcv.foreground = BGR233ToPixel[fg];
-	else
+	} else
 #endif
+#if (BPP == 16)
+        if (appData.useBGR565) {
+          gcv.foreground = BGR565ToPixel[fg];
+	} else
+#endif
+	{
 	  gcv.foreground = fg;
+	}
 
+#if 0
 	XChangeGC(dpy, gc, GCForeground, &gcv);
+#endif
 
 	for (i = 0; i < nSubrects; i++) {
 	  sx = rfbHextileExtractX(*ptr);
@@ -131,7 +199,11 @@
 	  sw = rfbHextileExtractW(*ptr);
 	  sh = rfbHextileExtractH(*ptr);
 	  ptr++;
+#if 0
 	  XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh);
+#else
+	  FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground);
+#endif
 	}
       }
     }
@@ -139,3 +211,5 @@
 
   return True;
 }
+
+#undef FillRectangle
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewer/listen.c
--- vnc_unixsrc.orig/vncviewer/listen.c	2001-01-16 03:07:57.000000000 -0500
+++ vnc_unixsrc/vncviewer/listen.c	2010-04-11 23:14:21.000000000 -0400
@@ -32,14 +32,88 @@
 #define FLASHDELAY 1	/* seconds */
 
 Bool listenSpecified = False;
+pid_t listenParent = 0;
 int listenPort = 0, flashPort = 0;
 
+#if 0
 static Font flashFont;
-
 static void getFlashFont(Display *d);
 static void flashDisplay(Display *d, char *user);
+#endif
+
 static Bool AllXEventsPredicate(Display *d, XEvent *ev, char *arg);
 
+void raiseme(int force);
+
+static int accept_popup_check(int *argc, char **argv, char *sip, char *sih) {
+	char line[16];
+	char msg[1000];
+	int dopopup = 1;
+
+	if (!getenv("SSVNC_ACCEPT_POPUP")) {
+		return 1;
+	}
+	
+	if (!dopopup && use_tty()) {
+		raiseme(1);
+		fprintf(stderr, "Accept VNC connection? y/[n] ");
+		fgets(line, sizeof(line), stdin);
+		if (!strchr(line, 'y') && !strchr(line, 'Y')) {
+			fprintf(stderr, "Refusing connection.\n");
+			return 0;
+		} else {
+			fprintf(stderr, "Accepting connection.\n");
+			return 1;
+		}
+	} else {
+		int pid, pid2, accept_it = 0;
+
+		pid = fork();
+		if (pid == -1) {
+			perror("fork"); 
+			exit(1);
+		}
+		if (pid == 0) {
+			char *geometry = "2x2+0+0";
+			String fb[] = { "*message.Scroll: whenNeeded", NULL};
+			close(rfbsock);
+
+			toplevel = XtAppInitialize(&appContext, "Ssvnc", cmdLineOptions, numCmdLineOptions,
+			    argc, argv, fb, NULL, 0);
+			XtVaSetValues(toplevel, XtNmaxWidth, 2, XtNmaxHeight, 2, NULL);
+			XtVaSetValues(toplevel, XtNgeometry, geometry, NULL);
+			XtRealizeWidget(toplevel);
+			dpy = XtDisplay(toplevel);
+			sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n                               Hostname: %s\n\n", sip, sih);
+			strcat(msg, "Accept or Reject VNC connection?");
+			if (CreateMsg(msg, 2)) {
+				XCloseDisplay(dpy);
+				exit(0);
+			} else {
+				XCloseDisplay(dpy);
+				exit(1);
+			}
+		} else {
+			int status;
+			pid2 = waitpid(pid, &status, 0);
+			fprintf(stderr, "waitpid: %d/%d status: %d\n", pid, pid2, status);
+			if (pid2 == pid) {
+				if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+					accept_it = 1;
+				}
+			}
+		}
+		if (accept_it) {
+			fprintf(stderr, "Accepting connection.\n");
+			return 1;
+		} else {
+			fprintf(stderr, "Refusing connection.\n");
+			return 0;
+		}
+	}
+	return 0;
+}
+
 /*
  * listenForIncomingConnections() - listen for incoming connections from
  * servers, and fork a new process to deal with each connection.  We must do
@@ -47,145 +121,291 @@
  * cope with forking very well.
  */
 
+extern char *accept6_hostname;
+extern char *accept6_ipaddr;
+
 void
 listenForIncomingConnections(int *argc, char **argv, int listenArgIndex)
 {
-  Display *d;
-  XEvent ev;
-  int listenSocket, flashSocket, sock;
-  fd_set fds;
-  char flashUser[256];
-  int n;
-  int i;
-  char *displayname = NULL;
-
-  listenSpecified = True;
-
-  for (i = 1; i < *argc; i++) {
-    if (strcmp(argv[i], "-display") == 0 && i+1 < *argc) {
-      displayname = argv[i+1];
-    }
-  }
+	Display *d;
+	XEvent ev;
+	int listenSocket, listenSocket6, flashSocket, sock;
+	fd_set fds;
+	char flashUser[256];
+	int n;
+	int i;
+	char *displayname = NULL;
+	int children = 0;
+	int totalconn = 0, maxconn = 0;
+
+	listenSpecified = True;
+	listenParent = getpid();
+
+	for (i = 1; i < *argc; i++) {
+		if (strcmp(argv[i], "-display") == 0 && i+1 < *argc) {
+			displayname = argv[i+1];
+		}
+	}
+	if (sock || flashUser || n) {}
 
-  if (listenArgIndex+1 < *argc && argv[listenArgIndex+1][0] >= '0' &&
+	if (listenArgIndex+1 < *argc && argv[listenArgIndex+1][0] >= '0' &&
 					    argv[listenArgIndex+1][0] <= '9') {
 
-    listenPort = LISTEN_PORT_OFFSET + atoi(argv[listenArgIndex+1]);
-    flashPort = FLASH_PORT_OFFSET + atoi(argv[listenArgIndex+1]);
-    removeArgs(argc, argv, listenArgIndex, 2);
+		listenPort = LISTEN_PORT_OFFSET + atoi(argv[listenArgIndex+1]);
+		flashPort = FLASH_PORT_OFFSET + atoi(argv[listenArgIndex+1]);
+		removeArgs(argc, argv, listenArgIndex, 2);
 
-  } else {
+	} else {
 
-    char *display;
-    char *colonPos;
-    struct utsname hostinfo;
+		char *display;
+		char *colonPos;
+		struct utsname hostinfo;
 
-    removeArgs(argc, argv, listenArgIndex, 1);
+		removeArgs(argc, argv, listenArgIndex, 1);
 
-    display = XDisplayName(displayname);
-    colonPos = strchr(display, ':');
+		display = XDisplayName(displayname);
+		colonPos = strchr(display, ':');
 
-    uname(&hostinfo);
+		uname(&hostinfo);
 
-    if (colonPos && ((colonPos == display) ||
-		     (strncmp(hostinfo.nodename, display,
-			      strlen(hostinfo.nodename)) == 0))) {
+		if (colonPos && ((colonPos == display) ||
+			     (strncmp(hostinfo.nodename, display,
+				      strlen(hostinfo.nodename)) == 0))) {
 
-      listenPort = LISTEN_PORT_OFFSET + atoi(colonPos+1);
-      flashPort = FLASH_PORT_OFFSET + atoi(colonPos+1);
+			listenPort = LISTEN_PORT_OFFSET + atoi(colonPos+1);
+			flashPort = FLASH_PORT_OFFSET + atoi(colonPos+1);
 
-    } else {
-      fprintf(stderr,"%s: cannot work out which display number to "
-	      "listen on.\n", programName);
-      fprintf(stderr,"Please specify explicitly with -listen <num>\n");
-      exit(1);
-    }
-  }
+		} else {
+			fprintf(stderr,"%s: cannot work out which display number to "
+			      "listen on.\n", programName);
+			fprintf(stderr,"Please specify explicitly with -listen <num>\n");
+			exit(1);
+		}
 
-  if (!(d = XOpenDisplay(displayname))) {
-    fprintf(stderr,"%s: unable to open display %s\n",
-	    programName, XDisplayName(displayname));
-    exit(1);
-  }
+	}
 
-  getFlashFont(d);
+	if (!(d = XOpenDisplay(displayname))) {
+		fprintf(stderr,"%s: unable to open display %s\n",
+		    programName, XDisplayName(displayname));
+		exit(1);
+	}
 
-  listenSocket = ListenAtTcpPort(listenPort);
-  flashSocket = ListenAtTcpPort(flashPort);
+#if 0
+	getFlashFont(d);
+#endif
 
-  if ((listenSocket < 0) || (flashSocket < 0)) exit(1);
+	listenSocket  = ListenAtTcpPort(listenPort);
+	listenSocket6 = ListenAtTcpPort6(listenPort);
+
+#if 0
+	flashSocket = ListenAtTcpPort(flashPort);
+#endif
+	flashSocket = 1234;
+
+	if (listenSocket < 0 && listenSocket6 < 0) {
+		fprintf(stderr,"%s -listen: could not obtain a listening socket on port %d\n",
+		    programName, listenPort);
+		exit(1);
+	}
 
-  fprintf(stderr,"%s -listen: Listening on port %d (flash port %d)\n",
-	  programName,listenPort,flashPort);
-  fprintf(stderr,"%s -listen: Command line errors are not reported until "
+	fprintf(stderr,"%s -listen: Listening on port %d  ipv4_fd: %d ipv6_fd: %d\n",
+	  programName, listenPort, listenSocket, listenSocket6);
+	fprintf(stderr,"%s -listen: Cmdline errors are not reported until "
 	  "a connection comes in.\n", programName);
 
-  while (True) {
+	/* this will only work if X events drives this loop -- they don't */
+	if (getenv("SSVNC_MAX_LISTEN")) {
+		maxconn = atoi(getenv("SSVNC_MAX_LISTEN"));
+	}
 
-    /* reap any zombies */
-    int status, pid;
-    while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
-
-    /* discard any X events */
-    while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL))
-      ;
-
-    FD_ZERO(&fds); 
-
-    FD_SET(flashSocket, &fds);
-    FD_SET(listenSocket, &fds);
-    FD_SET(ConnectionNumber(d), &fds);
-
-    select(FD_SETSIZE, &fds, NULL, NULL, NULL);
-
-    if (FD_ISSET(flashSocket, &fds)) {
-
-      sock = AcceptTcpConnection(flashSocket);
-      if (sock < 0) exit(1);
-      n = read(sock, flashUser, 255);
-      if (n > 0) {
-	flashUser[n] = 0;
-	flashDisplay(d, flashUser);
-      } else {
-	flashDisplay(d, NULL);
-      }
-      close(sock);
-    }
+    while (True) {
+	int lsock = -1;
 
-    if (FD_ISSET(listenSocket, &fds)) {
-      rfbsock = AcceptTcpConnection(listenSocket);
-      if (rfbsock < 0) exit(1);
-      if (!SetNonBlocking(rfbsock)) exit(1);
+	/* reap any zombies */
+	int status, pid;
+	while ((pid = wait3(&status, WNOHANG, (struct rusage *)0))>0) {
+		if (pid > 0 && children > 0) {
+			children--;	
+			/* this will only work if X events drives this loop -- they don't */
+			if (maxconn > 0 && totalconn >= maxconn) {
+				fprintf(stderr,"%s -listen: Finished final connection %d\n",
+				    programName, maxconn);
+				exit(0);
+			}
+		}
+	}
 
-      XCloseDisplay(d);
+	/* discard any X events */
+	while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL)) {
+		;
+	}
 
-      /* Now fork off a new process to deal with it... */
+	FD_ZERO(&fds); 
 
-      switch (fork()) {
+#if 0
+	FD_SET(flashSocket, &fds);
+#endif
+	if (listenSocket >= 0) {
+    		FD_SET(listenSocket, &fds);
+	}
+	if (listenSocket6 >= 0) {
+    		FD_SET(listenSocket6, &fds);
+	}
+	FD_SET(ConnectionNumber(d), &fds);
 
-      case -1: 
-	perror("fork"); 
-	exit(1);
+	select(FD_SETSIZE, &fds, NULL, NULL, NULL);
 
-      case 0:
-	/* child - return to caller */
-	close(listenSocket);
-	close(flashSocket);
-	return;
+	while ((pid = wait3(&status, WNOHANG, (struct rusage *)0))>0) {
+		if (pid > 0 && children > 0) {
+			children--;	
+			if (maxconn > 0 && totalconn >= maxconn) {
+				fprintf(stderr,"%s -listen: Finished final connection %d\n",
+				programName, maxconn);
+				exit(0);
+			}
+		}
+	}
 
-      default:
-	/* parent - go round and listen again */
-	close(rfbsock); 
-	if (!(d = XOpenDisplay(displayname))) {
-	  fprintf(stderr,"%s: unable to open display %s\n",
-		  programName, XDisplayName(displayname));
-	  exit(1);
+#if 0
+	if (FD_ISSET(flashSocket, &fds)) {
+		sock = AcceptTcpConnection(flashSocket);
+		if (sock < 0) exit(1);
+		n = read(sock, flashUser, 255);
+		if (n > 0) {
+			flashUser[n] = 0;
+			flashDisplay(d, flashUser);
+		} else {
+			flashDisplay(d, NULL);
+		}
+		close(sock);
+	}
+#endif
+
+	lsock = -1;
+	if (listenSocket >= 0 && FD_ISSET(listenSocket, &fds)) {
+		lsock = listenSocket;
+	} else if (listenSocket6 >= 0 && FD_ISSET(listenSocket6, &fds)) {
+		lsock = listenSocket6;
+	}
+
+	if (lsock >= 0) {
+		int multi_ok = 0;
+		char *sml = getenv("SSVNC_MULTIPLE_LISTEN");
+		char *sip = NULL;
+		char *sih = NULL;
+
+		if (lsock == listenSocket) {
+			rfbsock = AcceptTcpConnection(lsock);
+		} else {
+			rfbsock = AcceptTcpConnection6(lsock);
+		}
+
+		if (sml != NULL) {
+			if (strstr(sml, "MAX:") == sml || strstr(sml, "max:") == sml) {
+				char *q = strchr(sml, ':');
+				int maxc = atoi(q+1);
+				if (maxc == 0 && strcmp(q+1, "0")) {
+					maxc = -99;
+				}
+				if (maxc < 0) {
+					fprintf(stderr, "invalid SSVNC_MULTIPLE_LISTEN=MAX:n, %s, must be 0 or positive, using 1\n", sml); 
+				} else if (maxc == 0) {
+					multi_ok = 1;
+				} else if (children < maxc) {
+					multi_ok = 1;
+				}
+			} else if (strcmp(sml, "") && strcmp(sml, "0")) {
+				multi_ok = 1;
+			}
+		}
+
+		if (rfbsock < 0) exit(1);
+		if (!SetNonBlocking(rfbsock)) exit(1);
+
+		if (children > 0 && !multi_ok) {
+			fprintf(stderr,"\n");
+			fprintf(stderr,"%s: denying extra incoming connection (%d already)\n",
+			    programName, children);
+			fprintf(stderr,"%s: to override: use '-multilisten' or set SSVNC_MULTIPLE_LISTEN=1\n",
+			    programName);
+			fprintf(stderr,"\n");
+			close(rfbsock);
+			rfbsock = -1;
+			continue;
+		}
+
+		if (lsock == listenSocket) {
+			sip = get_peer_ip(rfbsock);
+			if (strlen(sip) > 100) sip = "0.0.0.0";
+			sih = ip2host(sip);
+			if (strlen(sih) > 300) sih = "unknown";
+		} else {
+			if (accept6_hostname != NULL) {
+				sip = accept6_ipaddr;
+				accept6_ipaddr = NULL;
+				sih = accept6_hostname;
+				accept6_hostname = NULL;
+			} else {
+				sip = "unknown";
+				sih = "unknown";
+			}
+		}
+
+		fprintf(stderr, "\n");
+		fprintf(stderr, "(LISTEN) Reverse VNC connection from IP: %s\n", sip);
+		fprintf(stderr, "                               Hostname: %s\n\n", sih);
+
+		if (sml == NULL && !accept_popup_check(argc, argv, sip, sih)) {
+			close(rfbsock);
+			rfbsock = -1;
+			continue;
+		}
+
+		totalconn++;
+
+		XCloseDisplay(d);
+
+		/* Now fork off a new process to deal with it... */
+
+		switch (fork()) {
+
+		case -1: 
+			perror("fork"); 
+			exit(1);
+
+		case 0:
+			/* child - return to caller */
+			close(listenSocket);
+#if 0
+			close(flashSocket);
+#endif
+			if (sml != NULL && !accept_popup_check(argc, argv, sip, sih)) {
+				close(rfbsock);
+				rfbsock = -1;
+				exit(0);
+			}
+			return;
+
+		default:
+			/* parent - go round and listen again */
+			children++;
+			close(rfbsock);
+			if (!(d = XOpenDisplay(displayname))) {
+				fprintf(stderr,"%s: unable to open display %s\n",
+				    programName, XDisplayName(displayname));
+				exit(1);
+			}
+#if 0
+			getFlashFont(d);
+#endif
+			fprintf(stderr,"\n\n%s -listen: Listening on port %d\n",
+			    programName,listenPort);
+			fprintf(stderr,"%s -listen: Cmdline errors are not reported until "
+			    "a connection comes in.\n\n", programName);
+			break;
+		}
 	}
-	getFlashFont(d);
-	break;
-      }
     }
-  }
 }
 
 
@@ -193,9 +413,16 @@
  * getFlashFont
  */
 
+#if 0
 static void
 getFlashFont(Display *d)
 {
+
+#if 1
+	/* no longer used */
+	if (d) {}
+	return;
+#else
   char fontName[256];
   char **fontNames;
   int nFontNames;
@@ -209,6 +436,9 @@
     sprintf(fontName,"fixed");
   }
   flashFont = XLoadFont(d, fontName);
+
+#endif
+
 }
 
 
@@ -219,6 +449,11 @@
 static void
 flashDisplay(Display *d, char *user)
 {
+#if 1
+	/* no longer used */
+	if (d || user) {}
+	return;
+#else
   Window w1, w2, w3, w4;
   XSetWindowAttributes attr;
 
@@ -284,7 +519,11 @@
   XDestroyWindow(d, w3);
   XDestroyWindow(d, w4);
   XFlush(d);
+
+#endif
+
 }
+#endif
 
 /*
  * AllXEventsPredicate is needed to make XCheckIfEvent return all events.
@@ -293,5 +532,6 @@
 static Bool
 AllXEventsPredicate(Display *d, XEvent *ev, char *arg)
 {
-  return True;
+	if (d || ev || arg) {}
+	return True;
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/misc.c vnc_unixsrc/vncviewer/misc.c
--- vnc_unixsrc.orig/vncviewer/misc.c	2003-01-15 02:58:32.000000000 -0500
+++ vnc_unixsrc/vncviewer/misc.c	2010-02-25 22:44:09.000000000 -0500
@@ -23,6 +23,7 @@
 
 #include <vncviewer.h>
 #include <signal.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 
 static void CleanupSignalHandler(int sig);
@@ -33,12 +34,20 @@
 
 Dimension dpyWidth, dpyHeight;
 Atom wmDeleteWindow, wmState;
+int fullscreen_startup = 0;
 
 static Bool xloginIconified = False;
 static XErrorHandler defaultXErrorHandler;
 static XIOErrorHandler defaultXIOErrorHandler;
 static XtErrorHandler defaultXtErrorHandler;
 
+int XError_ign = 0;
+
+void check_tall(void);
+int guessCrop(void);
+void get_scale_values(double *fx, double *fy);
+int scale_round(int n, double factor);
+Bool SendTextChatFinished(void);
 
 /*
  * ToplevelInitBeforeRealization sets the title, geometry and other resources
@@ -48,87 +57,122 @@
 void
 ToplevelInitBeforeRealization()
 {
-  char *titleFormat;
-  char *title;
-  char *geometry;
-
-  XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL);
-  title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1);
-  sprintf(title, titleFormat, desktopName);
-  XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL);
-
-  XtVaSetValues(toplevel, XtNmaxWidth, si.framebufferWidth,
-		XtNmaxHeight, si.framebufferHeight, NULL);
-
-  dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
-  dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
-
-  if (appData.fullScreen) {
-
-    /* full screen - set position to 0,0, but defer size calculation until
-       widgets are realized */
-
-    XtVaSetValues(toplevel, XtNoverrideRedirect, True,
-		  XtNgeometry, "+0+0", NULL);
-
-  } else {
-
-    /* not full screen - work out geometry for middle of screen unless
-       specified by user */
-
-    XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL);
-
-    if (geometry == NULL) {
-      Dimension toplevelX, toplevelY;
-      Dimension toplevelWidth = si.framebufferWidth;
-      Dimension toplevelHeight = si.framebufferHeight;
-
-      if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth)
-	toplevelWidth = dpyWidth - appData.wmDecorationWidth;
-
-      if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight)
-	toplevelHeight = dpyHeight - appData.wmDecorationHeight;
-
-      toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2;
-
-      toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2;
-
-      /* set position via "geometry" so that window manager thinks it's a
-	 user-specified position and therefore honours it */
-
-      geometry = XtMalloc(256);
-
-      sprintf(geometry, "%dx%d+%d+%d",
-	      toplevelWidth, toplevelHeight, toplevelX, toplevelY);
-      XtVaSetValues(toplevel, XtNgeometry, geometry, NULL);
-    }
-  }
+	char *titleFormat;
+	char *title;
+	char *geometry;
+	int h = si.framebufferHeight;
+	int w = si.framebufferWidth;
+
+	check_tall();
+	if (appData.yCrop < 0) {
+		appData.yCrop = guessCrop();
+		fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop);
+		if (appData.yCrop > 0) {
+			h = appData.yCrop;
+		}
+	}
+	
+	XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL);
+	title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1);
+	sprintf(title, titleFormat, desktopName);
+	XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL);
+
+	if (appData.scale != NULL) {
+		/* switched to not scaled */
+		double frac_x, frac_y;
+		get_scale_values(&frac_x, &frac_y);
+		if (frac_x > 0.0 && frac_y > 0.0) {
+			w = scale_round(w, frac_x);
+			h = scale_round(h, frac_y);
+		}
+	}
+	XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL);
+
+	dpyWidth  = WidthOfScreen(DefaultScreenOfDisplay(dpy));
+	dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
+
+	if (appData.fullScreen) {
+		/* full screen - set position to 0,0, but defer size calculation until widgets are realized */
+
+		if (!net_wm_supported()) {
+			XtVaSetValues(toplevel, XtNoverrideRedirect, True, XtNgeometry, "+0+0", NULL);
+		} else {
+			fullscreen_startup = 1;
+		}
+
+	} else {
+
+		/* not full screen - work out geometry for middle of screen unless specified by user */
+
+		XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL);
+
+		if (geometry == NULL) {
+			Dimension toplevelX, toplevelY;
+			Dimension toplevelWidth  = w;
+			Dimension toplevelHeight = h;
+
+			if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) {
+				toplevelWidth = dpyWidth - appData.wmDecorationWidth;
+			}
+
+			if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) {
+				toplevelHeight = dpyHeight - appData.wmDecorationHeight;
+			}
+
+			toplevelX = (dpyWidth  - toplevelWidth  - appData.wmDecorationWidth) / 2;
+			toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2;
+
+			if (appData.appShare) {
+				int X = appshare_x_hint;
+				int Y = appshare_y_hint;
+				if (appData.scale) {
+					double fx = 1.0, fy = 1.0;
+					get_scale_values(&fx, &fy);
+					if (fx > 0.0 && fy > 0.0) {
+						X *= fx;
+						Y *= fy;
+					}
+				}
+				if (appshare_x_hint != appshare_0_hint) {
+					toplevelX = X;
+				}
+				if (appshare_y_hint != appshare_0_hint) {
+					toplevelY = Y;
+				}
+			}
+
+			/* set position via "geometry" so that window manager thinks it's a
+			 user-specified position and therefore honours it */
+
+			geometry = XtMalloc(256);
+
+			sprintf(geometry, "%dx%d+%d+%d", toplevelWidth, toplevelHeight, toplevelX, toplevelY);
+			fprintf(stderr, "geometry: %s ycrop: %d\n", geometry, appData.yCrop);
+			XtVaSetValues(toplevel, XtNgeometry, geometry, NULL);
+		}
+	}
 
   /* Test if the keyboard is grabbed.  If so, it's probably because the
      XDM login window is up, so try iconifying it to release the grab */
 
-  if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync,
-		    GrabModeSync, CurrentTime) == GrabSuccess) {
-    XUngrabKeyboard(dpy, CurrentTime);
-  } else {
-    wmState = XInternAtom(dpy, "WM_STATE", False);
-
-    if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) {
-      xloginIconified = True;
-      XSync(dpy, False);
-      sleep(1);
-    }
-  }
-
-  /* Set handlers for signals and X errors to perform cleanup */
-
-  signal(SIGHUP, CleanupSignalHandler);
-  signal(SIGINT, CleanupSignalHandler);
-  signal(SIGTERM, CleanupSignalHandler);
-  defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler);
-  defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler);
-  defaultXtErrorHandler = XtAppSetErrorHandler(appContext,
-					       CleanupXtErrorHandler);
+	if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, GrabModeSync, CurrentTime) == GrabSuccess) {
+		XUngrabKeyboard(dpy, CurrentTime);
+	} else {
+		wmState = XInternAtom(dpy, "WM_STATE", False);
+		if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) {
+			xloginIconified = True;
+			XSync(dpy, False);
+			sleep(1);
+		}
+	}
+
+	/* Set handlers for signals and X errors to perform cleanup */
+	signal(SIGHUP,  CleanupSignalHandler);
+	signal(SIGINT,  CleanupSignalHandler);
+	signal(SIGTERM, CleanupSignalHandler);
+	defaultXErrorHandler   = XSetErrorHandler(CleanupXErrorHandler);
+	defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler);
+	defaultXtErrorHandler  = XtAppSetErrorHandler(appContext, CleanupXtErrorHandler);
 }
 
 
@@ -141,14 +185,22 @@
 void
 ToplevelInitAfterRealization()
 {
-  if (appData.fullScreen) {
-    FullScreenOn();
-  }
-
-  wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
-  XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1);
-  XtOverrideTranslations
-      (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
+	if (appData.fullScreen) {
+		FullScreenOn();
+		if (net_wm_supported()) {
+			/* problem with scroll bars sticking: */
+      			XSync(dpy, False);
+  			usleep(50 * 1000);
+			FullScreenOff();
+      			XSync(dpy, False);
+  			usleep(50 * 1000);
+			FullScreenOn();
+		}
+	}
+
+	wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+	XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1);
+	XtOverrideTranslations(toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
 }
 
 
@@ -157,9 +209,7 @@
  * CurrentTime if the event has no time field.
  */
 
-Time
-TimeFromEvent(XEvent *ev)
-{
+Time TimeFromEvent(XEvent *ev) {
   switch (ev->type) {
   case KeyPress:
   case KeyRelease:
@@ -192,18 +242,16 @@
  * generated by SendRFBEvent.
  */
 
-void
-Pause(Widget w, XEvent *event, String *params, Cardinal *num_params)
-{
-  int msec;
+void Pause(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	int msec;
 
-  if (*num_params == 0) {
-    msec = 100;
-  } else {
-    msec = atoi(params[0]);
-  }
-
-  usleep(msec * 1000);
+	if (*num_params == 0) {
+		msec = 100;
+	} else {
+		msec = atoi(params[0]);
+	}
+	usleep(msec * 1000);
+	if (w || event || params || num_params) {}
 }
 
 
@@ -256,6 +304,7 @@
   /* Wait for Child 1 to die */
   wait(&childstatus);
   
+	if (w || event || params || num_params) {}
   return;
 }
 
@@ -264,11 +313,10 @@
  * Quit action - called when we get a "delete window" message.
  */
 
-void
-Quit(Widget w, XEvent *event, String *params, Cardinal *num_params)
-{
-  Cleanup();
-  exit(0);
+void Quit(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	Cleanup();
+	if (w || event || params || num_params) {}
+	exit(0);
 }
 
 
@@ -276,49 +324,94 @@
  * Cleanup - perform any cleanup operations prior to exiting.
  */
 
-void
-Cleanup()
-{
-  if (xloginIconified) {
-    IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True);
-    XFlush(dpy);
-  }
+void Cleanup() {
+
+	if (appData.chatActive) {
+		appData.chatActive = False;
+		fprintf(stderr,"Sending SendTextChatClose()\n");
+		SendTextChatClose();
+		SendTextChatFinished();
+	}
+
+	if (xloginIconified) {
+		IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True);
+		XFlush(dpy);
+	}
 #ifdef MITSHM
-  if (appData.useShm)
-    ShmCleanup();
+	if (appData.useShm) {
+		if (UsingShm()) {
+			ShmDetach();
+		}
+		ShmCleanup();
+	}
 #endif
+
+	releaseAllPressedModifiers();
+
+	fprintf(stderr,"\nVNC Viewer exiting.\n\n");
+	if (listenSpecified) {
+		if (listenParent != 0 && getenv("SSVNC_LISTEN_ONCE") && listenParent != getpid()) {
+			fprintf(stderr, "SSVNC_LISTEN_ONCE: Trying to kill Listening Parent: %d\n", (int) listenParent);
+			fprintf(stderr, "SSVNC_LISTEN_ONCE: Press Ctrl-C if it continues to Listen.\n\n");
+			kill(listenParent, SIGTERM);
+		} else {
+			fprintf(stderr,"(NOTE: You may need to Press Ctrl-C to make the Viewer Stop Listening.)\n\n");
+		}
+	}
+}
+
+static void check_dbg(void) {
+	if (getenv("SSVNC_EXIT_DEBUG")) {
+		fprintf(stderr, "Press any key to continue: ");
+		getc(stdin);
+	}
 }
 
 static int
 CleanupXErrorHandler(Display *dpy, XErrorEvent *error)
 {
-  fprintf(stderr,"CleanupXErrorHandler called\n");
-  Cleanup();
-  return (*defaultXErrorHandler)(dpy, error);
+	if (XError_ign) {
+		char str[4096];
+		XError_ign++;
+		fprintf(stderr,"XError_ign called.\n");
+		str[0] = '\0';
+		if (XGetErrorText(dpy, error->error_code, str, 4096)) {
+			fprintf(stderr, "%s", str);
+		}
+		return 0;
+	}
+	fprintf(stderr,"CleanupXErrorHandler called\n");
+	check_dbg();
+	Cleanup();
+	return (*defaultXErrorHandler)(dpy, error);
 }
 
 static int
 CleanupXIOErrorHandler(Display *dpy)
 {
-  fprintf(stderr,"CleanupXIOErrorHandler called\n");
-  Cleanup();
-  return (*defaultXIOErrorHandler)(dpy);
+	fprintf(stderr,"CleanupXIOErrorHandler called\n");
+	check_dbg();
+	Cleanup();
+	return (*defaultXIOErrorHandler)(dpy);
 }
 
 static void
 CleanupXtErrorHandler(String message)
 {
-  fprintf(stderr,"CleanupXtErrorHandler called\n");
-  Cleanup();
-  (*defaultXtErrorHandler)(message);
+	fprintf(stderr,"CleanupXtErrorHandler called\n");
+	check_dbg();
+	Cleanup();
+	(*defaultXtErrorHandler)(message);
 }
 
 static void
 CleanupSignalHandler(int sig)
 {
-  fprintf(stderr,"CleanupSignalHandler called\n");
-  Cleanup();
-  exit(1);
+	fprintf(stderr,"CleanupSignalHandler called\n");
+	check_dbg();
+	Cleanup();
+	if (sig) {}
+	exit(1);
 }
 
 
@@ -362,7 +455,7 @@
   if (!XQueryTree(dpy, w, &dummy, &dummy, &children, &nchildren))
     return False;
 
-  for (i = 0; i < nchildren; i++) {
+  for (i = 0; i < (int) nchildren; i++) {
     if (IconifyNamedWindow(children[i], name, undo)) {
       XFree ((char *)children);
       return True;
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer/popup.c
--- vnc_unixsrc.orig/vncviewer/popup.c	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/vncviewer/popup.c	2010-04-11 22:03:32.000000000 -0400
@@ -22,25 +22,69 @@
  */
 
 #include "vncviewer.h"
+#include <time.h>
+#include <sys/wait.h>
 
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/Command.h>
+#include <X11/Xaw/AsciiText.h>
 #include <X11/Xaw/Toggle.h>
 
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Scrollbar.h>
+
 Widget popup, fullScreenToggle;
 
+Bool SendTextChatFinished(void);
+
+void popupFixer(Widget wid) {
+	Window rr, cr; 
+	unsigned int m;
+  	int x0 = 500, y0 = 500;
+	int xr, yr, wxr, wyr;
+	Dimension ph;
+	if (XQueryPointer(dpy, DefaultRootWindow(dpy), &rr, &cr, &xr, &yr, &wxr, &wyr, &m)) {
+		x0 = xr;
+		y0 = yr;
+	}
+  	XtPopup(wid, XtGrabNone);
+	XtVaGetValues(wid, XtNheight, &ph, NULL);
+	if (y0 + (int) ph > dpyHeight) {
+		y0 = dpyHeight - (int) ph;
+		if (y0 < 0) {
+			y0 = 0;
+		}
+	}
+	XtMoveWidget(wid, x0, y0);
+}
+
+void Noop(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	if (0) fprintf(stderr, "No-op\n");
+	if (w || event || params || num_params) {}
+}
+
 void
 ShowPopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
 {
-  XtMoveWidget(popup, event->xbutton.x_root, event->xbutton.y_root);
-  XtPopup(popup, XtGrabNone);
-  XSetWMProtocols(dpy, XtWindow(popup), &wmDeleteWindow, 1);
+	if (appData.popupFix) {
+		popupFixer(popup);
+	} else {
+		XtMoveWidget(popup, event->xbutton.x_root, event->xbutton.y_root);
+		XtPopup(popup, XtGrabNone);
+	}
+	if (appData.grabAll) {
+		XSync(dpy, False);
+		XRaiseWindow(dpy, XtWindow(popup));
+	}
+	XSetWMProtocols(dpy, XtWindow(popup), &wmDeleteWindow, 1);
+	XtOverrideTranslations(popup, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HidePopup()"));
+	if (w || event || params || num_params) {}
 }
 
 void
-HidePopup(Widget w, XEvent *event, String *params, Cardinal *num_params)
-{
-  XtPopdown(popup);
+HidePopup(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	XtPopdown(popup);
+	if (w || event || params || num_params) {}
 }
 
 
@@ -52,42 +96,808 @@
 };
 
 void
-CreatePopup()
+CreatePopup() {
+	Widget buttonForm1, buttonForm2, twoForm, button = 0, prevButton = NULL;
+	int i;
+	char buttonName[12];
+	String buttonType;
+
+	popup = XtVaCreatePopupShell("popup", transientShellWidgetClass, toplevel, NULL);
+
+	twoForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, popup, NULL);
+	buttonForm1 = XtVaCreateManagedWidget("buttonForm", formWidgetClass, twoForm, NULL);
+	buttonForm2 = XtVaCreateManagedWidget("buttonForm", formWidgetClass, twoForm, XtNfromHoriz, (XtArgVal) buttonForm1, NULL);
+
+	if (appData.popupButtonCount > 100) {
+		fprintf(stderr,"Too many popup buttons\n");
+		exit(1);
+	}
+
+	for (i = 1; i <= appData.popupButtonCount; i++) {
+		Widget bform;
+		sprintf(buttonName, "button%d", i);
+
+		if (i <= appData.popupButtonBreak) {
+			bform = buttonForm1;
+		} else {
+			if (i == appData.popupButtonBreak+1) {
+				prevButton = NULL;
+			}
+			bform = buttonForm2;
+		}
+		XtVaGetSubresources(bform, (XtPointer)&buttonType, buttonName, "Button", resources, 1, NULL);
+
+		if (strcmp(buttonType, "command") == 0) {
+			button = XtVaCreateManagedWidget(buttonName, commandWidgetClass, bform, NULL);
+			XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
+		} else if (strcmp(buttonType, "toggle") == 0) {
+			button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, bform, NULL);
+			XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
+		} else {
+			fprintf(stderr,"unknown button type '%s'\n", buttonType);
+		}
+		prevButton = button;
+	}
+}
+
+
+Widget scaleN;
+
+void
+ShowScaleN(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  if (appData.popupFix) {
+	popupFixer(scaleN);
+  } else {
+	XtMoveWidget(scaleN, event->xbutton.x_root, event->xbutton.y_root);
+  	XtPopup(scaleN, XtGrabNone);
+  }
+  if (appData.grabAll) {
+  	XRaiseWindow(dpy, XtWindow(scaleN));
+  }
+  XSetWMProtocols(dpy, XtWindow(scaleN), &wmDeleteWindow, 1);
+  XtOverrideTranslations(scaleN, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideScaleN()"));
+	if (w || event || params || num_params) {}
+}
+
+void
+HideScaleN(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  XtPopdown(scaleN);
+	if (w || event || params || num_params) {}
+}
+
+
+void
+CreateScaleN()
 {
   Widget buttonForm, button, prevButton = NULL;
   int i;
-  char buttonName[12];
+  char buttonName[32];
   String buttonType;
 
-  popup = XtVaCreatePopupShell("popup", transientShellWidgetClass, toplevel,
+  scaleN = XtVaCreatePopupShell("scaleN", transientShellWidgetClass, toplevel,
 			       NULL);
 
-  buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, popup,
+  buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, scaleN,
 				       NULL);
 
-  if (appData.popupButtonCount > 100) {
-    fprintf(stderr,"Too many popup buttons\n");
-    exit(1);
-  }
-
-  for (i = 1; i <= appData.popupButtonCount; i++) {
+  for (i = 0; i <= 6; i++) {
     sprintf(buttonName, "button%d", i);
     XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName,
 			"Button", resources, 1, NULL);
 
-    if (strcmp(buttonType, "command") == 0) {
-      button = XtVaCreateManagedWidget(buttonName, commandWidgetClass,
+    button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass,
 				       buttonForm, NULL);
-      XtVaSetValues(button, XtNfromVert, prevButton,
+    XtVaSetValues(button, XtNfromVert, prevButton,
 		    XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
-    } else if (strcmp(buttonType, "toggle") == 0) {
-      button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass,
+    prevButton = button;
+  }
+}
+
+Widget turbovncW;
+
+static Widget turboButtons[32];
+
+Widget qualtext, qualslider;
+
+void UpdateQualSlider(void) {
+#ifdef TURBOVNC
+	char text[16];
+	XawScrollbarSetThumb(qualslider, (float)appData.qualityLevel/100., 0.);
+	sprintf(text, "%3d", appData.qualityLevel);
+	XtVaSetValues(qualtext, XtNlabel, text, NULL);
+#endif
+}
+
+void qualScrollProc(Widget w, XtPointer client, XtPointer p) {
+#ifdef TURBOVNC
+	float size, val;  int qual, pos=(int)p;
+	XtVaGetValues(w, XtNshown, &size, XtNtopOfThumb, &val, 0);
+	if(pos<0) val-=.1;  else val+=.1;
+	qual=(int)(val*100.);  if(qual<1) qual=1;  if(qual>100) qual=100;
+	XawScrollbarSetThumb(w, val, 0.);
+	appData.qualityLevel=qual;
+	UpdateQual();
+#endif
+	if (w || client || p) {}
+}
+
+void qualJumpProc(Widget w, XtPointer client, XtPointer p) {
+#ifdef TURBOVNC
+	float val=*(float *)p;  int qual;
+	qual=(int)(val*100.);  if(qual<1) qual=1;  if(qual>100) qual=100;
+	appData.qualityLevel=qual;
+	UpdateQual();
+#endif
+	if (w || client || p) {}
+}
+
+void UpdateSubsampButtons(void) {
+#ifdef TURBOVNC
+	int i;
+	for (i=7; i <= 10; i++) {
+		XtVaSetValues(turboButtons[i], XtNstate, 0, NULL);
+	}
+	if (appData.subsampLevel==TVNC_1X) {
+		i = 7;
+	} else if (appData.subsampLevel==TVNC_2X) {
+		i = 8;
+	} else if (appData.subsampLevel==TVNC_4X) {
+		i = 9;
+	} else if (appData.subsampLevel==TVNC_GRAY) {
+		i = 10;
+	} else {
+		return;
+	}
+	XtVaSetValues(turboButtons[i], XtNstate, 1, NULL);
+#endif
+}
+
+void
+ShowTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	UpdateSubsampButtons(); 
+	UpdateQualSlider();
+	if (appData.popupFix) {
+		popupFixer(turbovncW);
+	} else {
+		XtMoveWidget(turbovncW, event->xbutton.x_root, event->xbutton.y_root);
+		XtPopup(turbovncW, XtGrabNone);
+	}
+	if (appData.grabAll) {
+		XRaiseWindow(dpy, XtWindow(turbovncW));
+	}
+	XSetWMProtocols(dpy, XtWindow(turbovncW), &wmDeleteWindow, 1);
+	XtOverrideTranslations(turbovncW, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideTurboVNC()"));
+	if (w || event || params || num_params) {}
+}
+
+void
+HideTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  XtPopdown(turbovncW);
+	if (w || event || params || num_params) {}
+}
+
+void
+CreateTurboVNC() {
+	Widget buttonForm, button, prevButton = NULL;
+	Widget label;
+	int i;
+	char buttonName[32];
+	String buttonType;
+
+	turbovncW = XtVaCreatePopupShell("turboVNC", transientShellWidgetClass, toplevel, NULL);
+
+	buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, turbovncW, NULL);
+
+	for (i = 0; i <= 12; i++) {
+		sprintf(buttonName, "button%d", i);
+#ifndef TURBOVNC
+		if (i == 0) {
+			sprintf(buttonName, "buttonNone");
+		} else if (i > 0) {
+			return;
+		}
+#endif
+		XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName,
+				"Button", resources, 1, NULL);
+
+		button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass,
+					       buttonForm, NULL);
+		turboButtons[i] = button;
+		XtVaSetValues(button, XtNfromVert, prevButton,
+			    XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
+		prevButton = button;
+	}
+
+	label = XtCreateManagedWidget("qualLabel", toggleWidgetClass, buttonForm, NULL, 0);
+	XtVaSetValues(label, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
+
+	qualslider = XtCreateManagedWidget("qualBar", scrollbarWidgetClass, buttonForm, NULL, 0);
+	XtVaSetValues(qualslider, XtNfromVert, label, XtNleft, XawChainLeft, NULL);
+	XtAddCallback(qualslider, XtNscrollProc, qualScrollProc, NULL) ;
+	XtAddCallback(qualslider, XtNjumpProc, qualJumpProc, NULL) ;
+
+	qualtext = XtCreateManagedWidget("qualText", labelWidgetClass, buttonForm, NULL, 0);
+	XtVaSetValues(qualtext, XtNfromVert, label, XtNfromHoriz, qualslider, XtNright, XawChainRight, NULL);
+}
+
+Widget qualityW;
+
+void
+ShowQuality(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  if (appData.popupFix) {
+	popupFixer(qualityW);
+  } else {
+	XtMoveWidget(qualityW, event->xbutton.x_root, event->xbutton.y_root);
+  	XtPopup(qualityW, XtGrabNone);
+  }
+  if (appData.grabAll) {
+  	XRaiseWindow(dpy, XtWindow(qualityW));
+  }
+  XSetWMProtocols(dpy, XtWindow(qualityW), &wmDeleteWindow, 1);
+  XtOverrideTranslations(qualityW, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideQuality()"));
+	if (w || event || params || num_params) {}
+}
+
+void
+HideQuality(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  XtPopdown(qualityW);
+	if (w || event || params || num_params) {}
+}
+
+
+void
+CreateQuality()
+{
+  Widget buttonForm, button, prevButton = NULL;
+  int i;
+  char buttonName[32];
+  String buttonType;
+
+  qualityW = XtVaCreatePopupShell("quality", transientShellWidgetClass, toplevel,
+			       NULL);
+
+  buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, qualityW,
+				       NULL);
+
+  for (i = -1; i <= 9; i++) {
+    if (i < 0) {
+	sprintf(buttonName, "buttonD");
+    } else {
+	sprintf(buttonName, "button%d", i);
+    }
+    XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName,
+			"Button", resources, 1, NULL);
+
+    button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass,
 				       buttonForm, NULL);
-      XtVaSetValues(button, XtNfromVert, prevButton,
+    XtVaSetValues(button, XtNfromVert, prevButton,
 		    XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
+    prevButton = button;
+  }
+}
+
+Widget compressW;
+
+void
+ShowCompress(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  if (appData.popupFix) {
+	popupFixer(compressW);
+  } else {
+	XtMoveWidget(compressW, event->xbutton.x_root, event->xbutton.y_root);
+  	XtPopup(compressW, XtGrabNone);
+  }
+  if (appData.grabAll) {
+  	XRaiseWindow(dpy, XtWindow(compressW));
+  }
+  XSetWMProtocols(dpy, XtWindow(compressW), &wmDeleteWindow, 1);
+  XtOverrideTranslations(compressW, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideCompress()"));
+	if (w || event || params || num_params) {}
+}
+
+void
+HideCompress(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+  XtPopdown(compressW);
+	if (w || event || params || num_params) {}
+}
+
+
+void
+CreateCompress()
+{
+  Widget buttonForm, button, prevButton = NULL;
+  int i;
+  char buttonName[32];
+  String buttonType;
+
+  compressW = XtVaCreatePopupShell("compress", transientShellWidgetClass, toplevel,
+			       NULL);
+
+  buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, compressW,
+				       NULL);
+
+  for (i = -1; i <= 9; i++) {
+    if (i < 0) {
+	sprintf(buttonName, "buttonD");
     } else {
-      fprintf(stderr,"unknown button type '%s'\n",buttonType);
+	sprintf(buttonName, "button%d", i);
     }
+    XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName,
+			"Button", resources, 1, NULL);
+
+    button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass,
+				       buttonForm, NULL);
+    XtVaSetValues(button, XtNfromVert, prevButton,
+		    XtNleft, XawChainLeft, XtNright, XawChainRight, NULL);
     prevButton = button;
   }
 }
+
+
+int filexfer_sock = -1;
+int filexfer_listen = -1;
+
+void HideFile(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	if (filexfer_sock >= 0) {
+		close(filexfer_sock);
+		filexfer_sock = -1;
+	}
+	if (filexfer_listen >= 0) {
+		close(filexfer_listen);
+		filexfer_listen = -1;
+	}
+	if (w || event || params || num_params) {}
+}
+
+extern int use_loopback;
+time_t start_listen = 0;
+pid_t java_helper = 0;
+
+void ShowFile(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	int i, port0 = 7200, port, sock = -1;
+	char *cmd, *jar;
+	char fmt[] = "java -cp '%s' VncViewer HOST localhost PORT %d delayAuthPanel yes ignoreMSLogonCheck yes disableSSL yes ftpOnly yes graftFtp yes dsmActive no  &";
+
+	if (getenv("SSVNC_ULTRA_FTP_JAR")) {
+		jar = getenv("SSVNC_ULTRA_FTP_JAR");
+		cmd = (char *) malloc(strlen(fmt) + strlen(jar) + 100);
+	} else {
+		fprintf(stderr, "Cannot find UltraVNC FTP jar file.\n");
+		return;
+	}
+
+	use_loopback = 1;
+	for (i = 0; i < 100; i++) {
+		port = port0 + i;
+		sock = ListenAtTcpPort(port);
+		if (sock < 0) {
+			sock = ListenAtTcpPort6(port);
+		}
+		if (sock >= 0) {
+			fprintf(stderr, "listening for filexfer on port: %d sock: %d\n", port, sock);
+			break;
+		}
+	}
+	use_loopback = 0;
+
+	if (sock >= 0) {
+		int st;
+		pid_t pid = fork();
+		if (pid < 0) {
+			free(cmd);
+			return;
+		} else if (pid == 0) {
+			int i;
+			sprintf(cmd, fmt, jar, port);
+			if (appData.ultraDSM) {
+				char *q = strstr(cmd, "dsmActive");
+				if (q) {
+					q = strstr(q, "no ");
+					if (q) {
+						q[0] = 'y';
+						q[1] = 'e';
+						q[2] = 's';
+					}
+				}
+			}
+			for (i = 3; i < 100; i++) {
+				close(i);
+			}
+			fprintf(stderr, "\n-- Experimental UltraVNC File Transfer --\n\nRunning cmd:\n\n  %s\n\n", cmd);
+			system(cmd);
+			exit(0);
+		}
+		fprintf(stderr, "java helper pid is: %d\n", (int) pid);
+		waitpid(pid, &st, 0);
+		java_helper = pid;
+		start_listen = time(NULL);
+	}
+	free(cmd);
+	filexfer_listen = sock;
+	if (w || event || params || num_params) {}
+}
+
+Widget chat, entry, text;
+
+static int chat_visible = 0;
+
+void
+ShowChat(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+	if (appData.termChat) {
+		return;
+	}
+	if (! chat_visible) {
+		XtPopup(chat, XtGrabNone);
+		chat_visible = 1;
+		wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+		XSetWMProtocols(dpy, XtWindow(chat), &wmDeleteWindow, 1);
+		if (appData.chatOnly) {
+			XtOverrideTranslations(chat, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
+		} else {
+			XtOverrideTranslations(chat, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideChat()"));
+		}
+		XSync(dpy, False);
+		usleep(200 * 1000);
+	}
+	if (w || event || params || num_params) {}
+}
+
+void hidechat(void) {
+	appData.chatActive = False;
+	if (appData.termChat) {
+		return;
+	}
+	if (chat_visible) {
+		XtPopdown(chat);
+		chat_visible = 0;
+		XSync(dpy, False);
+		usleep(200 * 1000);
+	}
+	if (appData.chatOnly) {
+		Quit(0, NULL, NULL, NULL);
+	}
+}
+
+void HideChat(Widget w, XEvent *event, String *params, Cardinal *num_params) {
+	SendTextChatClose();
+	SendTextChatFinished();
+	hidechat();
+	if (w || event || params || num_params) {}
+}
+
+void dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) {
+	SendTextChatClose();
+	SendTextChatFinished();
+	hidechat();
+	if (w || client_data || call_data) {}
+}
+
+extern void printChat(char *, Bool);
+
+static void ChatTextCallback(XtPointer clientData, XtIntervalId *id);
+static XtIntervalId timer;
+static Bool timerSet = False;
+
+void CheckTextInput(void);
+extern double start_time;
+
+static void ChatTextCallback(XtPointer clientData, XtIntervalId *id) {
+	static int db = -1;
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_CHAT")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+	if (db) fprintf(stderr, "ChatTextCallback: %.4f\n", dnow() - start_time);
+	CheckTextInput();
+	if (clientData || id) {}
+}
+
+void CheckTextInput(void) {
+	Arg args[2];
+	String str;
+	int len;
+	static int db = -1;
+
+	if (timerSet) {
+		XtRemoveTimeOut(timer);
+		timerSet = False;
+	}
+	if (appData.chatActive) {
+		timer = XtAppAddTimeOut(appContext, 333, ChatTextCallback, NULL);
+		timerSet = True;
+	}
+	if (appData.chatOnly && !appData.chatActive) {
+		Quit(0, NULL, NULL, NULL);
+	}
+
+	if (appData.termChat) {
+		return;
+	}
+#if 0
+	if (!appData.chatActive) {
+		return;
+	}
+#endif
+
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_CHAT")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+
+	XtSetArg(args[0], XtNstring, &str);
+	XtGetValues(entry, args, 1);
+
+	if (db) fprintf(stderr, "CheckTextInput\n");
+
+	if (str == NULL || str[0] == '\0') {
+		return;
+	} else {
+		char *q;
+		len = strlen(str);
+		if (db) fprintf(stderr, "CheckTextInput: len: %d  '%s'\n", len, str);
+		if (len <= 0) {
+			return;
+		}
+		q = strrchr(str, '\n'); 
+		if (q) {
+			char *send, save[2];
+			save[0] = *(q+1);
+			*(q+1) = '\0';
+			send = strdup(str);
+			*(q+1) = save[0];
+			if (send) {
+				SendTextChat(send);
+				printChat("Send: ", True);
+				printChat(send, True);
+				free(send);
+				if (save[0] == '\0') {
+					XtVaSetValues(entry, XtNtype, XawAsciiString, XtNstring, "", NULL);
+				} else {
+					char *leak = strdup(q+1);
+					XtVaSetValues(entry, XtNtype, XawAsciiString, XtNstring, leak, NULL);
+					if (strlen(leak) > 0) {
+						XSync(dpy, False);
+						XtVaSetValues(entry, XtNinsertPosition, strlen(leak), NULL);
+					}
+				}
+			}
+		}
+	}
+}
+
+void AppendChatInput0(char *in) {
+	Arg args[10];
+	int n;
+	String str;
+	int len;
+	static char *s = NULL;
+	static int slen = -1;
+	XawTextPosition pos;
+
+	fprintf(stderr, "AppendChatInput: in= '%s'\n", in);
+
+	XtSetArg(args[0], XtNstring, &str);
+	XtGetValues(text, args, 1);
+	fprintf(stderr, "AppendChatInput: str='%s'\n", str);
+	
+	len = strlen(str) + strlen(in);
+
+	if (slen <= len) {
+		slen = 2 * (len + 10);
+		if (s) free(s);
+		s = (char *) malloc(slen+1);
+	}
+	
+	s[0] = '\0';
+	strcat(s, str);
+	strcat(s, in);
+	fprintf(stderr, "AppendChatInput s=  '%s'\n", s);
+	pos = (XawTextPosition) (len-1);
+	n = 0;
+	XtSetArg(args[n], XtNtype, XawAsciiString);	n++;
+	XtSetArg(args[n], XtNstring, s);		n++;
+	XtSetArg(args[n], XtNdisplayPosition, pos);	n++;
+	XtSetArg(args[n], XtNinsertPosition, pos);	n++;
+	XtSetValues(text, args, n);
+	fprintf(stderr, "AppendChatInput done\n");
+}
+
+void AppendChatInput(char *in) {
+	XawTextPosition beg, end;
+	static XawTextPosition pos = 0;
+	XawTextBlock txt;
+
+	if (appData.termChat) {
+		return;
+	}
+
+	XawTextSetInsertionPoint(text, pos);
+	beg = XawTextGetInsertionPoint(text);
+	end = beg;
+#if 0
+	fprintf(stderr, "AppendChatInput: pos=%d in= '%s'\n", beg, in);
+#endif
+
+	txt.firstPos = 0;
+	txt.length = strlen(in);
+	txt.ptr = in;
+	txt.format = FMT8BIT;
+
+	XawTextReplace(text, beg, end, &txt);
+	XawTextSetInsertionPoint(text, beg + txt.length);
+
+	pos = XawTextGetInsertionPoint(text);
+#if 0
+	fprintf(stderr, "AppendChatInput done pos=%d\n", pos);
+#endif
+}
+
+#if 0
+static char errorbuf[1] = {0};
+#endif
+
+void CreateChat(void) {
+
+	Widget myform, dismiss;
+	Dimension w = 400, h = 300;
+
+	chat = XtVaCreatePopupShell("chat", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL);
+
+	myform = XtVaCreateManagedWidget("myform", formWidgetClass, chat, NULL);
+
+	text = XtVaCreateManagedWidget("text", asciiTextWidgetClass, myform,
+	    XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord,
+	    XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways,
+	    XtNwidth, w, XtNheight, h, XtNdisplayCaret, False,
+	    XtNeditType, XawtextAppend, XtNtype, XawAsciiString,
+	    XtNuseStringInPlace, False, NULL);
+
+	entry = XtVaCreateManagedWidget("entry", asciiTextWidgetClass, myform,
+	    XtNresize, XawtextResizeWidth, XtNresizable, True, XtNwrap, XawtextWrapNever,
+	    XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollNever,
+	    XtNheight, 20, XtNwidth, 400, XtNfromVert, text, XtNeditType, XawtextEdit,
+	    XtNdisplayCaret, True, XtNeditType, XawtextEdit, NULL);
+
+	dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Close Chat", XtNfromVert, entry, NULL);
+
+	AppendChatInput("");
+
+	XtAddCallback(dismiss, XtNcallback, dismiss_proc, NULL);
+
+	XtRealizeWidget(chat);
+
+	XtSetKeyboardFocus(chat, entry); 
+}
+
+Widget msgwin, msgtext;
+
+void AppendMsg(char *in) {
+	XawTextPosition beg, end;
+	static XawTextPosition pos = 0;
+	XawTextBlock txt;
+
+	XawTextSetInsertionPoint(msgtext, pos);
+	beg = XawTextGetInsertionPoint(msgtext);
+	end = beg;
+
+	txt.firstPos = 0;
+	txt.length = strlen(in);
+	txt.ptr = in;
+	txt.format = FMT8BIT;
+
+	XawTextReplace(msgtext, beg, end, &txt);
+	XawTextSetInsertionPoint(msgtext, beg + txt.length);
+
+	pos = XawTextGetInsertionPoint(msgtext);
+}
+
+static int msg_visible = 0;
+static int msg_NO_clicked = 0;
+
+void msg_dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) {
+	XtPopdown(msgwin);
+	msg_visible = 0;
+	XSync(dpy, False);
+	usleep(200 * 1000);
+	if (w || client_data || call_data) {}
+}
+
+void msg_NO_proc(Widget w, XtPointer client_data, XtPointer call_data) {
+	XtPopdown(msgwin);
+	msg_visible = 0;
+	msg_NO_clicked = 1;
+	XSync(dpy, False);
+	usleep(200 * 1000);
+	if (w || client_data || call_data) {}
+}
+
+int CreateMsg(char *msg, int wait) {
+
+	Widget myform, dismiss, reject;
+	char *p;
+	int n, run, wmax = 0;
+	int ret = 1;
+	Dimension w, h;
+
+
+	n = 0;
+	run = 0;
+	p = msg;
+	while (*p != '\0') {
+		if (*p == '\n') {
+			run = 0;
+			n++;
+		}
+		run++;
+		if (run > wmax) wmax = run;
+		p++;
+	}
+	if (wmax > 80) {
+		if (wmax > 120) n++;
+		if (wmax > 80) n++;
+		wmax = 80;
+	}
+	h = (Dimension) (n+2) * 14;
+	w = (Dimension) (wmax+10) * 8;
+
+	msgwin = XtVaCreatePopupShell("Message", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL);
+
+	myform = XtVaCreateManagedWidget("myform", formWidgetClass, msgwin, NULL);
+
+	msgtext = XtVaCreateManagedWidget("msgtext", asciiTextWidgetClass, myform,
+	    XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord,
+	    XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways,
+	    XtNwidth, w, XtNheight, h, XtNdisplayCaret, False,
+	    XtNeditType, XawtextAppend, XtNtype, XawAsciiString,
+	    XtNuseStringInPlace, False, NULL);
+
+	if (wait == 2) {
+		msg_NO_clicked = 0;
+
+		dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Accept", XtNfromVert, msgtext, NULL);
+		XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL);
+
+		reject = XtVaCreateManagedWidget("reject", commandWidgetClass, myform, XtNlabel, "Reject", XtNfromVert, dismiss, NULL);
+		XtAddCallback(reject, XtNcallback, msg_NO_proc, NULL);
+	} else {
+		dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "OK", XtNfromVert, msgtext, NULL);
+		XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL);
+		
+	}
+
+	AppendMsg("");
+	AppendMsg(msg);
+
+	XtRealizeWidget(msgwin);
+
+	XtPopup(msgwin, XtGrabNone);
+
+	XSync(dpy, False);
+	msg_visible = 1;
+	while (wait && msg_visible) {
+		if (0) fprintf(stderr, "mv: %d\n", msg_visible);
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+	if (wait == 2) {
+		if (msg_NO_clicked) {
+			ret = 0;
+		} else {
+			ret = 1;
+		}
+	}
+	return ret;
+}
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup_ad vnc_unixsrc/vncviewer/popup_ad
--- vnc_unixsrc.orig/vncviewer/popup_ad	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/popup_ad	2008-02-17 13:32:34.000000000 -0500
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+
+$ok = 0;
+
+open(A, "<argsresources.c") || die;
+
+while (<A>) {
+	if (/popupButtonCount:/) {
+		$on = 1;
+	} elsif (/^\s*NULL/) {
+		$on = 0;
+	}
+	next unless $on;
+	chomp;
+	last if /NULL/;
+	$_ =~ s/^\s*"//;
+	$_ =~ s/",//;
+	$_ .= "\n" unless $_ =~ /\n/;
+	print;
+}
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncviewer/rfbproto.c
--- vnc_unixsrc.orig/vncviewer/rfbproto.c	2008-09-05 19:51:24.000000000 -0400
+++ vnc_unixsrc/vncviewer/rfbproto.c	2010-04-17 22:34:38.000000000 -0400
@@ -23,7 +23,10 @@
  * rfbproto.c - functions to deal with client side of RFB protocol.
  */
 
+#include <sys/stat.h>
 #include <unistd.h>
+#include <time.h>
+#include <ctype.h>
 #include <errno.h>
 #include <pwd.h>
 #include <vncviewer.h>
@@ -31,6 +34,9 @@
 #include <zlib.h>
 #include <jpeglib.h>
 
+int server_major = 0, server_minor = 0;
+int viewer_major = 0, viewer_minor = 0;
+
 static void InitCapabilities(void);
 static Bool SetupTunneling(void);
 static int ReadSecurityType(void);
@@ -57,6 +63,47 @@
 static Bool HandleTight16(int rx, int ry, int rw, int rh);
 static Bool HandleTight32(int rx, int ry, int rw, int rh);
 
+/* runge add zrle */
+static Bool HandleZRLE8(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE15(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE16(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE24(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE24Up(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE24Down(int rx, int ry, int rw, int rh);
+static Bool HandleZRLE32(int rx, int ry, int rw, int rh);
+
+extern Bool HandleCursorPos(int x, int y);
+extern void printChat(char *, Bool);
+
+typedef struct {
+    unsigned long length;
+} rfbZRLEHeader;
+
+#define sz_rfbZRLEHeader 4
+
+#define rfbZRLETileWidth 64
+#define rfbZRLETileHeight 64
+
+#define DO_ZYWRLE 1
+
+#if DO_ZYWRLE
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+
+static const int bitsPerPackedPixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+int zywrle_level;
+int zywrleBuf[rfbZRLETileWidth*rfbZRLETileHeight];
+
+#include "zrlepalettehelper.h"
+static zrlePaletteHelper paletteHelper;
+
+#endif /* ZRLE_ONCE */
+#endif /* DO_ZYWRLE */
+
 static void ReadConnFailedReason(void);
 static long ReadCompactLen (void);
 
@@ -67,6 +114,25 @@
 static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
                               int compressedLen);
 
+extern void deskey(unsigned char *, int);
+extern void des(unsigned char *, unsigned char *);
+
+extern int currentMsg;
+extern double scale_factor_x;
+extern double scale_factor_y;
+
+extern int skip_maybe_sync;
+
+int sent_FBU = 0;
+int skip_XtUpdate = 0;
+int skip_XtUpdateAll = 0;
+
+static double dt_out = 0.0;
+static double dt_out_sc = 0.0;
+double latency = 0.0;
+double connect_time = 0.0;
+
+void raiseme(int force);
 
 int rfbsock;
 char *desktopName;
@@ -75,6 +141,14 @@
 char *serverCutText = NULL;
 Bool newServerCutText = False;
 
+/* ultravnc mslogon */
+#define rfbUltraVncMsLogon 0xfffffffa
+static Bool AuthUltraVncMsLogon(void);
+extern void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd);
+extern void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key);
+extern void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key);
+extern unsigned int urandom(void);
+
 int endianTest = 1;
 
 static Bool tightVncProtocol = False;
@@ -177,8 +251,26 @@
 	  sig_rfbEncodingPointerPos, "Pointer position update");
   CapsAdd(encodingCaps, rfbEncodingLastRect, rfbTightVncVendor,
 	  sig_rfbEncodingLastRect, "LastRect protocol extension");
+
+  CapsAdd(encodingCaps, rfbEncodingNewFBSize, rfbTightVncVendor,
+	  sig_rfbEncodingNewFBSize, "New FB size protocol extension");
+
+#ifdef TURBOVNC
+  CapsAdd(encodingCaps, rfbJpegQualityLevel1, rfbTurboVncVendor,
+	  sig_rfbEncodingNewFBSize, "TurboJPEG quality level");
+  CapsAdd(encodingCaps, rfbJpegSubsamp1X, rfbTurboVncVendor,
+	  sig_rfbEncodingNewFBSize, "TurboJPEG subsampling level");
+#endif
 }
 
+static char msgbuf[10000];
+
+static void wmsg(char *msg, int wait) {
+	fprintf(stderr, "%s", msg);
+	if (!use_tty() && !getenv("SSVNC_NO_MESSAGE_POPUP")) {
+		CreateMsg(msg, wait);
+	}
+}
 
 /*
  * ConnectToRFBServer.
@@ -187,24 +279,179 @@
 Bool
 ConnectToRFBServer(const char *hostname, int port)
 {
-  unsigned int host;
-
-  if (!StringToIPAddr(hostname, &host)) {
-    fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
-    return False;
-  }
+	char *q, *cmd = NULL;
+	Bool setnb;
+	struct stat sb;
+
+	if (strstr(hostname, "exec=") == hostname) {
+		cmd = strdup(hostname);
+		q = strchr(cmd, '=');
+		*q = ' ';
+		if (getenv("SSVNC_BASEDIR")) {
+			char *base = getenv("SSVNC_BASEDIR");
+			char *newcmd = (char *)malloc(strlen(base) + strlen(cmd) + 1000);	
+			sprintf(newcmd, "%s/unwrap.so", base);
+			if (stat(newcmd, &sb) == 0) {
+#if (defined(__MACH__) && defined(__APPLE__))
+				sprintf(newcmd, "DYLD_FORCE_FLAT_NAMESPACE=1; export DYLD_FORCE_FLAT_NAMESPACE; DYLD_INSERT_LIBRARIES='%s/unwrap.so'; export DYLD_INSERT_LIBRARIES; %s", base, cmd);
+#else
+				sprintf(newcmd, "LD_PRELOAD='%s/unwrap.so'; export LD_PRELOAD; %s", base, cmd);
+#endif
+				cmd = newcmd;
+			}
+		}
+	}
 
-  rfbsock = ConnectToTcpAddr(host, port);
+	if (cmd != NULL) {
+		int sfd[2];
+		char *q, *cmd2 = strdup(cmd);
+		pid_t pid;
+
+		q = strstr(cmd2, "pw=");
+		if (q && !getenv("SSVNC_SHOW_ULTRAVNC_DSM_PASSWORD")) {
+			q += strlen("pw=");
+			while (*q != '\0' && !isspace(*q)) {
+				*q = '*';
+				q++;
+			}
+		}
+
+		fprintf(stderr, "exec-cmd: %s\n\n", cmd2);
+		free(cmd2);
+
+		if (! SocketPair(sfd)) {
+			return False;
+		}
+		if (0) {
+			fprintf(stderr, "sfd: %d %d\n", sfd[0], sfd[1]);
+			fflush(stderr);
+		}
+
+		pid = fork();
+		if (pid == -1) {
+			perror("fork");
+			return False;
+		}
+		if (pid == 0) {
+			char *args[4];
+			int d;
+			args[0] = "/bin/sh";
+			args[1] = "-c";
+			args[2] = cmd;
+			args[3] = NULL;
+
+			close(sfd[1]);
+			dup2(sfd[0], 0);
+			dup2(sfd[0], 1);
+			for (d=3; d < 256; d++) {
+				if (d != sfd[0]) {
+					close(d);
+				}
+			}
+			execvp(args[0], args);
+			perror("exec");
+			exit(1);
+		} else {
+			close(sfd[0]);
+			rfbsock = sfd[1];
+		}
+		if (rfbsock < 0) {
+			sprintf(msgbuf,"Unable to connect to exec'd command: %s\n", cmd);
+			wmsg(msgbuf, 1);
+			return False;
+		}
+	} else if (strstr(hostname, "fd=") == hostname) {
+		rfbsock = atoi(hostname + strlen("fd="));
+	} else if (strchr(hostname, '/') && stat(hostname, &sb) == 0) {
+		/* assume unix domain socket */
+		char *thost = strdup(hostname); 
+
+		rfbsock = ConnectToUnixSocket(thost);
+		free(thost);
+
+		if (rfbsock < 0) {
+			sprintf(msgbuf,"Unable to connect to VNC server (unix-domain socket: %s)\n", hostname);
+			wmsg(msgbuf, 1);
+			return False;
+		}
+		
+	} else {
+		rfbsock = ConnectToTcpAddr(hostname, port);
+
+		if (rfbsock < 0 && !appData.noipv4) {
+			char *q, *hosttmp;
+			if (hostname[0] == '[') {
+				hosttmp = strdup(hostname+1);
+			} else {
+				hosttmp = strdup(hostname);
+			}
+			q = strrchr(hosttmp, ']');
+			if (q) *q = '\0';
+			if (strstr(hosttmp, "::ffff:") == hosttmp || strstr(hosttmp, "::FFFF:") == hosttmp) {
+				char *host = hosttmp + strlen("::ffff:");
+				if (dotted_ip(host, 0))  {
+					fprintf(stderr, "ConnectToTcpAddr[ipv4]: re-trying connection using '%s'\n", host);
+					rfbsock = ConnectToTcpAddr(host, port);
+				}
+			}
+			free(hosttmp);
+		}
+
+		if (rfbsock < 0) {
+			sprintf(msgbuf,"Unable to connect to VNC server (%s:%d)\n", hostname, port);
+			wmsg(msgbuf, 1);
+			return False;
+		}
+	}
 
-  if (rfbsock < 0) {
-    fprintf(stderr,"Unable to connect to VNC server\n");
-    return False;
-  }
+	setnb = SetNonBlocking(rfbsock);
+	return setnb;
+}
 
-  return SetNonBlocking(rfbsock);
+static void printFailureReason(void) {
+	CARD32 reasonLen;
+	ReadFromRFBServer((char *)&reasonLen, 4);
+	reasonLen = Swap32IfLE(reasonLen);
+	if (reasonLen < 4096) {
+		char *reason = (char *) malloc(reasonLen+1);
+		memset(reason, 0, reasonLen+1);
+		ReadFromRFBServer(reason, reasonLen);
+		sprintf(msgbuf, "Reason: %s\n", reason);
+		wmsg(msgbuf, 1);
+		free(reason);
+	}
 }
 
+static char *pr_sec_type(int type) {
+	char *str = "unknown";
+	if (type == rfbSecTypeInvalid) str = "rfbSecTypeInvalid";
+	if (type == rfbSecTypeNone) str = "rfbSecTypeNone";
+	if (type == rfbSecTypeVncAuth) str = "rfbSecTypeVncAuth";
+	if (type == rfbSecTypeRA2) str = "rfbSecTypeRA2";
+	if (type == rfbSecTypeRA2ne) str = "rfbSecTypeRA2ne";
+	if (type == rfbSecTypeTight) str = "rfbSecTypeTight";
+	if (type == rfbSecTypeUltra) str = "rfbSecTypeUltra";
+
+	if (type == rfbSecTypeAnonTls) str = "rfbSecTypeAnonTls";
+	if (type == rfbSecTypeVencrypt) str = "rfbSecTypeVencrypt";
+
+	if (type == (int) rfbUltraVncMsLogon) str = "rfbUltraVncMsLogon";
+	return str;
+}
+
+static char *pr_sec_subtype(int type) {
+	char *str = "unknown";
+	if (type == rfbVencryptPlain) str = "rfbVencryptPlain";
+	if (type == rfbVencryptTlsNone) str = "rfbVencryptTlsNone";
+	if (type == rfbVencryptTlsVnc) str = "rfbVencryptTlsVnc";
+	if (type == rfbVencryptTlsPlain) str = "rfbVencryptTlsPlain";
+	if (type == rfbVencryptX509None) str = "rfbVencryptX509None";
+	if (type == rfbVencryptX509Vnc) str = "rfbVencryptX509Vnc";
+	if (type == rfbVencryptX509Plain) str = "rfbVencryptX509Plain";
+	return str;
+}
 
+extern void ProcessXtEvents(void);
 /*
  * InitialiseRFBConnection.
  */
@@ -212,211 +459,654 @@
 Bool
 InitialiseRFBConnection(void)
 {
-  rfbProtocolVersionMsg pv;
-  int server_major, server_minor;
-  int viewer_major, viewer_minor;
-  rfbClientInitMsg ci;
-  int secType;
+	rfbProtocolVersionMsg pv;
+	rfbClientInitMsg ci;
+	int i, secType, anon_dh = 0, accept_uvnc = 0;
+	FILE *pd;
+	char *hsfile = NULL;
+	char *hsparam[128];
+	char *envsetsec = getenv("SSVNC_SET_SECURITY_TYPE");
+	char line[128];
+	double dt = 0.0;
 
-  /* if the connection is immediately closed, don't report anything, so
-       that pmw's monitor can make test connections */
+	/* if the connection is immediately closed, don't report anything, so
+	   that pmw's monitor can make test connections */
 
-  if (listenSpecified)
-    errorMessageOnReadFailure = False;
+	if (listenSpecified) {
+		errorMessageOnReadFailure = False;
+	}
 
-  if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg))
-    return False;
+	for (i=0; i < 128; i++) {
+		hsparam[i] = NULL;
+	}
 
-  errorMessageOnReadFailure = True;
+	skip_XtUpdateAll = 1;
+	ProcessXtEvents();
+	skip_XtUpdateAll = 0;
+
+	if (getenv("SSVNC_PREDIGESTED_HANDSHAKE")) {
+		double start = dnow();
+		hsfile = getenv("SSVNC_PREDIGESTED_HANDSHAKE");
+		while (dnow() < start + 10.0) {
+			int done = 0;
+			usleep(100 * 1000);
+			if ((pd = fopen(hsfile, "r")) != NULL) {
+				while (fgets(line, 128, pd) != NULL) {
+					if (strstr(line, "done") == line) {
+						done = 1;
+						usleep(100 * 1000);
+						break;
+					}
+				}
+				fclose(pd);
+			}
+			if (done) {
+				break;
+			}
+		}
+		if ((pd = fopen(hsfile, "r")) != NULL) {
+			i = 0;
+			while (fgets(line, 128, pd) != NULL) {
+				hsparam[i] = strdup(line);
+				fprintf(stderr, "%s", line);
+				if (i++ > 100) break; 
+			}
+			fclose(pd);
+		}
+		unlink(hsfile);
+	}
 
-  pv[sz_rfbProtocolVersionMsg] = 0;
+	if (getenv("SSVNC_SKIP_RFB_PROTOCOL_VERSION")) {
+		viewer_major = 3;
+		viewer_minor = 8;
+		goto end_of_proto_msg;
+	} else if (hsfile) {
+		int k = 0;
+		while (hsparam[k] != NULL) {
+			char *str = hsparam[k++];
+			if (strstr(str, "server=") == str) {
+				sprintf(pv, "%s", str + strlen("server="));
+				goto readed_pv;
+			}
+		}
+	}
 
-  if (sscanf(pv, rfbProtocolVersionFormat,
-	     &server_major, &server_minor) != 2) {
-    fprintf(stderr,"Not a valid VNC server\n");
-    return False;
-  }
+	dt = dnow();
+	if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) {
+		return False;
+	}
+	if (getenv("PRINT_DELAY1")) fprintf(stderr, "delay1: %.3f ms\n", (dnow() - dt) * 1000);
+	dt = 0.0;
 
-  viewer_major = rfbProtocolMajorVersion;
-  if (server_major == 3 && server_minor >= rfbProtocolMinorVersion) {
-    /* the server supports at least the standard protocol 3.7 */
-    viewer_minor = rfbProtocolMinorVersion;
-  } else {
-    /* any other server version, request the standard 3.3 */
-    viewer_minor = rfbProtocolFallbackMinorVersion;
-  }
+	readed_pv:
 
-  fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n",
-	  viewer_major, viewer_minor);
+	errorMessageOnReadFailure = True;
 
-  sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor);
+	pv[sz_rfbProtocolVersionMsg] = 0;
 
-  if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg))
-    return False;
+	if (strstr(pv, "ID:") == pv) {
+		;
+	} else if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) {
+		if (strstr(pv, "test") == pv) {
+			/* now some hacks for ultraVNC SC III (SSL) ... testA, etc */
+			int i;
+			char *se = NULL;
+
+			fprintf(stderr,"Trying UltraVNC Single Click III workaround: %s\n", pv);
+			for (i=0; i < 7 ; i++) {
+				pv[i] = pv[i+5];
+			}
+			if (!ReadFromRFBServer(pv+7, 5)) {
+				return False;
+			}
+
+			se = getenv("STUNNEL_EXTRA_OPTS");
+			if (se == NULL) {
+				se = getenv("STUNNEL_EXTRA_OPTS_USER");
+			}
+			if (se != NULL) {
+				if (strstr(se, "options")) {
+					if (strstr(se, "ALL") || strstr(se, "DONT_INSERT_EMPTY_FRAGMENTS")) {
+						;	/* good */
+					} else {
+						se = NULL;
+					}
+				} else {
+					se = NULL;
+				}
+			}
+			if (se == NULL) {
+				msgbuf[0] = '\0';
+				strcat(msgbuf, "\n");
+				strcat(msgbuf, "***************************************************************\n");
+				strcat(msgbuf, "To work around UltraVNC SC III SSL dropping after a few minutes\n");
+				strcat(msgbuf, "you may need to set STUNNEL_EXTRA_OPTS_USER='options = ALL'.\n");
+				strcat(msgbuf, "***************************************************************\n");
+				strcat(msgbuf, "\n");
+				wmsg(msgbuf, 0);
+			}
+			if (strstr(pv, "ID:") == pv) {
+				goto check_ID_string;
+			}
+			if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) == 2) {
+				goto ultra_vnc_nonsense;
+			}
+		}
+		sprintf(msgbuf, "Not a valid VNC server: '%s'\n", pv);
+		wmsg(msgbuf, 1);
+		return False;
+	}
 
-  /* Read or select the security type. */
-  if (viewer_minor == rfbProtocolMinorVersion) {
-    secType = SelectSecurityType();
-  } else {
-    secType = ReadSecurityType();
-  }
-  if (secType == rfbSecTypeInvalid)
-    return False;
+	check_ID_string:
+	if (strstr(pv, "ID:") == pv) {
+		char tmp[256];
+		fprintf(stderr, "UltraVNC Repeater string detected: %s\n", pv);
+		fprintf(stderr, "Pretending to be UltraVNC repeater: reading 250 bytes...\n\n");
+		if (!ReadFromRFBServer(tmp, 250 - 12)) {
+			return False;
+		}
+		if (!ReadFromRFBServer(pv, 12)) {
+			return False;
+		}
+		if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) {
+			sprintf(msgbuf,"Not a valid VNC server: '%s'\n", pv);
+			wmsg(msgbuf, 1);
+			return False;
+		}
+	}
 
-  switch (secType) {
-  case rfbSecTypeNone:
-    fprintf(stderr, "No authentication needed\n");
-    break;
-  case rfbSecTypeVncAuth:
-    if (!AuthenticateVNC())
-      return False;
-    break;
-  case rfbSecTypeTight:
-    tightVncProtocol = True;
-    InitCapabilities();
-    if (!SetupTunneling())
-      return False;
-    if (!PerformAuthenticationTight())
-      return False;
-    break;
-  default:                      /* should never happen */
-    fprintf(stderr, "Internal error: Invalid security type\n");
-    return False;
-  }
+	ultra_vnc_nonsense:
+	fprintf(stderr,"\nProto: %s\n", pv);
 
-  ci.shared = (appData.shareDesktop ? 1 : 0);
+	viewer_major = 3;
 
-  if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg))
-    return False;
+	if (appData.rfbVersion != NULL && sscanf(appData.rfbVersion, "%d.%d", &viewer_major, &viewer_minor) == 2) {
+		fprintf(stderr,"Setting RFB version to %d.%d from -rfbversion.\n\n", viewer_major, viewer_minor);
 
-  if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg))
-    return False;
+	} else if (getenv("SSVNC_RFB_VERSION") != NULL && sscanf(getenv("SSVNC_RFB_VERSION"), "%d.%d", &viewer_major, &viewer_minor) == 2) {
+		fprintf(stderr,"Setting RFB version to %d.%d from SSVNC_RFB_VERSION.\n\n", viewer_major, viewer_minor);
+
+	} else if (server_major > 3) {
+		viewer_minor = 8;
+	} else if (server_major == 3 && (server_minor == 14 || server_minor == 16)) {
+		/* hack for UltraVNC Single Click. They misuse rfb proto version */
+		fprintf(stderr,"Setting RFB version to 3.3 for UltraVNC Single Click.\n\n");
+		viewer_minor = 3;
+
+	} else if (server_major == 3 && server_minor >= 8) {
+		/* the server supports at least the standard protocol 3.8 */
+		viewer_minor = 8;
+
+	} else if (server_major == 3 && server_minor == 7) {
+		/* the server supports at least the standard protocol 3.7 */
+		viewer_minor = 7;
+
+	} else {
+		/* any other server version, request the standard 3.3 */
+		viewer_minor = 3;
+	}
+	/* n.b. Apple Remote Desktop uses 003.889, but we should be OK with 3.8 */
 
-  si.framebufferWidth = Swap16IfLE(si.framebufferWidth);
-  si.framebufferHeight = Swap16IfLE(si.framebufferHeight);
-  si.format.redMax = Swap16IfLE(si.format.redMax);
-  si.format.greenMax = Swap16IfLE(si.format.greenMax);
-  si.format.blueMax = Swap16IfLE(si.format.blueMax);
-  si.nameLength = Swap32IfLE(si.nameLength);
-
-  /* FIXME: Check arguments to malloc() calls. */
-  desktopName = malloc(si.nameLength + 1);
-  if (!desktopName) {
-    fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
-            (unsigned long)si.nameLength);
-    return False;
-  }
+	if (appData.msLogon) {
+		if (server_minor == 4) {
+			fprintf(stderr,"Setting RFB version to 3.4 for UltraVNC MS Logon.\n\n");
+			viewer_minor = 4;
+		}
+	}
+	if (getenv("SSVNC_ACCEPT_POPUP_SC")) {
+		if (server_minor == -4 || server_minor == -6 || server_minor == 14 || server_minor == 16) {
+			/* 4 and 6 work too? */
+			viewer_minor = server_minor;
+			accept_uvnc = 1;
+			fprintf(stderr,"Reset RFB version to 3.%d for UltraVNC SSVNC_ACCEPT_POPUP_SC.\n\n", viewer_minor);
+		}
+	}
 
-  if (!ReadFromRFBServer(desktopName, si.nameLength)) return False;
+	fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", viewer_major, viewer_minor);
 
-  desktopName[si.nameLength] = 0;
+	if (hsfile) {
+		int k = 0;
+		while (hsparam[k] != NULL) {
+			char *str = hsparam[k++];
+			if (strstr(str, "latency=") == str) {
+				latency = 1000. * atof(str + strlen("latency="));
+			}
+		}
+		k = 0;
+		while (hsparam[k] != NULL) {
+			char *str = hsparam[k++];
+			int v1, v2;
+			if (sscanf(str, "viewer=RFB %d.%d\n", &v1, &v2) == 2) {
+				viewer_major = v1;
+				viewer_minor = v2;
+				fprintf(stderr, "\nPre-Handshake set protocol version to: %d.%d  Latency: %.2f ms\n", viewer_major, viewer_minor, latency);
+				goto end_of_proto_msg;
+			}
+		}
+	}
+	sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor);
 
-  fprintf(stderr,"Desktop name \"%s\"\n",desktopName);
+	if (!appData.appShare) {
+		usleep(100*1000);
+	}
+	dt = dnow();
+	if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) {
+		return False;
+	}
 
-  fprintf(stderr,"VNC server default format:\n");
-  PrintPixelFormat(&si.format);
+	end_of_proto_msg:
 
-  if (tightVncProtocol) {
-    /* Read interaction capabilities (protocol 3.7t) */
-    if (!ReadInteractionCaps())
-      return False;
-  }
+	if (envsetsec) {
+		secType = atoi(getenv("SSVNC_SET_SECURITY_TYPE"));
+		goto sec_type;
+	}
+	if (hsfile) {
+		int k = 0;
+		while (hsparam[k] != NULL) {
+			char *str = hsparam[k++];
+			int st;
+			if (sscanf(str, "sectype=%d\n", &st) == 1) {
+				secType = st;
+				fprintf(stderr, "Pre-Handshake set Security-Type to: %d (%s)\n", st, pr_sec_type(st));
+				if (secType == rfbSecTypeVencrypt) {
+					goto sec_type;
+				} else if (secType == rfbSecTypeAnonTls) {
+					break;
+				}
+			}
+		}
+	}
 
-  return True;
+	if (accept_uvnc) {
+		unsigned int msg_sz = 0;
+		unsigned int nimmer = 0;
+		char msg[3000];
+		char *msg_buf, *sip = NULL, *sih = NULL;
+
+		if (!ReadFromRFBServer((char *) &msg_sz, 4)) {
+			return False;
+		}
+		dt_out_sc = dnow();
+		msg_sz = Swap32IfBE(msg_sz);
+		if (msg_sz > 1024) {
+			fprintf(stderr, "UVNC msg size too big: %d\n", msg_sz);
+			exit(1);
+		}
+		msg_buf = (char *)calloc(msg_sz + 100, 1);
+		if (!ReadFromRFBServer(msg_buf, msg_sz)) {
+			return False;
+		}
+
+		if (0) {
+			fprintf(stderr, "msg_buf: ");
+			write(2, msg_buf, msg_sz);
+			fprintf(stderr, "\n");
+		}
+
+		sip = get_peer_ip(rfbsock);
+		if (strlen(sip) > 100) sip = "0.0.0.0";
+		sih = ip2host(sip);
+		if (strlen(sih) > 300) sih = "unknown";
+
+		sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n                               Hostname: %s\n\n", sip, sih);
+		strcat(msg, "UltraVNC Server Message:\n");
+		strcat(msg, msg_buf);
+		free(msg_buf);
+		strcat(msg, "\n\n");
+		strcat(msg, "Accept or Reject VNC connection?");
+		if (CreateMsg(msg, 2)) {
+			nimmer = 1;
+			fprintf(stderr, "Accepting connection.\n\n");
+		} else {
+			nimmer = 0;
+			fprintf(stderr, "Refusing connection.\n\n");
+		}
+		if (!WriteExact(rfbsock, (char *) &nimmer, 4)) {
+			return False;
+		}
+	}
+
+	/* Read or select the security type. */
+	dt_out = 0.0;
+
+	skip_XtUpdateAll = 1;
+	if (viewer_minor >= 7 && !accept_uvnc) {
+		secType = SelectSecurityType();
+	} else {
+		secType = ReadSecurityType();
+	}
+	skip_XtUpdateAll = 0;
+
+	if (accept_uvnc) {
+		dt_out = dt_out_sc;
+	}
+
+	if (dt > 0.0 && dt_out > dt) {
+		latency = (dt_out - dt) * 1000;
+	}
+	
+	fprintf(stderr, "Security-Type: %d (%s)  Latency: %.2f ms\n", (int) secType, pr_sec_type(secType), latency);
+	if (secType == rfbSecTypeInvalid) {
+		return False;
+	}
+
+	sec_type:
+
+	if (hsfile) {
+		int subsectype = 0;
+		int k = 0;
+		while (hsparam[k] != NULL) {
+			char *str = hsparam[k++];
+			int st;
+			if (sscanf(str, "subtype=%d\n", &st) == 1) {
+				subsectype = st;
+				fprintf(stderr, "Pre-Handshake set Sub-Security-Type to: %d (%s)\n\n", st, pr_sec_subtype(st));
+				break;
+			}
+		}
+
+		if (!subsectype) {
+			;
+		} else if (secType == rfbSecTypeVencrypt) {
+			if (subsectype == rfbVencryptTlsNone) {
+				anon_dh = 1;
+				secType = rfbSecTypeNone;
+			} else if (subsectype == rfbVencryptTlsVnc) {
+				anon_dh = 1;
+				secType = rfbSecTypeVncAuth;
+			} else if (subsectype == rfbVencryptTlsPlain) {
+				anon_dh = 1;
+				secType = rfbSecTypeNone;
+			} else if (subsectype == rfbVencryptX509None) {
+				secType = rfbSecTypeNone;
+			} else if (subsectype == rfbVencryptX509Vnc) {
+				secType = rfbSecTypeVncAuth;
+			} else if (subsectype == rfbVencryptX509Plain) {
+				secType = rfbSecTypeNone;
+			}
+			if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) {
+				usleep(300*1000);
+			}
+			if (subsectype == rfbVencryptTlsNone || subsectype == rfbVencryptTlsVnc || subsectype == rfbVencryptTlsPlain) {
+				char tmp[1000], line[100];
+				tmp[0] = '\0';
+				strcat(tmp, "\n");
+				sprintf(line, "WARNING: Anonymous Diffie-Hellman TLS used (%s),\n", pr_sec_subtype(subsectype));
+				strcat(tmp, line);
+				strcat(tmp, "WARNING: there will be *NO* Authentication of the VNC Server.\n");
+				strcat(tmp, "WARNING: I.e. a Man-In-The-Middle attack is possible.\n");
+				strcat(tmp, "WARNING: Configure the server to use X509 certs and verify them.\n\n");
+				wmsg(tmp, 1);
+			}
+			if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) {
+				fprintf(stderr, "\nVeNCrypt Plain (username + passwd) selected.\n\n");
+				if (appData.unixPW != NULL) {
+					unixpw(appData.unixPW, 1);
+				} else if (getenv("SSVNC_UNIXPW")) {
+					unixpw(getenv("SSVNC_UNIXPW"), 1);
+				} else {
+					unixpw(".", 1);
+				}
+			}
+		}
+	}
+
+	switch (secType) {
+		case rfbSecTypeNone:
+			fprintf(stderr, "No VNC authentication needed\n");
+			if (viewer_minor >= 8) {
+				CARD32 authResult;
+
+				if (!ReadFromRFBServer((char *)&authResult, 4)) {
+					return False;
+				}
+
+				authResult = Swap32IfLE(authResult);
+
+				if (authResult == rfbVncAuthOK) {
+					fprintf(stderr, "VNC authentication succeeded (%d) for rfbSecTypeNone (RFB 3.8)\n", (int) authResult);
+				} else {
+					sprintf(msgbuf, "VNC authentication failed (%d) for rfbSecTypeNone (RFB 3.8)\n\n", (int) authResult);
+					wmsg(msgbuf, 1);
+					return False;
+				}
+			}
+			fprintf(stderr, "\n");
+			break;
+		case rfbSecTypeVncAuth:
+			if (!AuthenticateVNC()) {
+				return False;
+			}
+			break;
+		case rfbSecTypeTight:
+			tightVncProtocol = True;
+			InitCapabilities();
+			if (!SetupTunneling()) {
+				return False;
+			}
+			if (!PerformAuthenticationTight()) {
+				return False;
+			}
+			break;
+		case rfbUltraVncMsLogon:
+			if (!AuthUltraVncMsLogon()) {
+				return False;
+			}
+			break;
+		default:                      /* should never happen */
+			sprintf(msgbuf, "Internal error: Invalid security type: %d\n", secType);
+			wmsg(msgbuf, 1);
+			return False;
+	}
+
+	connect_time = dnow();
+
+	ci.shared = (appData.shareDesktop ? 1 : 0);
+
+	if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) {
+		return False;
+	}
+
+	if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) {
+		return False;
+	}
+
+	si.framebufferWidth = Swap16IfLE(si.framebufferWidth);
+	si.framebufferHeight = Swap16IfLE(si.framebufferHeight);
+	si.format.redMax = Swap16IfLE(si.format.redMax);
+	si.format.greenMax = Swap16IfLE(si.format.greenMax);
+	si.format.blueMax = Swap16IfLE(si.format.blueMax);
+	si.nameLength = Swap32IfLE(si.nameLength);
+
+	if (appData.chatOnly) {
+		si.framebufferWidth = 32;
+		si.framebufferHeight = 32;
+	}
+
+	/* FIXME: Check arguments to malloc() calls. */
+	desktopName = malloc(si.nameLength + 1);
+	memset(desktopName, 0, si.nameLength + 1);
+	if (!desktopName) {
+		fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
+		    (unsigned long)si.nameLength);
+		return False;
+	}
+
+	if (!ReadFromRFBServer(desktopName, si.nameLength)) {
+		return False;
+	}
+
+	desktopName[si.nameLength] = 0;
+
+	if (appData.appShare) {
+		int x_hint, y_hint;
+		char *p, *q = NULL;
+		p = desktopName;
+		while (*p != '\0') {
+ 			char *t = strstr(p, " XY=");
+			if (t) q = t;
+			p++;
+		}
+		if (q) {
+			int ok = 1;
+			p = q + strlen(" XY=");
+			while (*p != '\0') {
+				if (!strpbrk(p, "0123456789,+-")) {
+					ok = 0;
+				}
+				p++;
+			}
+			if (ok && sscanf(q+1, "XY=%d,%d", &x_hint, &y_hint) == 2) {
+				fprintf(stderr,"Using x11vnc appshare position: %s\n\n", q);
+				*q = '\0';
+				appshare_x_hint = x_hint;
+				appshare_y_hint = y_hint;
+			}
+		}
+	}
+
+	fprintf(stderr,"Desktop name \"%s\"\n\n", desktopName);
+
+	fprintf(stderr,"VNC server default format:\n");
+	PrintPixelFormat(&si.format);
+
+	if (tightVncProtocol) {
+		/* Read interaction capabilities (protocol 3.7t) */
+		if (!ReadInteractionCaps()) {
+			return False;
+		}
+	}
+
+	return True;
 }
 
 
 /*
- * Read security type from the server (protocol version 3.3)
+ * Read security type from the server (protocol 3.3)
  */
 
 static int
 ReadSecurityType(void)
 {
-  CARD32 secType;
+	CARD32 secType;
 
-  /* Read the security type */
-  if (!ReadFromRFBServer((char *)&secType, sizeof(secType)))
-    return rfbSecTypeInvalid;
+	/* Read the security type */
+	if (!ReadFromRFBServer((char *)&secType, sizeof(secType))) {
+		return rfbSecTypeInvalid;
+	}
+	dt_out = dnow();
 
-  secType = Swap32IfLE(secType);
+	secType = Swap32IfLE(secType);
 
-  if (secType == rfbSecTypeInvalid) {
-    ReadConnFailedReason();
-    return rfbSecTypeInvalid;
-  }
+	if (secType == rfbSecTypeInvalid) {
+		ReadConnFailedReason();
+		return rfbSecTypeInvalid;
+	}
 
-  if (secType != rfbSecTypeNone && secType != rfbSecTypeVncAuth) {
-    fprintf(stderr, "Unknown security type from RFB server: %d\n",
-            (int)secType);
-    return rfbSecTypeInvalid;
-  }
+	if (secType == rfbSecTypeNone) {
+		;	/* OK */
+	} else if (secType == rfbSecTypeVncAuth) {
+		;	/* OK */
+	} else if (secType == rfbUltraVncMsLogon) {
+		;	/* OK */
+	} else {
+		sprintf(msgbuf, "Unknown security type from RFB server: %d\n", (int)secType);
+		wmsg(msgbuf, 1);
+		return rfbSecTypeInvalid;
+	}
 
-  return (int)secType;
+	return (int)secType;
 }
 
 
 /*
- * Select security type from the server's list (protocol version 3.7)
+ * Select security type from the server's list (protocol 3.7)
  */
 
 static int
 SelectSecurityType(void)
 {
-  CARD8 nSecTypes;
-  char *secTypeNames[] = {"None", "VncAuth"};
-  CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth};
-  int nKnownSecTypes = sizeof(knownSecTypes);
-  CARD8 *secTypes;
-  CARD8 secType = rfbSecTypeInvalid;
-  int i, j;
-
-  /* Read the list of secutiry types. */
-  if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes)))
-    return rfbSecTypeInvalid;
-
-  if (nSecTypes == 0) {
-    ReadConnFailedReason();
-    return rfbSecTypeInvalid;
-  }
+	CARD8 nSecTypes;
+	char *secTypeNames[] = {"None", "VncAuth"};
+	CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth};
+	int nKnownSecTypes = sizeof(knownSecTypes);
+	CARD8 *secTypes;
+	CARD8 secType = rfbSecTypeInvalid;
+	int i, j;
+
+	if (secTypeNames) {}
+
+	/* Read the list of security types. */
+	if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) {
+		return rfbSecTypeInvalid;
+	}
+	dt_out = dnow();
 
-  secTypes = malloc(nSecTypes);
-  if (!ReadFromRFBServer((char *)secTypes, nSecTypes))
-    return rfbSecTypeInvalid;
-
-  /* Find out if the server supports TightVNC protocol extensions */
-  for (j = 0; j < (int)nSecTypes; j++) {
-    if (secTypes[j] == rfbSecTypeTight) {
-      free(secTypes);
-      secType = rfbSecTypeTight;
-      if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType)))
-        return rfbSecTypeInvalid;
-      fprintf(stderr, "Enabling TightVNC protocol extensions\n");
-      return rfbSecTypeTight;
-    }
-  }
+	if (nSecTypes == 0) {
+		ReadConnFailedReason();
+		return rfbSecTypeInvalid;
+	}
 
-  /* Find first supported security type */
-  for (j = 0; j < (int)nSecTypes; j++) {
-    for (i = 0; i < nKnownSecTypes; i++) {
-      if (secTypes[j] == knownSecTypes[i]) {
-        secType = secTypes[j];
-        if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) {
-          free(secTypes);
-          return rfbSecTypeInvalid;
-        }
-        break;
-      }
-    }
-    if (secType != rfbSecTypeInvalid) break;
-  }
+	secTypes = malloc(nSecTypes);
+	if (!ReadFromRFBServer((char *)secTypes, nSecTypes)) {
+		return rfbSecTypeInvalid;
+	}
+
+	if (getenv("SSVNC_DEBUG_SEC_TYPES")) {
+		for (j = 0; j < (int)nSecTypes; j++) {
+			fprintf(stderr, "sec-type[%d] %d\n", j, (int) secTypes[j]);
+		}
+	}
+
+	/* Find out if the server supports TightVNC protocol extensions */
+	for (j = 0; j < (int)nSecTypes; j++) {
+		if (getenv("VNCVIEWER_NO_SEC_TYPE_TIGHT")) {
+			break;
+		}
+		if (getenv("SSVNC_NO_SEC_TYPE_TIGHT")) {
+			break;
+		}
+#ifdef TURBOVNC
+		break;
+#endif
+		if (secTypes[j] == rfbSecTypeTight) {
+			free(secTypes);
+			secType = rfbSecTypeTight;
+			if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) {
+				return rfbSecTypeInvalid;
+			}
+			fprintf(stderr, "Enabling TightVNC protocol extensions\n");
+			return rfbSecTypeTight;
+		}
+	}
+
+	/* Find first supported security type */
+	for (j = 0; j < (int)nSecTypes; j++) {
+		for (i = 0; i < nKnownSecTypes; i++) {
+			if (secTypes[j] == knownSecTypes[i]) {
+				secType = secTypes[j];
+				if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) {
+				  free(secTypes);
+				  return rfbSecTypeInvalid;
+				}
+				break;
+				}
+		}
+		if (secType != rfbSecTypeInvalid) {
+			break;
+		}
+	}
 
-  free(secTypes);
+	if (secType == rfbSecTypeInvalid) {
+		fprintf(stderr, "Server did not offer supported security type:\n");
+		for (j = 0; j < (int)nSecTypes; j++) {
+			fprintf(stderr, "  sectype[%d] %d\n", j, (int) secTypes[j]);
+		}
+	}
 
-  if (secType == rfbSecTypeInvalid)
-    fprintf(stderr, "Server did not offer supported security type\n");
+	free(secTypes);
 
-  return (int)secType;
+	return (int)secType;
 }
 
 
@@ -451,6 +1141,9 @@
   return True;
 }
 
+static char *restart_session_pw = NULL;
+static int restart_session_len = 0;
+
 
 /*
  * Negotiate authentication scheme (protocol version 3.7t)
@@ -459,58 +1152,406 @@
 static Bool
 PerformAuthenticationTight(void)
 {
-  rfbAuthenticationCapsMsg caps;
-  CARD32 authScheme;
-  int i;
+	rfbAuthenticationCapsMsg caps;
+	CARD32 authScheme;
+	int i;
 
-  /* In the protocol version 3.7t, the server informs us about supported
-     authentication schemes. Here we read this information. */
+	/* In the protocol version 3.7t, the server informs us about supported
+	authentication schemes. Here we read this information. */
 
-  if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg))
-    return False;
+	if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg)) {
+		return False;
+	}
 
-  caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes);
+	caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes);
 
-  if (!caps.nAuthTypes) {
-    fprintf(stderr, "No authentication needed\n");
-    return True;
-  }
+	if (!caps.nAuthTypes) {
+		fprintf(stderr, "No VNC authentication needed\n\n");
+		if (viewer_minor >= 8) {
+			CARD32 authResult;
+
+			if (!ReadFromRFBServer((char *)&authResult, 4)) {
+				return False;
+			}
+
+			authResult = Swap32IfLE(authResult);
+
+			if (authResult == rfbVncAuthOK) {
+				fprintf(stderr, "VNC authentication succeeded (%d) for PerformAuthenticationTight rfbSecTypeNone (RFB 3.8)\n", (int) authResult);
+			} else {
+				sprintf(msgbuf, "VNC authentication failed (%d) for PerformAuthenticationTight rfbSecTypeNone (RFB 3.8)\n\n", (int) authResult);
+				wmsg(msgbuf, 1);
+				return False;
+			}
+		}
+		return True;
+	}
 
-  if (!ReadCapabilityList(authCaps, caps.nAuthTypes))
-    return False;
+	if (!ReadCapabilityList(authCaps, caps.nAuthTypes)) {
+		return False;
+	}
 
-  /* Prefer Unix login authentication if a user name was given. */
-  if (appData.userLogin && CapsIsEnabled(authCaps, rfbAuthUnixLogin)) {
-    authScheme = Swap32IfLE(rfbAuthUnixLogin);
-    if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme)))
-      return False;
-    return AuthenticateUnixLogin();
-  }
+	/* Prefer Unix login authentication if a user name was given. */
+	if (appData.userLogin && CapsIsEnabled(authCaps, rfbAuthUnixLogin)) {
+		authScheme = Swap32IfLE(rfbAuthUnixLogin);
+		if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) {
+			return False;
+		}
+		return AuthenticateUnixLogin();
+	}
 
-  /* Otherwise, try server's preferred authentication scheme. */
-  for (i = 0; i < CapsNumEnabled(authCaps); i++) {
-    authScheme = CapsGetByOrder(authCaps, i);
-    if (authScheme != rfbAuthUnixLogin && authScheme != rfbAuthVNC)
-      continue;                 /* unknown scheme - cannot use it */
-    authScheme = Swap32IfLE(authScheme);
-    if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme)))
-      return False;
-    authScheme = Swap32IfLE(authScheme); /* convert it back */
-    if (authScheme == rfbAuthUnixLogin) {
-      return AuthenticateUnixLogin();
-    } else if (authScheme == rfbAuthVNC) {
-      return AuthenticateVNC();
-    } else {
-      /* Should never happen. */
-      fprintf(stderr, "Assertion failed: unknown authentication scheme\n");
-      return False;
-    }
-  }
+	/* Otherwise, try server's preferred authentication scheme. */
+	for (i = 0; i < CapsNumEnabled(authCaps); i++) {
+		authScheme = CapsGetByOrder(authCaps, i);
+		if (authScheme != rfbAuthUnixLogin && authScheme != rfbAuthVNC) {
+			continue;                 /* unknown scheme - cannot use it */
+		}
+		authScheme = Swap32IfLE(authScheme);
+		if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) {
+			return False;
+		}
+		authScheme = Swap32IfLE(authScheme); /* convert it back */
+		if (authScheme == rfbAuthUnixLogin) {
+			return AuthenticateUnixLogin();
+		} else if (authScheme == rfbAuthVNC) {
+			return AuthenticateVNC();
+		} else {
+			/* Should never happen. */
+			fprintf(stderr, "Assertion failed: unknown authentication scheme\n");
+			return False;
+		}
+	}
 
-  fprintf(stderr, "No suitable authentication schemes offered by server\n");
-  return False;
+	sprintf(msgbuf, "No suitable authentication schemes offered by server\n");
+	wmsg(msgbuf, 1);
+	return False;
+}
+
+#if 0
+unsigned char encPasswd[8];
+unsigned char encPasswd_MSLOGON[32];
+char clearPasswd_MSLOGIN[256];
+static Bool old_ultravnc_mslogon_code(void) {
+	char *passwd = NULL;
+	CARD8 challenge_mslogon[CHALLENGESIZE_MSLOGON];
+
+	/* code from the old uvnc way (1.0.2?) that would go into AuthenticateVNC() template */
+	
+	if (appData.msLogon != NULL) {
+		raiseme(1);
+		if (!strcmp(appData.msLogon, "1")) {
+			char tmp[256];
+			fprintf(stderr, "\nUltraVNC MS Logon Username[@Domain]: ");
+			if (fgets(tmp, 256, stdin) == NULL) {
+				exit(1);
+			}
+			appData.msLogon = strdup(tmp);
+		}
+		passwd = getpass("UltraVNC MS Logon Password: ");
+		if (! passwd) {
+			exit(1);
+		}
+		fprintf(stderr, "\n");
+
+		UvncEncryptPasswd_MSLOGON(encPasswd_MSLOGON, passwd);
+	}
+	if (appData.msLogon) {
+		if (!ReadFromRFBServer((char *)challenge_mslogon, CHALLENGESIZE_MSLOGON)) {
+			return False;
+		}
+	}
+	if (appData.msLogon) {
+		int i;
+		char tmp[256];
+		char *q, *domain = ".";
+		for (i=0; i < 32; i++) {
+			challenge_mslogon[i] = encPasswd_MSLOGON[i] ^ challenge_mslogon[i];
+		}
+		q = strchr(appData.msLogon, '@');
+		if (q) {
+			*q = '\0';
+			domain = strdup(q+1);
+		}
+		memset(tmp, 0, sizeof(tmp));
+		strcat(tmp, appData.msLogon);
+		if (!WriteExact(rfbsock, tmp, 256)) {
+			return False;
+		}
+		memset(tmp, 0, sizeof(tmp));
+		strcat(tmp, domain);
+		if (!WriteExact(rfbsock, tmp, 256)) {
+			return False;
+		}
+		memset(tmp, 0, sizeof(tmp));
+		strcat(tmp, passwd);
+		if (!WriteExact(rfbsock, tmp, CHALLENGESIZE_MSLOGON)) {
+			return False;
+		}
+	}
 }
+#endif
 
+static void hexprint(char *label, char *data, int len) {
+	int i;
+	fprintf(stderr, "%s: ", label);
+	for (i=0; i < len; i++) {
+		unsigned char c = (unsigned char) data[i];
+		fprintf(stderr, "%02x ", (int) c);
+		if ((i+1) % 20 == 0) {
+			fprintf(stderr, "\n%s: ", label);
+		}
+	}
+	fprintf(stderr, "\n");
+}
+
+#define DH_MAX_BITS 31
+static unsigned long long max_dh = ((unsigned long long) 1) << DH_MAX_BITS;
+
+static unsigned long long bytes_to_uint64(char *bytes) {
+	unsigned long long result = 0;
+	int i;
+
+	for (i=0; i < 8; i++) {
+		result <<= 8;
+		result += (unsigned char) bytes[i];
+	}
+	return result;
+}
+
+static void uint64_to_bytes(unsigned long long n, char *bytes) {
+	int i;
+
+	for (i=0; i < 8; i++) {
+		bytes[i] = (unsigned char) (n >> (8 * (7 - i)));
+	}
+}
+
+static void try_invert(char *wireuser, char *wirepass, unsigned long long actual_key) {
+	if (wireuser || wirepass || actual_key) {}
+	return;
+}
+
+
+static unsigned long long XpowYmodN(unsigned long long x, unsigned long long y, unsigned long long N) {
+	unsigned long long result = 1;
+	unsigned long long oneShift63 = ((unsigned long long) 1) << 63;
+	int i;
+
+	for (i = 0; i < 64; y <<= 1, i++) {
+		result = result * result % N;
+		if (y & oneShift63) {
+			result = result * x % N;
+		}
+	}
+	return result;
+}
+
+/*
+ * UltraVNC MS-Logon authentication (for v1.0.5 and later.)
+ */
+
+/*
+ * NOTE: The UltraVNC MS-Logon username and password exchange is
+ *       VERY insecure.  It can be brute forced in ~2e+9 operations.
+ *       It's not clear we should support it...  It is only worth using
+ *       in an environment where no one is sniffing the network, in which
+ *       case all of this DH exchange secrecy is unnecessary...
+ */
+
+static Bool AuthUltraVncMsLogon(void) {
+	CARD32 authResult;
+	char gen[8], mod[8], pub[8], rsp[8];
+	char user[256], passwd[64], *gpw;
+	unsigned char key[8];
+	unsigned long long ugen, umod, ursp, upub, uprv, ukey;
+	double now = dnow();
+	int db = 0;
+
+	if (getenv("SSVNC_DEBUG_MSLOGON")) {
+		db = atoi(getenv("SSVNC_DEBUG_MSLOGON"));
+	}
+
+	fprintf(stderr, "\nAuthUltraVncMsLogon()\n");
+
+	if (!ReadFromRFBServer(gen, sizeof(gen))) {
+		return False;
+	}
+	if (db) hexprint("gen", gen, sizeof(gen));
+
+	if (!ReadFromRFBServer(mod, sizeof(mod))) {
+		return False;
+	}
+	if (db) hexprint("mod", mod, sizeof(mod));
+	
+	if (!ReadFromRFBServer(rsp, sizeof(rsp))) {
+		return False;
+	}
+	if (db) hexprint("rsp", rsp, sizeof(rsp));
+
+	ugen = bytes_to_uint64(gen);
+	umod = bytes_to_uint64(mod);
+	ursp = bytes_to_uint64(rsp);
+
+	if (db) {
+		fprintf(stderr, "ugen: 0x%016llx %12llu\n", ugen, ugen);
+		fprintf(stderr, "umod: 0x%016llx %12llu\n", umod, umod);
+		fprintf(stderr, "ursp: 0x%016llx %12llu\n", ursp, ursp);
+	}
+
+	if (ugen > max_dh) {
+		fprintf(stderr, "ugen: too big: 0x%016llx\n", ugen);
+		return False;
+	}
+
+	if (umod > max_dh) {
+		fprintf(stderr, "umod: too big: 0x%016llx\n", umod);
+		return False;
+	}
+
+	/* make a random long long: */
+	uprv = 0xffffffff * (now - (unsigned int) now);
+	uprv = uprv << 32;
+	uprv |= (unsigned long long) urandom();
+	uprv = uprv % max_dh;
+
+	if (db) fprintf(stderr, "uprv: 0x%016llx %12llu\n", uprv, uprv);
+
+	upub = XpowYmodN(ugen, uprv, umod);
+
+	if (db) fprintf(stderr, "upub: 0x%016llx %12llu\n", upub, upub);
+
+	uint64_to_bytes(upub, pub);
+
+	if (db) hexprint("pub", pub, sizeof(pub));
+
+	if (!WriteExact(rfbsock, (char *)pub, sizeof(pub))) {
+		return False;
+	}
+	if (db) fprintf(stderr, "wrote pub.\n");
+
+	if (ursp > max_dh) {
+		fprintf(stderr, "ursp: too big: 0x%016llx\n", ursp);
+		return False;
+	}
+
+	ukey = XpowYmodN(ursp, uprv, umod);
+
+	if (db) fprintf(stderr, "ukey: 0x%016llx %12llu\n", ukey, ukey);
+
+	if (1)  {
+		char tmp[10000];
+		tmp[0] = '\0';
+		strcat(tmp, "\n");
+		strcat(tmp, "WARNING: The UltraVNC Diffie-Hellman Key is weak (key < 2e+9, i.e. 31 bits)\n");
+		strcat(tmp, "WARNING: and so an eavesdropper could recover your MS-Logon username and\n");
+		strcat(tmp, "WARNING: password via brute force in a few seconds of CPU time. \n");
+		strcat(tmp, "WARNING: If this connection is NOT being tunnelled through a separate SSL or\n");
+		strcat(tmp, "WARNING: SSH encrypted tunnel, consider things carefully before proceeding...\n");
+		strcat(tmp, "WARNING: Do not enter an important username+password when prompted below if\n");
+		strcat(tmp, "WARNING: there is a risk of an eavesdropper sniffing this connection.\n");
+		strcat(tmp, "WARNING: UltraVNC MSLogon encryption is VERY weak.  You've been warned!\n");
+		wmsg(tmp, 1);
+	}
+
+	uint64_to_bytes(ukey, (char *) key);
+
+	if (appData.msLogon == NULL || !strcmp(appData.msLogon, "1")) {
+		char tmp[256], *q, *s;
+		if (!use_tty()) {
+			fprintf(stderr, "\nEnter UltraVNC MS-Logon Username[@Domain] in the popup.\n");
+			s = DoUserDialog(); 
+		} else {
+			raiseme(1);
+			fprintf(stderr, "\nUltraVNC MS-Logon Username[@Domain]: ");
+			if (fgets(tmp, 256, stdin) == NULL) {
+				exit(1);
+			}
+			s = strdup(tmp);
+		}
+		q = strchr(s, '\n');
+		if (q) *q = '\0';
+		appData.msLogon = strdup(s);
+	}
+
+	if (!use_tty()) {
+		gpw = DoPasswordDialog(); 
+	} else {
+		raiseme(1);
+		gpw = getpass("UltraVNC MS-Logon Password: ");
+	}
+	if (! gpw) {
+		return False;
+	}
+	fprintf(stderr, "\n");
+
+	memset(user, 0, sizeof(user));
+	strncpy(user, appData.msLogon, 255);
+
+	memset(passwd, 0, sizeof(passwd));
+	strncpy(passwd, gpw, 63);
+
+	if (db > 1) {
+		fprintf(stderr, "user='%s'\n", user);
+		fprintf(stderr, "pass='%s'\n", passwd);
+	}
+
+	UvncEncryptBytes2((unsigned char *) user,   sizeof(user),   key);
+	UvncEncryptBytes2((unsigned char *) passwd, sizeof(passwd), key);
+
+	if (getenv("TRY_INVERT")) {
+		try_invert(user, passwd, ukey);
+		exit(0);
+	}
+
+	if (db) {
+		hexprint("user", user, sizeof(user));
+		hexprint("pass", passwd, sizeof(passwd));
+	}
+
+	if (!WriteExact(rfbsock, user, sizeof(user))) {
+		return False;
+	}
+	if (db) fprintf(stderr, "wrote user.\n");
+
+	if (!WriteExact(rfbsock, passwd, sizeof(passwd))) {
+		return False;
+	}
+	if (db) fprintf(stderr, "wrote passwd.\n");
+
+	if (!ReadFromRFBServer((char *) &authResult, 4)) {
+		return False;
+	}
+	authResult = Swap32IfLE(authResult);
+
+	if (db) fprintf(stderr, "authResult: %d\n", (int) authResult);
+
+	switch (authResult) {
+	case rfbVncAuthOK:
+		fprintf(stderr, "UVNC MS-Logon authentication succeeded.\n\n");
+		break;
+	case rfbVncAuthFailed:
+		fprintf(stderr, "UVNC MS-Logon authentication failed.\n");
+		if (viewer_minor >= 8) {
+			printFailureReason();
+		} else {
+			sprintf(msgbuf, "UVNC MS-Logon authentication failed.\n");
+			wmsg(msgbuf, 1);
+		}
+		fprintf(stderr, "\n");
+		return False;
+	case rfbVncAuthTooMany:
+		sprintf(msgbuf, "UVNC MS-Logon authentication failed - too many tries.\n\n");
+		wmsg(msgbuf, 1);
+		return False;
+	default:
+		sprintf(msgbuf, "Unknown UVNC MS-Logon authentication result: %d\n\n",
+		    (int)authResult);
+		wmsg(msgbuf, 1);
+		return False;
+	}
+
+	return True;
+}
 
 /*
  * Standard VNC authentication.
@@ -519,80 +1560,119 @@
 static Bool
 AuthenticateVNC(void)
 {
-  CARD32 authScheme, authResult;
-  CARD8 challenge[CHALLENGESIZE];
-  char *passwd;
-  char  buffer[64];
-  char* cstatus;
-  int   len;
+	CARD32 authScheme, authResult;
+	CARD8 challenge[CHALLENGESIZE];
+	char *passwd = NULL;
+	char  buffer[64];
+	char* cstatus;
+	int   len;
+	int restart = 0;
 
-  fprintf(stderr, "Performing standard VNC authentication\n");
+	if (authScheme) {}
 
-  if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE))
-    return False;
+	fprintf(stderr, "\nPerforming standard VNC authentication\n");
 
-  if (appData.passwordFile) {
-    passwd = vncDecryptPasswdFromFile(appData.passwordFile);
-    if (!passwd) {
-      fprintf(stderr, "Cannot read valid password from file \"%s\"\n",
-	      appData.passwordFile);
-      return False;
-    }
-  } else if (appData.autoPass) {
-    passwd = buffer;
-    cstatus = fgets(buffer, sizeof buffer, stdin);
-    if (cstatus == NULL)
-       buffer[0] = '\0';
-    else
-    {
-       len = strlen(buffer);
-       if (len > 0 && buffer[len - 1] == '\n')
-	  buffer[len - 1] = '\0';
-    }
-  } else if (appData.passwordDialog) {
-    passwd = DoPasswordDialog();
-  } else {
-    passwd = getpass("Password: ");
-  }
+	if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) {
+		return False;
+	}
+		
+	if (restart_session_pw != NULL) {
+		passwd = restart_session_pw;	
+		restart_session_pw = NULL;
+		restart = 1;
+	} else if (appData.passwordFile) {
+		passwd = vncDecryptPasswdFromFile(appData.passwordFile);
+		if (!passwd) {
+			sprintf(msgbuf, "Cannot read valid password from file \"%s\"\n", appData.passwordFile);
+			wmsg(msgbuf, 1);
+			return False;
+		}
+	} else if (appData.autoPass) {
+		passwd = buffer;
+		raiseme(1);
+		cstatus = fgets(buffer, sizeof buffer, stdin);
+		if (cstatus == NULL) {
+			buffer[0] = '\0';
+		} else {
+			len = strlen(buffer);
+			if (len > 0 && buffer[len - 1] == '\n') {
+				buffer[len - 1] = '\0';
+			}
+		}
+	} else if (getenv("VNCVIEWER_PASSWORD")) {
+		passwd = strdup(getenv("VNCVIEWER_PASSWORD"));
+	} else if (appData.passwordDialog || !use_tty()) {
+		passwd = DoPasswordDialog();
+	} else {
+		raiseme(1);
+		passwd = getpass("VNC Password: ");
+	}
 
-  if (!passwd || strlen(passwd) == 0) {
-    fprintf(stderr, "Reading password failed\n");
-    return False;
-  }
-  if (strlen(passwd) > 8) {
-    passwd[8] = '\0';
-  }
+	if (getenv("VNCVIEWER_PASSWORD")) {
+		putenv("VNCVIEWER_PASSWORD=none");
+	}
 
-  vncEncryptBytes(challenge, passwd);
+	if (restart) {
+#define EN0 0
+#define DE1 1
+		unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7};
+		deskey(s_fixedkey, DE1);
+		des(passwd, passwd);
+	} else {
+		if (!passwd || strlen(passwd) == 0) {
+			sprintf(msgbuf, "Reading password failed\n\n");
+			wmsg(msgbuf, 1);
+			return False;
+		}
+		if (strlen(passwd) > 8) {
+			passwd[8] = '\0';
+		}
+	}
 
-  /* Lose the password from memory */
-  memset(passwd, '\0', strlen(passwd));
+	vncEncryptBytes(challenge, passwd);
+	
 
-  if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE))
-    return False;
 
-  if (!ReadFromRFBServer((char *)&authResult, 4))
-    return False;
+#if 0
+	/* Lose the password from memory */
+	memset(passwd, '\0', strlen(passwd));
+#endif
 
-  authResult = Swap32IfLE(authResult);
+	if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) {
+		return False;
+	}
 
-  switch (authResult) {
-  case rfbVncAuthOK:
-    fprintf(stderr, "VNC authentication succeeded\n");
-    break;
-  case rfbVncAuthFailed:
-    fprintf(stderr, "VNC authentication failed\n");
-    return False;
-  case rfbVncAuthTooMany:
-    fprintf(stderr, "VNC authentication failed - too many tries\n");
-    return False;
-  default:
-    fprintf(stderr, "Unknown VNC authentication result: %d\n",
-	    (int)authResult);
-    return False;
-  }
+	if (!ReadFromRFBServer((char *)&authResult, 4)) {
+		return False;
+	}
 
-  return True;
+	authResult = Swap32IfLE(authResult);
+
+	switch (authResult) {
+	case rfbVncAuthOK:
+		fprintf(stderr, "VNC authentication succeeded\n\n");
+		break;
+	case rfbVncAuthFailed:
+		fprintf(stderr, "VNC authentication failed.\n");
+		if (viewer_minor >= 8) {
+			printFailureReason();
+		} else {
+			sprintf(msgbuf, "VNC authentication failed.\n");
+			wmsg(msgbuf, 1);
+		}
+		fprintf(stderr, "\n");
+		return False;
+	case rfbVncAuthTooMany:
+		sprintf(msgbuf, "VNC authentication failed - too many tries\n\n");
+		wmsg(msgbuf, 1);
+		return False;
+	default:
+		sprintf(msgbuf, "Unknown VNC authentication result: %d\n\n", (int)authResult);
+		wmsg(msgbuf, 1);
+		return False;
+	}
+
+	return True;
 }
 
 /*
@@ -602,68 +1682,77 @@
 static Bool
 AuthenticateUnixLogin(void)
 {
-  CARD32 loginLen, passwdLen, authResult;
-  char *login;
-  char *passwd;
-  struct passwd *ps;
-
-  fprintf(stderr, "Performing Unix login-style authentication\n");
-
-  if (appData.userLogin) {
-    login = appData.userLogin;
-  } else {
-    ps = getpwuid(getuid());
-    login = ps->pw_name;
-  }
+	CARD32 loginLen, passwdLen, authResult;
+	char *login;
+	char *passwd;
+	struct passwd *ps;
+
+	fprintf(stderr, "\nPerforming Unix login-style authentication\n");
+
+	if (appData.userLogin) {
+		login = appData.userLogin;
+	} else {
+		ps = getpwuid(getuid());
+		login = ps->pw_name;
+	}
 
-  fprintf(stderr, "Using user name \"%s\"\n", login);
+	fprintf(stderr, "Using user name \"%s\"\n", login);
 
-  if (appData.passwordDialog) {
-    passwd = DoPasswordDialog();
-  } else {
-    passwd = getpass("Password: ");
-  }
-  if (!passwd || strlen(passwd) == 0) {
-    fprintf(stderr, "Reading password failed\n");
-    return False;
-  }
+	if (appData.passwordDialog || !use_tty()) {
+		passwd = DoPasswordDialog();
+	} else {
+		raiseme(1);
+		passwd = getpass("VNC Password: ");
+	}
+	if (!passwd || strlen(passwd) == 0) {
+		fprintf(stderr, "Reading password failed\n");
+		return False;
+	}
 
-  loginLen = Swap32IfLE((CARD32)strlen(login));
-  passwdLen = Swap32IfLE((CARD32)strlen(passwd));
+	loginLen = Swap32IfLE((CARD32)strlen(login));
+	passwdLen = Swap32IfLE((CARD32)strlen(passwd));
 
-  if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) ||
-      !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen)))
-    return False;
+	if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) ||
+	    !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen))) {
+		return False;
+	}
 
-  if (!WriteExact(rfbsock, login, strlen(login)) ||
-      !WriteExact(rfbsock, passwd, strlen(passwd)))
-    return False;
+	if (!WriteExact(rfbsock, login, strlen(login)) ||
+	    !WriteExact(rfbsock, passwd, strlen(passwd))) {
+		return False;
+	}
 
-  /* Lose the password from memory */
-  memset(passwd, '\0', strlen(passwd));
+#if 0
+	/* Lose the password from memory */
+	memset(passwd, '\0', strlen(passwd));
+#endif
 
-  if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult)))
-    return False;
+	if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult))) {
+		return False;
+	}
 
-  authResult = Swap32IfLE(authResult);
+	authResult = Swap32IfLE(authResult);
 
-  switch (authResult) {
-  case rfbVncAuthOK:
-    fprintf(stderr, "Authentication succeeded\n");
-    break;
-  case rfbVncAuthFailed:
-    fprintf(stderr, "Authentication failed\n");
-    return False;
-  case rfbVncAuthTooMany:
-    fprintf(stderr, "Authentication failed - too many tries\n");
-    return False;
-  default:
-    fprintf(stderr, "Unknown authentication result: %d\n",
-	    (int)authResult);
-    return False;
-  }
+	switch (authResult) {
+	case rfbVncAuthOK:
+		fprintf(stderr, "Authentication succeeded\n\n");
+		break;
+	case rfbVncAuthFailed:
+		sprintf(msgbuf, "Authentication failed\n\n");
+		wmsg(msgbuf, 1);
+		return False;
+	case rfbVncAuthTooMany:
+		sprintf(msgbuf, "Authentication failed - too many tries\n\n");
+		wmsg(msgbuf, 1);
+		return False;
+	default:
+		sprintf(msgbuf, "Unknown authentication result: %d\n\n",
+		    (int)authResult);
+		wmsg(msgbuf, 1);
+		return False;
+	}
 
-  return True;
+	return True;
 }
 
 
@@ -675,19 +1764,20 @@
 static Bool
 ReadInteractionCaps(void)
 {
-  rfbInteractionCapsMsg intr_caps;
+	rfbInteractionCapsMsg intr_caps;
 
-  /* Read the counts of list items following */
-  if (!ReadFromRFBServer((char *)&intr_caps, sz_rfbInteractionCapsMsg))
-    return False;
-  intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes);
-  intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes);
-  intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes);
-
-  /* Read the lists of server- and client-initiated messages */
-  return (ReadCapabilityList(serverMsgCaps, intr_caps.nServerMessageTypes) &&
-	  ReadCapabilityList(clientMsgCaps, intr_caps.nClientMessageTypes) &&
-	  ReadCapabilityList(encodingCaps, intr_caps.nEncodingTypes));
+	/* Read the counts of list items following */
+	if (!ReadFromRFBServer((char *)&intr_caps, sz_rfbInteractionCapsMsg)) {
+		return False;
+	}
+	intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes);
+	intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes);
+	intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes);
+
+	/* Read the lists of server- and client-initiated messages */
+	return (ReadCapabilityList(serverMsgCaps, intr_caps.nServerMessageTypes) &&
+		ReadCapabilityList(clientMsgCaps, intr_caps.nClientMessageTypes) &&
+		ReadCapabilityList(encodingCaps, intr_caps.nEncodingTypes));
 }
 
 
@@ -697,22 +1787,70 @@
  * many records to read from the socket.
  */
 
-static Bool
-ReadCapabilityList(CapsContainer *caps, int count)
-{
-  rfbCapabilityInfo msginfo;
-  int i;
+static Bool
+ReadCapabilityList(CapsContainer *caps, int count)
+{
+	rfbCapabilityInfo msginfo;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo)) {
+			return False;
+		}
+		msginfo.code = Swap32IfLE(msginfo.code);
+		CapsEnable(caps, &msginfo);
+	}
+
+	return True;
+}
+
 
-  for (i = 0; i < count; i++) {
-    if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo))
-      return False;
-    msginfo.code = Swap32IfLE(msginfo.code);
-    CapsEnable(caps, &msginfo);
-  }
+/* used to have !tunnelSpecified */
 
-  return True;
+static int guess_compresslevel(void) {
+	int n;
+	if (latency > 200.0) {
+		n = 8;
+	} else if (latency > 100.0) {
+		n = 7;
+	} else if (latency > 60.0) {
+		n = 6;
+	} else if (latency > 15.0) {
+		n = 4;
+	} else if (latency > 8.0) {
+		n = 2;
+	} else if (latency > 0.0) {
+		n = 1;
+	} else {
+		/* no latency measurement */
+		n = 3;
+	}
+	return n;
 }
 
+static int guess_qualitylevel(void) {
+	int n;
+	if (latency > 200.0) {
+		n = 4;
+	} else if (latency > 100.0) {
+		n = 5;
+	} else if (latency > 60.0) {
+		n = 6;
+	} else if (latency > 15.0) {
+		n = 7;
+	} else if (latency > 8.0) {
+		n = 8;
+	} else if (latency > 0.0) {
+		n = 9;
+	} else {
+		/* no latency measurement */
+		n = 6;
+	}
+#ifdef TURBOVNC
+	n *= 10;
+#endif
+	return n;
+}
 
 /*
  * SetFormatAndEncodings.
@@ -729,6 +1867,21 @@
   Bool requestCompressLevel = False;
   Bool requestQualityLevel = False;
   Bool requestLastRectEncoding = False;
+  Bool requestNewFBSizeEncoding = True;
+  Bool requestTextChatEncoding = True;
+  Bool requestSubsampLevel = False;
+  int dsm = 0;
+  int tQL, tQLmax = 9;
+  static int qlmsg = 0, clmsg = 0;
+#ifdef TURBOVNC
+	tQLmax = 100;
+#endif
+
+	if (requestTextChatEncoding || requestSubsampLevel || tQL) {}
+
+#if 0
+  fprintf(stderr, "SetFormatAndEncodings: sent_FBU state: %2d\n", sent_FBU);
+#endif
 
   spf.type = rfbSetPixelFormat;
   spf.format = myFormat;
@@ -736,15 +1889,32 @@
   spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
   spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
 
+
+  currentMsg = rfbSetPixelFormat;
   if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg))
     return False;
 
   se->type = rfbSetEncodings;
   se->nEncodings = 0;
 
+  if (appData.ultraDSM) {
+  	dsm = 1;
+  }
+
   if (appData.encodingsString) {
     char *encStr = appData.encodingsString;
     int encStrLen;
+	if (strchr(encStr, ','))  {
+		char *p;
+		encStr = strdup(encStr);
+		p = encStr;
+		while (*p != '\0') {
+			if (*p == ',') {
+				*p = ' ';
+			}
+			p++;
+		}
+	}
     do {
       char *nextEncStr = strchr(encStr, ' ');
       if (nextEncStr) {
@@ -754,50 +1924,102 @@
 	encStrLen = strlen(encStr);
       }
 
+if (getenv("DEBUG_SETFORMAT")) {
+	fprintf(stderr, "encs: ");
+	write(2, encStr, encStrLen);
+	fprintf(stderr, "\n");
+}
+
       if (strncasecmp(encStr,"raw",encStrLen) == 0) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
       } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
-      } else if (strncasecmp(encStr,"tight",encStrLen) == 0) {
+      } else if (strncasecmp(encStr,"tight",encStrLen) == 0 && !dsm) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
 	requestLastRectEncoding = True;
-	if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
-	  requestCompressLevel = True;
-	if (appData.enableJPEG)
-	  requestQualityLevel = True;
+	if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
+		requestCompressLevel = True;
+        }
+	if (appData.enableJPEG) {
+		requestQualityLevel = True;
+        }
+#ifdef TURBOVNC
+	requestSubsampLevel = True;
+#endif
       } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
-      } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
+      } else if (strncasecmp(encStr,"zlib",encStrLen) == 0 && !dsm) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
-	if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
-	  requestCompressLevel = True;
-      } else if (strncasecmp(encStr,"corre",encStrLen) == 0) {
+	if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
+		requestCompressLevel = True;
+	}
+      } else if (strncasecmp(encStr,"corre",encStrLen) == 0 && !dsm) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
       } else if (strncasecmp(encStr,"rre",encStrLen) == 0) {
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
+      } else if (strncasecmp(encStr,"zrle",encStrLen) == 0) {
+	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE);
+#if DO_ZYWRLE
+      } else if (strncasecmp(encStr,"zywrle",encStrLen) == 0) {
+		int qlevel = appData.qualityLevel;
+		if (qlevel < 0 || qlevel > tQLmax) qlevel = guess_qualitylevel();
+		encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE);
+		requestQualityLevel = True;
+		if (qlevel < 3) {
+			zywrle_level = 3;
+		} else if (qlevel < 6) {
+			zywrle_level = 2;
+		} else {
+			zywrle_level = 1;
+		}
+#endif
       } else {
 	fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr);
+        if (dsm && strstr(encStr, "tight") == encStr) fprintf(stderr, "tight encoding does not yet work with ultraDSM, skipping it.\n");
+        if (dsm && strstr(encStr, "corre") == encStr) fprintf(stderr, "corre encoding does not yet work with ultraDSM, skipping it.\n");
+        if (dsm && strstr(encStr, "zlib" ) == encStr) fprintf(stderr, "zlib  encoding does not yet work with ultraDSM, skipping it.\n");
       }
 
       encStr = nextEncStr;
     } while (encStr && se->nEncodings < MAX_ENCODINGS);
 
     if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) {
-      encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
-					  rfbEncodingCompressLevel0);
+	;
+    } else if (se->nEncodings < MAX_ENCODINGS) {
+	appData.compressLevel = guess_compresslevel();
+	if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel);
     }
+    encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0);
 
     if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) {
-      if (appData.qualityLevel < 0 || appData.qualityLevel > 9)
-        appData.qualityLevel = 5;
-      encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
-					  rfbEncodingQualityLevel0);
+	if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) {
+		appData.qualityLevel = guess_qualitylevel();
+		if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel  %d\n", appData.qualityLevel);
+	}
+    } else if (se->nEncodings < MAX_ENCODINGS) {
+	appData.qualityLevel = guess_qualitylevel();
+	if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel  %d\n", appData.qualityLevel);
+    }
+#ifdef TURBOVNC
+    tQL = appData.qualityLevel / 10;
+    if (tQL < 0) tQL = 1;
+    if (tQL > 9) tQL = 9;
+    encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0);
+    encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1);
+    if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) {
+	if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) {
+		appData.subsampLevel = TVNC_1X;
+	}
+	encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X);
     }
+#else
+    encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0);
+#endif
 
     if (appData.useRemoteCursor) {
       if (se->nEncodings < MAX_ENCODINGS)
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
-      if (se->nEncodings < MAX_ENCODINGS)
+      if (se->nEncodings < MAX_ENCODINGS && !appData.useX11Cursor)
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
       if (se->nEncodings < MAX_ENCODINGS)
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
@@ -806,10 +2028,16 @@
     if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
       encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
     }
-  }
-  else {
+
+    if (se->nEncodings < MAX_ENCODINGS && requestNewFBSizeEncoding) {
+      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize);
+    }
+
+  } else {
+	/* DIFFERENT CASE */
+
     if (SameMachine(rfbsock)) {
-      if (!tunnelSpecified) {
+      if (!tunnelSpecified && appData.useRawLocal) {
 	fprintf(stderr,"Same machine: preferring raw encoding\n");
 	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
       } else {
@@ -818,44 +2046,84 @@
     }
 
     encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
-    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+    if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE);
     encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
-    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
-    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
+    if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+    if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
     encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
 
-    if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
-      encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
-					  rfbEncodingCompressLevel0);
-    } else if (!tunnelSpecified) {
-      /* If -tunnel option was provided, we assume that server machine is
-	 not in the local network so we use default compression level for
-	 tight encoding instead of fast compression. Thus we are
-	 requesting level 1 compression only if tunneling is not used. */
-      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1);
-    }
-
-    if (appData.enableJPEG) {
-      if (appData.qualityLevel < 0 || appData.qualityLevel > 9)
-	appData.qualityLevel = 5;
-      encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
-					  rfbEncodingQualityLevel0);
+    if (!dsm && appData.compressLevel >= 0 && appData.compressLevel <= 9) {
+	encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0);
+    } else {
+	/*
+         * OUT OF DATE: If -tunnel option was provided, we assume that server machine is
+	 * not in the local network so we use default compression level for
+	 * tight encoding instead of fast compression. Thus we are
+	 * requesting level 1 compression only if tunneling is not used.
+         */
+	appData.compressLevel = guess_compresslevel();
+	if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel);
+	encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0);
+    }
+
+    if (!dsm && appData.enableJPEG) {
+	if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) {
+		appData.qualityLevel = guess_qualitylevel();
+		if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel  %d\n", appData.qualityLevel);
+	}
+
+#ifdef TURBOVNC
+    requestSubsampLevel = True;
+    tQL = appData.qualityLevel / 10;
+    if (tQL < 0) tQL = 1;
+    if (tQL > 9) tQL = 9;
+    encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0);
+    encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1);
+    if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) {
+	if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) {
+		appData.subsampLevel = TVNC_1X;
+	}
+	encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X);
+    }
+#else
+    encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0);
+#endif
+
     }
 
     if (appData.useRemoteCursor) {
       encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
-      encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+      if (!appData.useX11Cursor) {
+      	encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+      }
       encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
     }
 
     encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+    encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize);
   }
 
   len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
 
-  se->nEncodings = Swap16IfLE(se->nEncodings);
+	if (!appData.ultraDSM) {
+		se->nEncodings = Swap16IfLE(se->nEncodings);
 
-  if (!WriteExact(rfbsock, buf, len)) return False;
+		if (!WriteExact(rfbsock, buf, len)) return False;
+	} else {
+		/* for UltraVNC encryption DSM we have to send each encoding separately (why?) */
+		int i, errs = 0, nenc = se->nEncodings;
+		
+		se->nEncodings = Swap16IfLE(se->nEncodings);
+
+		currentMsg = rfbSetEncodings;
+		if (!WriteExact(rfbsock, buf, sz_rfbSetEncodingsMsg)) errs++;
+		for (i=0; i < nenc; i++) {
+			if (!WriteExact(rfbsock, (char *)&encs[i], sizeof(CARD32))) errs++;
+		}
+		if (errs) return False;
+	}
 
   return True;
 }
@@ -868,31 +2136,86 @@
 Bool
 SendIncrementalFramebufferUpdateRequest()
 {
-  return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
-				      si.framebufferHeight, True);
+	return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+	    si.framebufferHeight, True);
 }
 
+time_t last_filexfer = 0;
+int delay_filexfer = 3;
+extern void CheckFileXfer(void);
+extern int rfbsock_is_ready(void);
+
+
+static int dyn = -1;
+extern int filexfer_sock;
+extern int filexfer_listen;
 
 /*
  * SendFramebufferUpdateRequest.
  */
-
 Bool
 SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental)
 {
-  rfbFramebufferUpdateRequestMsg fur;
+	rfbFramebufferUpdateRequestMsg fur;
+	static int db = -1;
 
-  fur.type = rfbFramebufferUpdateRequest;
-  fur.incremental = incremental ? 1 : 0;
-  fur.x = Swap16IfLE(x);
-  fur.y = Swap16IfLE(y);
-  fur.w = Swap16IfLE(w);
-  fur.h = Swap16IfLE(h);
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_RECTS")) {
+			db = atoi(getenv("SSVNC_DEBUG_RECTS"));
+		} else {
+			db = 0;
+		}
+	}
 
-  if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
-    return False;
+	if (db) fprintf(stderr, "SendFramebufferUpdateRequest(%d, %d, %d, %d, incremental=%d)\n", x, y, w, h, (int) incremental);
 
-  return True;
+	if (dyn < 0) {
+		struct stat sb;
+		if (getenv("USER") && !strcmp(getenv("USER"), "runge")) {
+			if (stat("/tmp/nodyn", &sb) == 0) {
+				putenv("NOFTFBUPDATES=1");
+				unlink("/tmp/nodyn");
+			}
+		}
+		if (getenv("NOFTFBUPDATES")) {
+			dyn = 0;
+		} else {
+			dyn = 1;
+		}
+	}
+
+	if (appData.fileActive && filexfer_sock >= 0) {
+		static int first = 1;
+		if (first) {
+			fprintf(stderr, "SFU: dynamic fb updates during filexfer: %d\n", dyn);
+			first = 0;
+		}
+if (db > 2 || 0) fprintf(stderr, "A sfur: %d %d %d %d d_last: %d\n", x, y, w, h, (int) (time(NULL) - last_filexfer));
+		if (!dyn || time(NULL) < last_filexfer + delay_filexfer) {
+			return True;
+		}
+	}
+if (db > 1) fprintf(stderr, "B sfur: %d %d %d %d\n", x, y, w, h);
+
+	fur.type = rfbFramebufferUpdateRequest;
+	fur.incremental = incremental ? 1 : 0;
+	fur.x = Swap16IfLE(x);
+	fur.y = Swap16IfLE(y);
+	fur.w = Swap16IfLE(w);
+	fur.h = Swap16IfLE(h);
+
+	if (incremental) {
+		sent_FBU = 1;
+	} else {
+		sent_FBU = 2;
+	}
+
+	currentMsg = rfbFramebufferUpdateRequest;
+	if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) {
+		return False;
+	}
+
+	return True;
 }
 
 
@@ -903,19 +2226,38 @@
 Bool
 SendPointerEvent(int x, int y, int buttonMask)
 {
-  rfbPointerEventMsg pe;
+	rfbPointerEventMsg pe;
+
+	if (appData.fileActive) {
+		if (!dyn || time(NULL) < last_filexfer + delay_filexfer) {
+#if 0
+			fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL));
+#endif
+			return True;
+		}
+	}
 
-  pe.type = rfbPointerEvent;
-  pe.buttonMask = buttonMask;
-  if (x < 0) x = 0;
-  if (y < 0) y = 0;
-
-  if (!appData.useX11Cursor)
-    SoftCursorMove(x, y);
-
-  pe.x = Swap16IfLE(x);
-  pe.y = Swap16IfLE(y);
-  return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
+	pe.type = rfbPointerEvent;
+	pe.buttonMask = buttonMask;
+
+	if (scale_factor_x > 0.0 && scale_factor_x != 1.0) {
+		x /= scale_factor_x;
+	}
+	if (scale_factor_y > 0.0 && scale_factor_y != 1.0) {
+		y /= scale_factor_y;
+	}
+
+	if (x < 0) x = 0;
+	if (y < 0) y = 0;
+
+	if (!appData.useX11Cursor) {
+		SoftCursorMove(x, y);
+	}
+
+	pe.x = Swap16IfLE(x);
+	pe.y = Swap16IfLE(y);
+	currentMsg = rfbPointerEvent;
+	return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
 }
 
 
@@ -926,12 +2268,22 @@
 Bool
 SendKeyEvent(CARD32 key, Bool down)
 {
-  rfbKeyEventMsg ke;
+	rfbKeyEventMsg ke;
+
+	if (appData.fileActive) {
+		if (!dyn || time(NULL) < last_filexfer + delay_filexfer) {
+#if 0
+			fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL));
+#endif
+			return True;
+		}
+	}
 
-  ke.type = rfbKeyEvent;
-  ke.down = down ? 1 : 0;
-  ke.key = Swap32IfLE(key);
-  return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
+	ke.type = rfbKeyEvent;
+	ke.down = down ? 1 : 0;
+	ke.key = Swap32IfLE(key);
+	currentMsg = rfbKeyEvent;
+	return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
 }
 
 
@@ -942,281 +2294,1025 @@
 Bool
 SendClientCutText(char *str, int len)
 {
-  rfbClientCutTextMsg cct;
+	rfbClientCutTextMsg cct;
+
+	if (serverCutText) {
+		free(serverCutText);
+	}
+	serverCutText = NULL;
+
+	if (appData.fileActive) {
+		if (!dyn || time(NULL) < last_filexfer + delay_filexfer) {
+			/* ultravnc java viewer lets this one through. */
+			return True;
+		}
+	}
+
+	if (appData.viewOnly) {
+		return True;
+	}
 
-  if (serverCutText)
-    free(serverCutText);
-  serverCutText = NULL;
-
-  cct.type = rfbClientCutText;
-  cct.length = Swap32IfLE(len);
-  return  (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
-	   WriteExact(rfbsock, str, len));
+	cct.type = rfbClientCutText;
+	cct.length = Swap32IfLE((unsigned int) len);
+	currentMsg = rfbClientCutText;
+	return  (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
+	    WriteExact(rfbsock, str, len));
 }
 
+static int ultra_scale = 0;
 
-/*
- * HandleRFBServerMessage.
- */
+Bool
+SendServerScale(int nfac)
+{
+	rfbSetScaleMsg ssc;
+	if (nfac < 0 || nfac > 100) {
+		return True;
+	}
+
+	ultra_scale = nfac;
+	ssc.type = rfbSetScale;
+	ssc.scale = nfac;
+	currentMsg = rfbSetScale;
+	return WriteExact(rfbsock, (char *)&ssc, sz_rfbSetScaleMsg);
+}
 
 Bool
-HandleRFBServerMessage()
+SendServerInput(Bool enabled)
 {
-  rfbServerToClientMsg msg;
+	rfbSetServerInputMsg sim;
 
-  if (!ReadFromRFBServer((char *)&msg, 1))
-    return False;
+	sim.type = rfbSetServerInput;
+	sim.status = enabled;
+	currentMsg = rfbSetServerInput;
+	return WriteExact(rfbsock, (char *)&sim, sz_rfbSetServerInputMsg);
+}
 
-  switch (msg.type) {
+Bool
+SendSingleWindow(int x, int y)
+{
+	static int w_old = -1, h_old = -1;
+	rfbSetSWMsg sw;
 
-  case rfbSetColourMapEntries:
-  {
-    int i;
-    CARD16 rgb[3];
-    XColor xc;
+	fprintf(stderr, "SendSingleWindow: %d %d\n", x, y);
 
-    if (!ReadFromRFBServer(((char *)&msg) + 1,
-			   sz_rfbSetColourMapEntriesMsg - 1))
-      return False;
+	if (x == -1 && y == -1)  {
+		sw.type = rfbSetSW;
+		sw.x = Swap16IfLE(1);
+		sw.y = Swap16IfLE(1);
+		if (w_old > 0) {
+			si.framebufferWidth  = w_old;
+			si.framebufferHeight = h_old;
+			ReDoDesktop();
+		}
+		w_old = h_old = -1;
+	} else {
+		sw.type = rfbSetSW;
+		sw.x = Swap16IfLE(x);
+		sw.y = Swap16IfLE(y);
+		w_old = si.framebufferWidth;
+		h_old = si.framebufferHeight;
+		
+	}
+	sw.status = True;
+	currentMsg = rfbSetSW;
+	return WriteExact(rfbsock, (char *)&sw, sz_rfbSetSWMsg);
+}
 
-    msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
-    msg.scme.nColours = Swap16IfLE(msg.scme.nColours);
+Bool
+SendTextChat(char *str)
+{
+	static int db = -1;
+	rfbTextChatMsg chat;
 
-    for (i = 0; i < msg.scme.nColours; i++) {
-      if (!ReadFromRFBServer((char *)rgb, 6))
-	return False;
-      xc.pixel = msg.scme.firstColour + i;
-      xc.red = Swap16IfLE(rgb[0]);
-      xc.green = Swap16IfLE(rgb[1]);
-      xc.blue = Swap16IfLE(rgb[2]);
-      xc.flags = DoRed|DoGreen|DoBlue;
-      XStoreColor(dpy, cmap, &xc);
-    }
+	if (db < 0) {
+		if (getenv("SSVNC_DEBUG_CHAT")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
+	if (!appData.chatActive) {
+		SendTextChatOpen();
+		appData.chatActive = True;
+	}
 
-    break;
-  }
+	chat.type = rfbTextChat;
+	chat.pad1 = 0;
+	chat.pad2 = 0;
+	chat.length = (unsigned int) strlen(str);
+	if (db) fprintf(stderr, "SendTextChat: %d '%s'\n", (int) chat.length, str);
+	chat.length = Swap32IfLE(chat.length);
+	if (!WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg)) {
+		return False;
+	}
+	currentMsg = rfbTextChat;
+	return WriteExact(rfbsock, str, strlen(str));
+}
 
-  case rfbFramebufferUpdate:
-  {
-    rfbFramebufferUpdateRectHeader rect;
-    int linesToRead;
-    int bytesPerLine;
-    int i;
-    int usecs;
+extern void raiseme(int force);
 
-    if (!ReadFromRFBServer(((char *)&msg.fu) + 1,
-			   sz_rfbFramebufferUpdateMsg - 1))
-      return False;
+Bool
+SendTextChatOpen(void)
+{
+	rfbTextChatMsg chat;
 
-    msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
+	raiseme(0);
+	chat.type = rfbTextChat;
+	chat.pad1 = 0;
+	chat.pad2 = 0;
+	chat.length = Swap32IfLE(rfbTextChatOpen);
+	return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg);
+}
 
-    for (i = 0; i < msg.fu.nRects; i++) {
-      if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
-	return False;
+Bool
+SendTextChatClose(void)
+{
+	rfbTextChatMsg chat;
+	chat.type = rfbTextChat;
+	chat.pad1 = 0;
+	chat.pad2 = 0;
+	chat.length = Swap32IfLE(rfbTextChatClose);
+	appData.chatActive = False;
+	return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg);
+}
 
-      rect.encoding = Swap32IfLE(rect.encoding);
-      if (rect.encoding == rfbEncodingLastRect)
-	break;
+Bool
+SendTextChatFinished(void)
+{
+	rfbTextChatMsg chat;
+	chat.type = rfbTextChat;
+	chat.pad1 = 0;
+	chat.pad2 = 0;
+	chat.length = Swap32IfLE(rfbTextChatFinished);
+	appData.chatActive = False;
+	return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg);
+}
+
+extern int do_format_change;
+extern int do_cursor_change;
+extern double do_fb_update;
+extern void cutover_format_change(void);
+
+double dtime(double *t_old) {
+        /* 
+         * usage: call with 0.0 to initialize, subsequent calls give
+         * the time difference since last call.
+         */
+        double t_now, dt;
+        struct timeval now;
+
+        gettimeofday(&now, NULL);
+        t_now = now.tv_sec + ( (double) now.tv_usec/1000000. );
+        if (*t_old == 0.0) {
+                *t_old = t_now;
+                return t_now;
+        }
+        dt = t_now - *t_old;
+        *t_old = t_now;
+        return(dt);
+}
+
+/* common dtime() activities: */
+double dtime0(double *t_old) {
+        *t_old = 0.0;
+        return dtime(t_old);
+}
+
+double dnow(void) {
+        double t;
+        return dtime0(&t);
+}
+
+static char fxfer[65536];
+
+Bool HandleFileXfer(void) {
+	unsigned char hdr[12];
+	unsigned int len;
+
+        int rfbDirContentRequest = 1;
+        int rfbDirPacket = 2; /* Full directory name or full file name. */
+        int rfbFileTransferRequest = 3;
+        int rfbFileHeader = 4;
+        int rfbFilePacket = 5; /* One slice of the file */
+        int rfbEndOfFile = 6;
+        int rfbAbortFileTransfer = 7;
+        int rfbFileTransferOffer = 8;
+        int rfbFileAcceptHeader = 9; /* The server accepts or rejects the file */
+        int rfbCommand = 10;
+        int rfbCommandReturn = 11;
+        int rfbFileChecksums = 12;
+
+        int rfbRDirContent = 1; /* Request a Server Directory contents */
+        int rfbRDrivesList = 2; /* Request the server's drives list */
+
+        int rfbADirectory = 1; /* Reception of a directory name */
+        int rfbAFile = 2; /* Reception of a file name  */
+        int rfbADrivesList = 3; /* Reception of a list of drives */
+        int rfbADirCreate = 4; /* Response to a create dir command  */
+        int rfbADirDelete = 5; /* Response to a delete dir command  */
+        int rfbAFileCreate = 6; /* Response to a create file command  */
+        int rfbAFileDelete = 7; /* Response to a delete file command */
+
+        int rfbCDirCreate = 1; /* Request the server to create the given directory */
+        int rfbCDirDelete = 2; /* Request the server to delete the given directory */
+        int rfbCFileCreate = 3; /* Request the server to create the given file */
+        int rfbCFileDelete = 4; /* Request the server to delete the given file */
+
+        int rfbRErrorUnknownCmd = 1; /* Unknown FileTransfer command. */
+#define rfbRErrorCmd 0xFFFFFFFF
+
+	static int db = -1;
+	static int guess_x11vnc = 0;
+
+#if 0
+	if (filexfer_sock < 0) {
+		return True;
+	}
+	/* instead, we read and discard the ft msg data. */
+#endif
+
+/*fprintf(stderr, "In  HandleFileXfer\n"); */
 
-      rect.r.x = Swap16IfLE(rect.r.x);
-      rect.r.y = Swap16IfLE(rect.r.y);
-      rect.r.w = Swap16IfLE(rect.r.w);
-      rect.r.h = Swap16IfLE(rect.r.h);
-
-      if (rect.encoding == rfbEncodingXCursor ||
-	  rect.encoding == rfbEncodingRichCursor) {
-	if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h,
-			      rect.encoding)) {
-	  return False;
+	if (db < 0) {
+		if (getenv("DEBUG_HandleFileXfer")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
 	}
-	continue;
-      }
 
-      if (rect.encoding == rfbEncodingPointerPos) {
-	if (!HandleCursorPos(rect.r.x, rect.r.y)) {
-	  return False;
+	last_filexfer = time(NULL);
+	/*fprintf(stderr, "last_filexfer-1: %d\n", last_filexfer); */
+
+	/* load first byte to send to Java be the FT msg number: */
+	hdr[0] = rfbFileTransfer;
+
+	/* this is to avoid XtAppProcessEvent() calls induce by our ReadFromRFBServer calls below: */
+	skip_XtUpdateAll = 1;
+	if (!ReadFromRFBServer(&hdr[1], 11)) {
+		skip_XtUpdateAll = 0;
+		return False;
+	}
+	if (filexfer_sock >= 0) {
+		write(filexfer_sock, hdr, 12);
+	} else {
+		fprintf(stderr, "filexfer_sock closed, discarding 12 bytes\n");
+	}
+	if (db) fprintf(stderr, "\n");
+	if (db) fprintf(stderr, "Got rfbFileTransfer hdr\n");
+	if (db > 1) write(2, hdr, 12);
+
+	if (db) {
+		int i;
+		fprintf(stderr, "HFX HDR:");
+		for (i=0; i < 12; i++) {
+			fprintf(stderr, " %d", (int) hdr[i]);
+		}
+		fprintf(stderr, "\n");
 	}
-	continue;
-      }
 
-      if ((rect.r.x + rect.r.w > si.framebufferWidth) ||
-	  (rect.r.y + rect.r.h > si.framebufferHeight))
-	{
-	  fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n",
-		  rect.r.w, rect.r.h, rect.r.x, rect.r.y);
-	  return False;
+	if (hdr[1] == rfbEndOfFile) {
+		goto read_no_more;
+	} else if (hdr[1] == rfbAbortFileTransfer) {
+		goto read_no_more;
 	}
 
-      if (rect.r.h * rect.r.w == 0) {
-	fprintf(stderr,"Zero size rect - ignoring\n");
-	continue;
-      }
+	if (hdr[1] == rfbDirPacket && hdr[3] == rfbADirectory) {
+		
+	}
+
+	len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11];
+	if (db) fprintf(stderr, "Got rfbFileTransfer: len1 %u\n", len);
+	if (len > 0) {
+		if (!ReadFromRFBServer(fxfer, len)) {
+			skip_XtUpdateAll = 0;
+			return False;
+		}
+		if (db > 1) write(2, fxfer, len);
+		if (len >= 12 && hdr[1] == rfbDirPacket) {
+			/* try to guess if x11vnc or not... */
+			if (db) {
+				int i;
+				fprintf(stderr, "HFX DIR PKT (attr, timeL, timeH):");
+				for (i=0; i < 12; i++) {
+					fprintf(stderr, " %d", (unsigned char) fxfer[i]);
+				}
+				fprintf(stderr, "\n");
+			}
+			if (hdr[2] == 1) {
+				int dattr  = (unsigned char) fxfer[0];
+				int timeL1 = (unsigned char) fxfer[4];
+				int timeL2 = (unsigned char) fxfer[5];
+				int timeL3 = (unsigned char) fxfer[6];
+				int timeL4 = (unsigned char) fxfer[7];
+				int timeH1 = (unsigned char) fxfer[8];
+				int timeH2 = (unsigned char) fxfer[9];
+				int timeH3 = (unsigned char) fxfer[10];
+				int timeH4 = (unsigned char) fxfer[11];
+				if (dattr != 0) {
+					if (timeH1 == 0 && timeH2 == 0 && timeH3 == 0 && timeH4 == 0) {
+						if ((timeL1 != 0 || timeL2 != 0) && timeL3 != 0 && timeL4 != 0) {
+							if (!guess_x11vnc) fprintf(stderr, "guessed x11vnc server\n");
+							guess_x11vnc = 1;
+						}
+					}
+				}
+			}
+		}
+		if (db && 0) fprintf(stderr, "\n");
+		if (filexfer_sock >= 0) {
+			write(filexfer_sock, fxfer, len);
+		} else {
+			fprintf(stderr, "filexfer_sock closed, discarding %d bytes\n", len);
+		}
+	}
+
+	len = (hdr[4] << 24) | (hdr[5] << 16) | (hdr[6] << 8) | hdr[7];
+	if (db) fprintf(stderr, "Got rfbFileTransfer: len2 %u\n", len);
+
+#if 0
+	if (hdr[1] == rfbFileHeader && len != rfbRErrorCmd)
+#else
+	/* the extra 4 bytes get send on rfbRErrorCmd as well. */
+	if (hdr[1] == rfbFileHeader) {
+#endif
+		int is_err = 0;
+		if (len == rfbRErrorCmd) {
+			is_err = 1;
+		}
+		if (db) fprintf(stderr, "Got rfbFileTransfer: rfbFileHeader\n");
+		if (is_err && guess_x11vnc) {
+			fprintf(stderr, "rfbRErrorCmd x11vnc skip read 4 bytes.\n");
+			goto read_no_more;
+		}
+		len = 4;
+		if (!ReadFromRFBServer(fxfer, len)) {
+			skip_XtUpdateAll = 0;
+			return False;
+		}
+		if (db > 1) write(2, fxfer, len);
+		if (db && 0) fprintf(stderr, "\n");
+		if (is_err) {
+			fprintf(stderr, "rfbRErrorCmd skip write 4 bytes.\n");
+			goto read_no_more;
+		}
+		if (filexfer_sock >= 0) {
+			write(filexfer_sock, fxfer, len);
+		} else {
+			fprintf(stderr, "filexfer_sock closed, discarding %d bytes\n", len);
+		}
+	}
 
-      /* If RichCursor encoding is used, we should prevent collisions
-	 between framebuffer updates and cursor drawing operations. */
-      SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+	read_no_more:
 
-      switch (rect.encoding) {
+	if (filexfer_sock < 0) {
+		int stop = 0;
+		static time_t last_stop = 0;
+#if 0
+		/* this isn't working */
+		if (hdr[1] == rfbFilePacket || hdr[1] == rfbFileHeader) {
+			fprintf(stderr, "filexfer_sock closed, trying to abort receive\n");
+			stop = 1;
+		}
+#endif
+		if (stop && time(NULL) > last_stop+1) {
+			unsigned char rpl[12];
+			int k;
+			rpl[0] = rfbFileTransfer;
+			rpl[1] = rfbAbortFileTransfer;
+			for (k=2; k < 12; k++) {
+				rpl[k] = 0;
+			}
+			WriteExact(rfbsock, rpl, 12);
+			last_stop = time(NULL);
+		}
+	}
 
-      case rfbEncodingRaw:
+	if (db) fprintf(stderr, "Got rfbFileTransfer done.\n");
+	skip_XtUpdateAll = 0;
 
-	bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
-	linesToRead = BUFFER_SIZE / bytesPerLine;
+	if (db) fprintf(stderr, "CFX: B\n");
+	CheckFileXfer();
+/*fprintf(stderr, "Out HandleFileXfer\n"); */
+	return True;
+}
 
-	while (rect.r.h > 0) {
-	  if (linesToRead > rect.r.h)
-	    linesToRead = rect.r.h;
+/*
+ * HandleRFBServerMessage.
+ */
 
-	  if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead))
-	    return False;
 
-	  CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w,
-			   linesToRead);
+Bool
+HandleRFBServerMessage()
+{
+	static int db = -1;
+	rfbServerToClientMsg msg;
 
-	  rect.r.h -= linesToRead;
-	  rect.r.y += linesToRead;
+	if (db < 0) {
+		if (getenv("DEBUG_RFB_SMSG")) {
+			db = 1;
+		} else {
+			db = 0;
+		}
+	}
 
+	if (!ReadFromRFBServer((char *)&msg, 1)) {
+		return False;
 	}
-	break;
+	if (appData.ultraDSM) {
+		if (!ReadFromRFBServer((char *)&msg, 1)) {
+			return False;
+		}
+	}
+
+/*fprintf(stderr, "msg.type: %d\n", msg.type); */
 
-      case rfbEncodingCopyRect:
-      {
-	rfbCopyRect cr;
-
-	if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect))
-	  return False;
-
-	cr.srcX = Swap16IfLE(cr.srcX);
-	cr.srcY = Swap16IfLE(cr.srcY);
-
-	/* If RichCursor encoding is used, we should extend our
-	   "cursor lock area" (previously set to destination
-	   rectangle) to the source rectangle as well. */
-	SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
-
-	if (appData.copyRectDelay != 0) {
-	  XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
-			 rect.r.w, rect.r.h);
-	  XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
-			 rect.r.w, rect.r.h);
-	  XSync(dpy,False);
-	  usleep(appData.copyRectDelay * 1000);
-	  XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
-			 rect.r.w, rect.r.h);
-	  XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
-			 rect.r.w, rect.r.h);
+	if (msg.type == rfbFileTransfer) {
+		return HandleFileXfer();
 	}
 
-	XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY,
-		  rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+    switch (msg.type) {
 
-	break;
-      }
+    case rfbSetColourMapEntries:
+    {
+	int i;
+	CARD16 rgb[3];
+	XColor xc;
 
-      case rfbEncodingRRE:
-      {
-	switch (myFormat.bitsPerPixel) {
-	case 8:
-	  if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 16:
-	  if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 32:
-	  if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
+	if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) {
+		return False;
 	}
-	break;
-      }
 
-      case rfbEncodingCoRRE:
-      {
-	switch (myFormat.bitsPerPixel) {
-	case 8:
-	  if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 16:
-	  if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 32:
-	  if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
+	msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
+	msg.scme.nColours = Swap16IfLE(msg.scme.nColours);
+
+	for (i = 0; i < msg.scme.nColours; i++) {
+		if (!ReadFromRFBServer((char *)rgb, 6)) {
+			return False;
+		}
+		xc.pixel = msg.scme.firstColour + i;
+		xc.red = Swap16IfLE(rgb[0]);
+		xc.green = Swap16IfLE(rgb[1]);
+		xc.blue = Swap16IfLE(rgb[2]);
+		if (appData.useGreyScale) {
+			int ave = (xc.red + xc.green + xc.blue)/3;
+			xc.red   = ave;
+			xc.green = ave;
+			xc.blue  = ave;
+		}
+		xc.flags = DoRed|DoGreen|DoBlue;
+		XStoreColor(dpy, cmap, &xc);
 	}
+
 	break;
-      }
+    }
+
+    case rfbFramebufferUpdate:
+    {
+	rfbFramebufferUpdateRectHeader rect;
+	int linesToRead;
+	int bytesPerLine;
+	int i;
+
+	int area_copyrect = 0;
+	int area_tight = 0;
+	int area_zrle = 0;
+	int area_raw = 0;
+	static int rdb = -1;
+	static int delay_sync = -1;
+	static int delay_sync_env = -1;
+	int try_delay_sync = 0;
+	int cnt_pseudo = 0;
+	int cnt_image  = 0;
+
+	int skip_incFBU = 0;
+
+	if (db) fprintf(stderr, "FBU-0:    %.6f\n", dnow());
+	if (rdb < 0) {
+		if (getenv("SSVNC_DEBUG_RECTS")) {
+			rdb = atoi(getenv("SSVNC_DEBUG_RECTS"));
+		} else {
+			rdb = 0;
+		}
+	}
+	if (delay_sync < 0) {
+		if (getenv("SSVNC_DELAY_SYNC")) {
+			delay_sync = atoi(getenv("SSVNC_DELAY_SYNC"));
+			delay_sync_env = delay_sync;
+		} else {
+			delay_sync = 0;
+		}
+	}
+
+	sent_FBU = -1;
 
-      case rfbEncodingHextile:
-      {
-	switch (myFormat.bitsPerPixel) {
-	case 8:
-	  if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 16:
-	  if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 32:
-	  if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
+	if (appData.pipelineUpdates) {
+		/* turbovnc speed idea */
+		XEvent ev;
+		memset(&ev, 0, sizeof(ev));
+		ev.xclient.type = ClientMessage;
+		ev.xclient.window = XtWindow(desktop);
+		ev.xclient.message_type = XA_INTEGER;
+		ev.xclient.format = 8;
+		strcpy(ev.xclient.data.b, "SendRFBUpdate");
+		XSendEvent(dpy, XtWindow(desktop), False, 0, &ev);
 	}
-	break;
-      }
 
-      case rfbEncodingZlib:
-      {
-	switch (myFormat.bitsPerPixel) {
-	case 8:
-	  if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 16:
-	  if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 32:
-	  if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
+	if (!ReadFromRFBServer(((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) {
+		return False;
 	}
-	break;
-     }
 
-      case rfbEncodingTight:
-      {
-	switch (myFormat.bitsPerPixel) {
-	case 8:
-	  if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 16:
-	  if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
-	case 32:
-	  if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
-	    return False;
-	  break;
+	msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
+
+	if (rdb) fprintf(stderr, "Begin rect loop %d\n", msg.fu.nRects);
+
+	if (delay_sync) {
+		try_delay_sync = 1;
+	} else {
+		if (delay_sync_env != -1 && delay_sync_env == 0) {
+			;
+		} else if (appData.yCrop > 0) {
+			;
+		} else if (scale_factor_x > 0.0 && scale_factor_x != 1.0) {
+			;
+		} else if (scale_factor_y > 0.0 && scale_factor_y != 1.0) {
+			;
+		} else {
+			static int msg = 0;
+			/* fullScreen? */
+			/* useXserverBackingStore? */
+			/* useX11Cursor & etc? */
+			/* scrollbars? */
+			if (!msg) {
+				fprintf(stderr, "enabling 'delay_sync' mode for faster local drawing,\ndisable via env SSVNC_DELAY_SYNC=0 if there are painting errors.\n"); 
+				msg = 1;
+			}
+			try_delay_sync = 1;
+		}
+	}
+	if (try_delay_sync) {
+		skip_maybe_sync = 1;
+	}
+#define STOP_DELAY_SYNC \
+	if (try_delay_sync) { \
+		if (cnt_image && skip_maybe_sync) { \
+			XSync(dpy, False); \
+		} \
+		try_delay_sync = 0; \
+		skip_maybe_sync = 0; \
 	}
-	break;
-      }
 
-      default:
-	fprintf(stderr,"Unknown rect encoding %d\n",
-		(int)rect.encoding);
-	return False;
-      }
+	for (i = 0; i < msg.fu.nRects; i++) {
+		if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) {
+			return False;
+		}
+
+		rect.encoding = Swap32IfLE(rect.encoding);
+		if (rect.encoding == rfbEncodingLastRect) {
+			break;
+		}
+
+		rect.r.x = Swap16IfLE(rect.r.x);
+		rect.r.y = Swap16IfLE(rect.r.y);
+		rect.r.w = Swap16IfLE(rect.r.w);
+		rect.r.h = Swap16IfLE(rect.r.h);
+
+		if (rdb > 1) fprintf(stderr, "nRects: %d  i=%d enc: %d   %dx%d+%d+%d\n", msg.fu.nRects, i, (int) rect.encoding, rect.r.w, rect.r.h, rect.r.x, rect.r.y); 
+			
+		if (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) {
+			cnt_pseudo++;
+			STOP_DELAY_SYNC	
+			
+			if (db) fprintf(stderr, "FBU-Cur1  %.6f\n", dnow());
+			if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rect.encoding)) {
+				return False;
+			}
+			if (db) fprintf(stderr, "FBU-Cur2  %.6f\n", dnow());
+			continue;
+		}
+
+		if (rect.encoding == rfbEncodingPointerPos) {
+			cnt_pseudo++;
+			STOP_DELAY_SYNC	
+			if (db) fprintf(stderr, "FBU-Pos1  %.6f\n", dnow());
+			if (0) fprintf(stderr, "CursorPos: %d %d / %d %d\n", rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+			if (ultra_scale > 0) {
+				int f = ultra_scale;
+				if (!HandleCursorPos(rect.r.x/f, rect.r.y/f)) {
+					return False;
+				}
+			} else {
+				if (!HandleCursorPos(rect.r.x, rect.r.y)) {
+					return False;
+				}
+			}
+			if (db) fprintf(stderr, "FBU-Pos2  %.6f\n", dnow());
+			continue;
+		}
+		if (rect.encoding == rfbEncodingNewFBSize) {
+			cnt_pseudo++;
+			STOP_DELAY_SYNC	
+			if (appData.chatOnly) {
+				continue;
+			}
+			fprintf(stderr,"New Size: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			si.framebufferWidth = rect.r.w;
+			si.framebufferHeight = rect.r.h;
+			/*fprintf(stderr, "si: %d %d\n", si.framebufferWidth, si.framebufferHeight); */
+			ReDoDesktop();
+			continue;
+		}
+		if (rdb) fprintf(stderr,"Rect: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+		cnt_image++;
+
+		if (appData.ultraDSM) {
+			/*
+			 * What a huge mess the UltraVNC DSM plugin is!!!
+			 * We read and ignore their little "this much data" hint...
+			 */
+			switch (rect.encoding)
+			{
+			case rfbEncodingRaw:
+			case rfbEncodingRRE:
+			case rfbEncodingCoRRE:
+			case rfbEncodingHextile:
+			/*case rfbEncodingUltra: */
+/*			case rfbEncodingZlib: */
+			/*case rfbEncodingXOR_Zlib: */
+			/*case rfbEncodingXORMultiColor_Zlib: */
+			/*case rfbEncodingXORMonoColor_Zlib: */
+			/*case rfbEncodingSolidColor: */
+			case rfbEncodingTight:
+			case rfbEncodingZlibHex:
+			case rfbEncodingZRLE:
+			case rfbEncodingZYWRLE:
+			    {
+				CARD32 discard;
+				ReadFromRFBServer((char *)&discard, sizeof(CARD32));
+			    }
+			    break;
+			}
+		}
+
+		if ((rect.r.x + rect.r.w > si.framebufferWidth) ||
+		    (rect.r.y + rect.r.h > si.framebufferHeight)) {
+			if (!appData.chatOnly) {
+				fprintf(stderr,"Rect too large: %dx%d at (%d, %d) encoding=%d\n",
+				rect.r.w, rect.r.h, rect.r.x, rect.r.y, (int) rect.encoding);
+				return False;
+			}
+		}
+
+		if (rect.r.h * rect.r.w == 0) {
+			fprintf(stderr,"*** Warning *** Zero size rect: %dx%d+%d+%d  encoding=%d\n",
+			    rect.r.w, rect.r.h, rect.r.x, rect.r.y, (int) rect.encoding);
+			if (0) continue;
+		}
+
+		/* If RichCursor encoding is used, we should prevent collisions
+		   between framebuffer updates and cursor drawing operations. */
+		if (db) fprintf(stderr, "FBU-SCL1  %.6f\n", dnow());
+
+		SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+
+		if (db) fprintf(stderr, "FBU-SCL2  %.6f\n", dnow());
+
+
+		switch (rect.encoding) {
+
+		case rfbEncodingRaw:
+
+			bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
+			linesToRead = BUFFER_SIZE / bytesPerLine;
+
+			if (db) fprintf(stderr, "Raw:     %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			area_raw += rect.r.w * rect.r.h;
+
+			while (rect.r.h > 0) {
+				if (linesToRead > rect.r.h) {
+					linesToRead = rect.r.h;
+				}
+
+				if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) {
+					return False;
+				}
+
+				CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, linesToRead);
+
+				rect.r.h -= linesToRead;
+				rect.r.y += linesToRead;
+			}
+			break;
+
+		case rfbEncodingCopyRect:
+		{
+			rfbCopyRect cr;
+
+			STOP_DELAY_SYNC	
+			XSync(dpy, False);
+
+			if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) {
+				return False;
+			}
+			if (appData.chatOnly) {
+				break;
+			}
+
+			cr.srcX = Swap16IfLE(cr.srcX);
+			cr.srcY = Swap16IfLE(cr.srcY);
+
+			if (db) fprintf(stderr, "Copy:    %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			area_copyrect += rect.r.w * rect.r.h;
+
+			/* If RichCursor encoding is used, we should extend our
+			   "cursor lock area" (previously set to destination
+			   rectangle) to the source rectangle as well. */
+
+			if (db) fprintf(stderr, "FBU-SCL3  %.6f\n", dnow());
+
+			SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
+
+			if (db) fprintf(stderr, "FBU-SCL4  %.6f\n", dnow());
+
+			if (appData.copyRectDelay != 0) {
+				XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h);
+				XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+				XSync(dpy,False);
+				usleep(appData.copyRectDelay * 1000);
+				XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+				XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h);
+			}
+
+			if (db) fprintf(stderr, "FBU-CPA1  %.6f\n", dnow());
+			if (!appData.useXserverBackingStore) {
+				copy_rect(rect.r.x, rect.r.y, rect.r.w, rect.r.h, cr.srcX, cr.srcY);
+				put_image(rect.r.x, rect.r.y, rect.r.x, rect.r.y, rect.r.w, rect.r.h, 0);
+				XSync(dpy, False);
+			} else {
+				XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY,
+				    rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			}
+			if (db) fprintf(stderr, "FBU-CPA2  %.6f\n", dnow());
+
+			break;
+		}
+
+		case rfbEncodingRRE:
+		{
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 32:
+				if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			}
+			break;
+		}
+
+		case rfbEncodingCoRRE:
+		{
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 32:
+				if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			}
+			break;
+		}
+
+		case rfbEncodingHextile:
+		{
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 32:
+				if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			}
+			break;
+		}
+
+		case rfbEncodingZlib:
+		{
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 32:
+				if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			}
+			break;
+		}
+
+		case rfbEncodingTight:
+		{
+			if (db) fprintf(stderr, "Tight:   %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			area_tight += rect.r.w * rect.r.h;
+			if (db) fprintf(stderr, "FBU-TGH1  %.6f\n", dnow());
+
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 32:
+				if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			}
+			if (db) fprintf(stderr, "FBU-TGH2  %.6f\n", dnow());
+			break;
+		}
+
+		/* runge adds zrle and zywrle: */
+		case rfbEncodingZRLE:
+#if DO_ZYWRLE
+		zywrle_level = 0;
+		case rfbEncodingZYWRLE:
+#endif
+		{
+			if (db) fprintf(stderr, "ZRLE:    %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+			area_zrle += rect.r.w * rect.r.h;
+			switch (myFormat.bitsPerPixel) {
+			case 8:
+				if (!HandleZRLE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			case 16:
+				if (myFormat.greenMax > 0x1f) {
+					if (!HandleZRLE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else {
+					if (!HandleZRLE15(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				}
+				break;
+			case 32:
+			    {
+				unsigned int maxColor=(myFormat.redMax<<myFormat.redShift)|
+				    (myFormat.greenMax<<myFormat.greenShift)|
+				    (myFormat.blueMax<<myFormat.blueShift);
+				static int ZRLE32 = -1;
+
+				if (ZRLE32 < 0) {
+					/* for debugging or workaround e.g. BE display to LE */
+					if (getenv("ZRLE32")) {
+						if (strstr(getenv("ZRLE32"), "24Up")) {
+							ZRLE32 = 3;
+						} else if (strstr(getenv("ZRLE32"), "24Down")) {
+							ZRLE32 = 2;
+						} else {
+							ZRLE32 = 1;
+						}
+					} else {
+						ZRLE32 = 0;
+					}
+				}
+
+if (db) fprintf(stderr, "maxColor: 0x%x  mfbigEnding: %d\n", maxColor, myFormat.bigEndian);
+
+				if (ZRLE32 == 1) {
+if (db) fprintf(stderr, "HandleZRLE32\n");
+					if (!HandleZRLE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if (ZRLE32 == 2) {
+if (db) fprintf(stderr, "HandleZRLE24Down\n");
+					if (!HandleZRLE24Down(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if (ZRLE32 == 3) {
+if (db) fprintf(stderr, "HandleZRLE24Up\n");
+					if (!HandleZRLE24Up(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if ((myFormat.bigEndian && (maxColor&0xff)==0) || (!myFormat.bigEndian && (maxColor&0xff000000)==0)) {
+if (db) fprintf(stderr, "HandleZRLE24\n");
+					if (!HandleZRLE24(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if (!myFormat.bigEndian && (maxColor&0xff)==0) {
+if (db) fprintf(stderr, "HandleZRLE24Up\n");
+					if (!HandleZRLE24Up(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if (myFormat.bigEndian && (maxColor&0xff000000)==0) {
+if (db) fprintf(stderr, "HandleZRLE24Down\n");
+					if (!HandleZRLE24Down(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+						return False;
+					}
+				} else if (!HandleZRLE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) {
+					return False;
+				}
+				break;
+			    }
+			}
+			break;
+		}
+
+		default:
+		fprintf(stderr,"Unknown rect encoding %d\n", (int)rect.encoding);
+		return False;
+		}
 
-      /* Now we may discard "soft cursor locks". */
-      SoftCursorUnlockScreen();
-    }
+		/* Now we may discard "soft cursor locks". */
+		if (db) fprintf(stderr, "FBU-SUL1  %.6f\n", dnow());
+
+		SoftCursorUnlockScreen();
+
+		if (db) fprintf(stderr, "FBU-SUL2  %.6f\n", dnow());
+	}
+
+	if (try_delay_sync) {
+		skip_maybe_sync = 0;
+	}
+
+	if (1 || area_copyrect) {
+		/* we always do this now for some reason... */
+		if (db) fprintf(stderr, "FBU-XSN1  %.6f\n", dnow());
+		XSync(dpy, False);
+		if (db) fprintf(stderr, "FBU-XSN2  %.6f\n", dnow());
+	}
+	sent_FBU = 0;
+	/*
+	 * we need to be careful since Xt events are processed
+	 * usually in the middle of FBU.  So we do any scheduled ones now
+	 * which is pretty safe but not absolutely safe.
+         */
+	if (do_format_change) {
+		cutover_format_change();
+		do_format_change = 0;
+		SetVisualAndCmap();
+		SetFormatAndEncodings();
+		if (do_cursor_change) {
+			if (do_cursor_change == 1) {
+				DesktopCursorOff();
+			}
+			do_cursor_change = 0;
+		} else {
+			SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+			    si.framebufferHeight, False);
+			skip_incFBU = 1;
+		}
+	}
+	if (do_fb_update != 0.0) {
+		if (dnow() > do_fb_update + 1.1) {
+			do_fb_update = 0.0;
+			SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+			    si.framebufferHeight, False);
+		}
+	}
 
 #ifdef MITSHM
     /* if using shared memory PutImage, make sure that the X server has
@@ -1224,59 +3320,168 @@
        mainly to avoid copyrect using invalid screen contents - not sure
        if we'd need it otherwise. */
 
-    if (appData.useShm)
-      XSync(dpy, False);
+	if (appData.useShm) {
+		XSync(dpy, False);
+	} else
 #endif
+	{
+		/* we do it always now. */
+		XSync(dpy, False);
+	}
+	
+	if (skip_XtUpdate || skip_incFBU) {
+		;
+	} else if (appData.pipelineUpdates) {
+		;
+	} else if (!SendIncrementalFramebufferUpdateRequest()) {
+		return False;
+	}
 
-    if (!SendIncrementalFramebufferUpdateRequest())
-      return False;
-
-    break;
+	break;
   }
 
   case rfbBell:
   {
-    Window toplevelWin;
+	Window toplevelWin;
 
-    XBell(dpy, 0);
+	if (appData.useBell) {
+		XBell(dpy, 0);
+	}
+
+	if (appData.raiseOnBeep) {
+		toplevelWin = XtWindow(toplevel);
+		XMapRaised(dpy, toplevelWin);
+	}
 
-    if (appData.raiseOnBeep) {
-      toplevelWin = XtWindow(toplevel);
-      XMapRaised(dpy, toplevelWin);
+	break;
     }
 
-    break;
-  }
+    case rfbServerCutText:
+    {
+	if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbServerCutTextMsg - 1)) {
+		return False;
+	}
 
-  case rfbServerCutText:
-  {
-    if (!ReadFromRFBServer(((char *)&msg) + 1,
-			   sz_rfbServerCutTextMsg - 1))
-      return False;
+	msg.sct.length = Swap32IfLE(msg.sct.length);
 
-    msg.sct.length = Swap32IfLE(msg.sct.length);
+	if (serverCutText) {
+		free(serverCutText);
+	}
 
-    if (serverCutText)
-      free(serverCutText);
+	serverCutText = malloc(msg.sct.length+1);
 
-    serverCutText = malloc(msg.sct.length+1);
+	if (!ReadFromRFBServer(serverCutText, msg.sct.length)) {
+		return False;
+	}
 
-    if (!ReadFromRFBServer(serverCutText, msg.sct.length))
-      return False;
+	serverCutText[msg.sct.length] = 0;
 
-    serverCutText[msg.sct.length] = 0;
+	newServerCutText = True;
 
-    newServerCutText = True;
+	break;
+    }
 
-    break;
-  }
+    case rfbTextChat:
+    {
+	char *buffer = NULL;
+	if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbTextChatMsg - 1)) {
+		return False;
+	}
+	msg.tc.length = Swap32IfLE(msg.tc.length);
+	switch(msg.tc.length) {
+	case rfbTextChatOpen:
+		if (appData.termChat) {
+			printChat("\n*ChatOpen*\n\nSend: ", True);
+		} else {
+			printChat("\n*ChatOpen*\n", True);
+		}
+		appData.chatActive = True;
+		break;
+	case rfbTextChatClose:
+		printChat("\n*ChatClose*\n", False);
+		appData.chatActive = False;
+		break;
+	case rfbTextChatFinished:
+		printChat("\n*ChatFinished*\n", False);
+		appData.chatActive = False;
+		break;
+	default:
+		buffer = (char *)malloc(msg.tc.length+1);
+		if (!ReadFromRFBServer(buffer, msg.tc.length)) {
+			free(buffer);
+			return False;
+		}
+		buffer[msg.tc.length] = '\0';
+		appData.chatActive = True;
+		GotChatText(buffer, msg.tc.length);
+		free(buffer);
+	}
+	break;
+    }
 
-  default:
-    fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
-    return False;
-  }
+    case rfbResizeFrameBuffer:
+    {
+	rfbResizeFrameBufferMsg rsmsg;
+	if (!ReadFromRFBServer(((char *)&rsmsg) + 1, sz_rfbResizeFrameBufferMsg - 1)) {
+		return False;
+	}
+	si.framebufferWidth  = Swap16IfLE(rsmsg.framebufferWidth);
+	si.framebufferHeight = Swap16IfLE(rsmsg.framebufferHeight);
+	fprintf(stderr,"UltraVNC ReSize: %dx%d\n", si.framebufferWidth, si.framebufferHeight);
+	ReDoDesktop();
+	break;
+    }
 
-  return True;
+    case rfbRestartConnection:
+    {
+	rfbRestartConnectionMsg rc;
+	int len;
+	char *rs_str;
+	char buf[5] = "\xff\xff\xff\xff";
+	fprintf(stderr, "rfbRestartConnection. type=%d\n", (int) rc.type);
+	if (!ReadFromRFBServer((char *)&rc + 1, sz_rfbRestartConnectionMsg - 1)) {
+		return False;
+	}
+	len = Swap32IfLE(rc.length);
+	fprintf(stderr, "rfbRestartConnection. pad1=%d\n", (int) rc.pad1);
+	fprintf(stderr, "rfbRestartConnection. pad2=%d\n", (int) rc.pad2);
+	fprintf(stderr, "rfbRestartConnection. len=%d\n", len);
+	if (len) {
+		rs_str = (char *)malloc(2*len);	
+		if (!ReadFromRFBServer(rs_str, len)) {
+			return False;
+		}
+		restart_session_pw = rs_str;
+		restart_session_len = len;
+	}
+	if (!WriteExact(rfbsock, buf, 4)) {
+		return False;
+	}
+	InitialiseRFBConnection();
+	SetVisualAndCmap();
+	SetFormatAndEncodings();
+	DesktopCursorOff();
+	SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False);
+
+	break;
+    }
+
+    default:
+	fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
+	return False;
+    }
+
+	if (appData.fileActive) {
+		if (filexfer_sock < 0 && filexfer_listen < 0) {
+			appData.fileActive = False;
+			SendFramebufferUpdateRequest(0, 0, 1, 1, False);
+		} else {
+/*fprintf(stderr, "CFX: A\n"); */
+			CheckFileXfer();
+		}
+	}
+
+    return True;
 }
 
 
@@ -1296,26 +3501,93 @@
 #define CONCAT2(a,b) a##b
 #define CONCAT2E(a,b) CONCAT2(a,b)
 
+#define CONCAT3(a,b,c) a##b##c
+#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
+
+static unsigned char* frameBuffer = NULL;
+static int frameBufferLen = 0;
+
+#ifdef TURBOVNC
+#include "turbovnc/turbojpeg.h"
+tjhandle tjhnd=NULL;
+static char *compressedData = NULL;
+static char *uncompressedData = NULL;
+#define CopyDataToImage CopyDataToScreen
+static void turbovnc_FillRectangle(XGCValues *gcv, int rx, int ry, int rw, int rh) {
+	if (!appData.useXserverBackingStore) {
+		FillScreen(rx, ry, rw, rh, gcv->foreground);
+	} else {
+		XChangeGC(dpy, gc, GCForeground, gcv);
+		XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
+	}
+}
+static void CopyImageToScreen(int x, int y, int w, int h) {
+	put_image(x, y, x, y, w, h, 0);
+}
+#endif
+
 #define BPP 8
 #include "rre.c"
 #include "corre.c"
 #include "hextile.c"
 #include "zlib.c"
+
+#ifdef TURBOVNC
+#undef FillRectangle
+#define FillRectangle turbovnc_FillRectangle
+#include "turbovnc/tight.c"
+#undef FillRectangle
+#else
 #include "tight.c"
+#endif
+
+#include "zrle.c"
 #undef BPP
+
 #define BPP 16
 #include "rre.c"
 #include "corre.c"
 #include "hextile.c"
 #include "zlib.c"
+
+#ifdef TURBOVNC
+#undef FillRectangle
+#define FillRectangle turbovnc_FillRectangle
+#include "turbovnc/tight.c"
+#undef FillRectangle
+#else
 #include "tight.c"
+#endif
+
+#include "zrle.c"
+#define REALBPP 15
+#include "zrle.c"
 #undef BPP
+
 #define BPP 32
 #include "rre.c"
 #include "corre.c"
 #include "hextile.c"
 #include "zlib.c"
+
+#ifdef TURBOVNC
+#undef FillRectangle
+#define FillRectangle turbovnc_FillRectangle
+#include "turbovnc/tight.c"
+#undef FillRectangle
+#else
 #include "tight.c"
+#endif
+
+#include "zrle.c"
+#define REALBPP 24
+#include "zrle.c"
+#define REALBPP 24
+#define UNCOMP 8
+#include "zrle.c"
+#define REALBPP 24
+#define UNCOMP -8
+#include "zrle.c"
 #undef BPP
 
 /*
@@ -1325,23 +3597,27 @@
 static void
 ReadConnFailedReason(void)
 {
-  CARD32 reasonLen;
-  char *reason = NULL;
+	CARD32 reasonLen;
+	char *reason = NULL;
 
-  if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) {
-    reasonLen = Swap32IfLE(reasonLen);
-    if ((reason = malloc(reasonLen)) != NULL &&
-        ReadFromRFBServer(reason, reasonLen)) {
-      fprintf(stderr,"VNC connection failed: %.*s\n", (int)reasonLen, reason);
-      free(reason);
-      return;
-    }
-  }
+	if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) {
+		reasonLen = Swap32IfLE(reasonLen);
+		if ((reason = malloc(reasonLen)) != NULL &&
+		    ReadFromRFBServer(reason, reasonLen)) {
+			int len = (int) reasonLen < sizeof(msgbuf) - 10 ? (int) reasonLen : sizeof(msgbuf) - 10;
+			sprintf(msgbuf,"VNC connection failed: %.*s\n", len, reason);
+			wmsg(msgbuf, 1);
+			free(reason);
+			return;
+		}
+	}
 
-  fprintf(stderr, "VNC connection failed\n");
+	sprintf(msgbuf, "VNC connection failed\n");
+	wmsg(msgbuf, 1);
 
-  if (reason != NULL)
-    free(reason);
+	if (reason != NULL) {
+		free(reason);
+	}
 }
 
 /*
@@ -1358,9 +3634,9 @@
 	    "  %s significant bit in each byte is leftmost on the screen.\n",
 	    (format->bigEndian ? "Most" : "Least"));
   } else {
-    fprintf(stderr,"  %d bits per pixel.\n",format->bitsPerPixel);
+    fprintf(stderr,"  %d bits per pixel.  ",format->bitsPerPixel);
     if (format->bitsPerPixel != 8) {
-      fprintf(stderr,"  %s significant byte first in each pixel.\n",
+      fprintf(stderr,"%s significant byte first in each pixel.\n",
 	      (format->bigEndian ? "Most" : "Least"));
     }
     if (format->trueColour) {
@@ -1462,4 +3738,3 @@
 
   cinfo->src = &jpegSrcManager;
 }
-
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/rre.c
--- vnc_unixsrc.orig/vncviewer/rre.c	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/vncviewer/rre.c	2008-10-05 15:16:30.000000000 -0400
@@ -29,6 +29,18 @@
 #define HandleRREBPP CONCAT2E(HandleRRE,BPP)
 #define CARDBPP CONCAT2E(CARD,BPP)
 
+#define FillRectangle(x, y, w, h, color)  \
+	{ \
+		XGCValues _gcv; \
+		_gcv.foreground = color; \
+		if (!appData.useXserverBackingStore) { \
+			FillScreen(x, y, w, h, _gcv.foreground); \
+		} else { \
+			XChangeGC(dpy, gc, GCForeground, &_gcv); \
+			XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \
+		} \
+	}
+
 static Bool
 HandleRREBPP (int rx, int ry, int rw, int rh)
 {
@@ -49,11 +61,19 @@
 #if (BPP == 8)
   gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
 #else
+#if (BPP == 16)
+  gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix);
+#else
   gcv.foreground = pix;
 #endif
+#endif
 
+#if 0
   XChangeGC(dpy, gc, GCForeground, &gcv);
   XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
+#else
+  FillRectangle(rx, ry, rw, rh, gcv.foreground);
+#endif
 
   for (i = 0; i < hdr.nSubrects; i++) {
     if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
@@ -70,13 +90,23 @@
 #if (BPP == 8)
     gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
 #else
+#if (BPP == 16)
+    gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix);
+#else
     gcv.foreground = pix;
 #endif
+#endif
 
+#if 0
     XChangeGC(dpy, gc, GCForeground, &gcv);
     XFillRectangle(dpy, desktopWin, gc, rx + subrect.x, ry + subrect.y,
 		   subrect.w, subrect.h);
+#else
+    FillRectangle(rx + subrect.x, ry + subrect.y, subrect.w, subrect.h, gcv.foreground);
+#endif
   }
 
   return True;
 }
+
+#undef FillRectangle
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/selection.c vnc_unixsrc/vncviewer/selection.c
--- vnc_unixsrc.orig/vncviewer/selection.c	2004-03-03 04:11:52.000000000 -0500
+++ vnc_unixsrc/vncviewer/selection.c	2010-02-25 23:28:48.000000000 -0500
@@ -43,13 +43,16 @@
 				unsigned long* length, int* format);
 static void LoseSelection(Widget w, Atom *selection);
 
-static Bool iAmSelectionOwner = False;
+static Bool PrimarySelectionOwner = False;
+static Bool ClipboardSelectionOwner = False;
 static Time prevSelectionTime = 0L;
 static Time cutBufferTime = 0L;
 
 #define TIME_LATER(a, b) ((a) != 0 && ((b) == 0 || (INT32)((a) - (b)) > 0))
 
 
+static Atom clipboard_atom = None;
+
 /*
  * InitialiseSelection() must be called after realizing widgets (because
  * otherwise XtGetSelectionValue() fails).  We register events on the root
@@ -62,22 +65,28 @@
  * available.
  */
 
-void
-InitialiseSelection()
-{
+static int dbg_sel = -1;
+
+void InitialiseSelection() {
 #if XtSpecificationRelease >= 6
-  XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel);
+	XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel);
 #else
-  _XtRegisterWindow(DefaultRootWindow(dpy), toplevel);
+	_XtRegisterWindow(DefaultRootWindow(dpy), toplevel);
 #endif
-  XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask);
+	XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask);
 
-  XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange,
-		       NULL);
+	XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange, NULL);
 
-  XtGetSelectionValue(toplevel, XA_PRIMARY,
+	clipboard_atom = XInternAtom(dpy, "CLIPBOARD", False);
+
+	XtGetSelectionValue(toplevel, XA_PRIMARY,
 		      XInternAtom(dpy, "TIMESTAMP", False),
 		      GetInitialSelectionTimeCallback, NULL, CurrentTime);
+
+	if (dbg_sel < 0) {
+		dbg_sel = 0;
+		if (getenv("SSVNC_DEBUG_SELECTION")) dbg_sel = 1;
+	}
 }
 
 
@@ -93,13 +102,16 @@
 				Atom* selection, Atom* type, XtPointer value,
 				unsigned long* length, int* format)
 {
-  if (value && *format == 32 && *length == 1)
-    prevSelectionTime = *(CARD32 *)value;
-  else
-    prevSelectionTime = 0L;
-
-  if (value)
-    XtFree(value);
+	if (value && *format == 32 && *length == 1) {
+		prevSelectionTime = *(CARD32 *)value;
+	} else {
+		prevSelectionTime = 0L;
+	}
+
+	if (value) {
+		XtFree(value);
+	}
+	if (w || clientData || selection || type || value || length || format) {}
 }
 
 
@@ -121,26 +133,30 @@
 void
 SelectionToVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
 {
-  Bool always = False;
+	Bool always = appData.sendAlways;
+	Atom sendsel = XA_PRIMARY;
 
-  if (*num_params != 0) {
-    if (strcmp(params[0],"always") == 0) {
-      always = True;
-    } else if (strcmp(params[0],"new") == 0) {
-      always = False;
-    } else {
-      fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n");
-      return;
-    }
-  }
-
-  if (always) {
-    XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL,
-			TimeFromEvent(event));
-  } else {
-    XtGetSelectionValue(w, XA_PRIMARY, XInternAtom(dpy, "TIMESTAMP", False),
-			GetSelectionTimeCallback, NULL, TimeFromEvent(event));
-  }
+	if (*num_params != 0) {
+		if (strcmp(params[0],"always") == 0) {
+			always = True;
+		} else if (strcmp(params[0],"new") == 0) {
+			always = False;
+		} else {
+			fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n");
+			return;
+		}
+	}
+	if (appData.sendClipboard && clipboard_atom != None) {
+		sendsel = clipboard_atom;
+	}
+	if (dbg_sel) fprintf(stderr, "SelectionToVNC %s\n", sendsel == XA_PRIMARY ? "PRIMARY" : "CLIPBOARD");
+
+	if (always) {
+		XtGetSelectionValue(w, sendsel, XA_STRING, GetSelectionCallback, NULL, TimeFromEvent(event));
+	} else {
+		XtGetSelectionValue(w, sendsel, XInternAtom(dpy, "TIMESTAMP", False), GetSelectionTimeCallback, NULL, TimeFromEvent(event));
+	}
+	if (w || event || params || num_params) {}
 }
 
 
@@ -158,10 +174,13 @@
   int len = *length;
   char *str = (char *)value;
 
-  if (str)
-    SendClientCutText(str, len);
-  else
-    SendCutBuffer();
+	if (str) {
+		if (dbg_sel) fprintf(stderr, "SendClientCutText len: %d\n", len);
+		SendClientCutText(str, len);
+	} else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) {
+		SendCutBuffer();
+	}
+	if (w || clientData || selection || type || value || length || format) {}
 }
 
 
@@ -180,26 +199,24 @@
 			 Atom* type, XtPointer value, unsigned long* length,
 			 int* format)
 {
-  if (value && *format == 32 && *length == 1) {
+	if (value && *format == 32 && *length == 1) {
+		Time t = *(CARD32 *)value;
 
-    Time t = *(CARD32 *)value;
-
-    if (TIME_LATER(t, prevSelectionTime)) {
-      prevSelectionTime = t;
-      XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL,
-			  CurrentTime);
-    }
-
-  } else {
-
-    if (TIME_LATER(cutBufferTime, prevSelectionTime)) {
-      prevSelectionTime = cutBufferTime;
-      SendCutBuffer();
-    }
-  }
-
-  if (value)
-    XtFree(value);
+		if (TIME_LATER(t, prevSelectionTime)) {
+			prevSelectionTime = t;
+			XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, CurrentTime);
+		}
+	} else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) {
+		if (TIME_LATER(cutBufferTime, prevSelectionTime)) {
+			prevSelectionTime = cutBufferTime;
+			SendCutBuffer();
+		}
+	}
+
+	if (value) {
+		XtFree(value);
+	}
+	if (w || clientData || selection || type || value || length || format) {}
 }
 
 
@@ -209,16 +226,17 @@
  */
 
 static void
-SendCutBuffer()
-{
-  char *str;
-  int len;
+SendCutBuffer() {
+	char *str;
+	int len;
 
-  str = XFetchBytes(dpy, &len);
-  if (!str) return;
+	if (dbg_sel) fprintf(stderr, "SendCutBuffer len: %d\n", len);
 
-  SendClientCutText(str, len);
-  XFree(str);
+	str = XFetchBytes(dpy, &len);
+	if (!str) return;
+
+	SendClientCutText(str, len);
+	XFree(str);
 }
 
 
@@ -230,10 +248,12 @@
 static void
 CutBufferChange(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont)
 {
-  if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0)
-    return;
+	if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0) {
+		return;
+	}
 
-  cutBufferTime = ev->xproperty.time;
+	cutBufferTime = ev->xproperty.time;
+	if (w || ptr || cont) {}
 }
 
 
@@ -249,36 +269,69 @@
 void
 SelectionFromVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
 {
-  Bool always = False;
-  Time t = TimeFromEvent(event);
-
-  if (*num_params != 0) {
-    if (strcmp(params[0],"always") == 0) {
-      always = True;
-    } else if (strcmp(params[0],"new") == 0) {
-      always = False;
-    } else {
-      fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n");
-      return;
-    }
-  }
-
-  if (t == CurrentTime) {
-    fprintf(stderr,"Error in translations: SelectionFromVNC() must act on "
-	    "event with time field\n");
-    return;
-  }
-
-  if (!serverCutText || (!always && !newServerCutText))
-    return;
-
-  newServerCutText = False;
-
-  XStoreBytes(dpy, serverCutText, strlen(serverCutText));
-  if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection,
-		     NULL)) {
-    iAmSelectionOwner = True;
-  }
+	Bool always = False;
+	Time t = TimeFromEvent(event);
+	int hold_primary   = 0;
+	int hold_clipboard = 0;
+
+	if (dbg_sel) fprintf(stderr, "SelectionFromVNC\n");
+
+	if (*num_params != 0) {
+		if (strcmp(params[0],"always") == 0) {
+			always = True;
+		} else if (strcmp(params[0],"new") == 0) {
+			always = False;
+		} else {
+			fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n");
+			return;
+		}
+	}
+
+	if (t == CurrentTime) {
+		fprintf(stderr,"Error in translations: SelectionFromVNC() must act on "
+		    "event with time field\n");
+		return;
+	}
+
+	if (!serverCutText || (!always && !newServerCutText)) {
+		return;
+	}
+
+	newServerCutText = False;
+
+	if (appData.appShare) {
+		if (strstr(serverCutText, "X11VNC_APPSHARE_CMD:") == serverCutText) {
+			/* do something with it? */
+			return;
+		}
+	}
+
+	XStoreBytes(dpy, serverCutText, strlen(serverCutText));
+
+	if (appData.recvText == NULL) {
+		appData.recvText = strdup("both");
+	}
+	if (!strcasecmp(appData.recvText, "primary")) {
+		hold_primary = 1;
+	} else if (!strcasecmp(appData.recvText, "clipboard")) {
+		hold_clipboard = 1;
+	} else {
+		hold_primary = hold_clipboard = 1;
+	}
+
+	if (!hold_primary) {
+		;
+	} else if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection, NULL)) {
+		PrimarySelectionOwner = True;
+		if (dbg_sel) fprintf(stderr, "Own PRIMARY\n");
+	}
+	if (!hold_clipboard || clipboard_atom == None) {
+		;
+	} else if (XtOwnSelection(desktop, clipboard_atom, t, ConvertSelection, LoseSelection, NULL)) {
+		ClipboardSelectionOwner = True;
+		if (dbg_sel) fprintf(stderr, "Own CLIPBOARD\n");
+	}
+	if (w || event || params || num_params) {}
 }
 
 
@@ -293,37 +346,36 @@
 		 XtPointer* value, unsigned long* length, int* format)
 {
 
-  if (*target == XA_STRING && serverCutText != NULL) {
-    *type = XA_STRING;
-    *length = strlen(serverCutText);
-    *value = (XtPointer)XtMalloc(*length);
-    memcpy((char*)*value, serverCutText, *length);
-    *format = 8;
-    return True;
-  }
+	if (*target == XA_STRING && serverCutText != NULL) {
+		*type = XA_STRING;
+		*length = strlen(serverCutText);
+		*value = (XtPointer)XtMalloc(*length);
+		memcpy((char*)*value, serverCutText, *length);
+		*format = 8;
+		return True;
+	}
 
-  if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
+	if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
 				  (XPointer*)value, length, format)) {
-    if (*target == XInternAtom(dpy, "TARGETS", False)) {
-      /* add STRING to list of standard targets */
-      Atom* targetP;
-      Atom* std_targets = (Atom*)*value;
-      unsigned long std_length = *length;
-
-      *length = std_length + 1;
-      *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length));
-      targetP = *(Atom**)value;
-      *targetP++ = XA_STRING;
-      memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
-      XtFree((char*)std_targets);
-      *type = XA_ATOM;
-      *format = 32;
-      return True;
-    }
-
-    return True;
-  }
-  return False;
+		if (*target == XInternAtom(dpy, "TARGETS", False)) {
+			/* add STRING to list of standard targets */
+			Atom* targetP;
+			Atom* std_targets = (Atom*)*value;
+			unsigned long std_length = *length;
+
+			*length = std_length + 1;
+			*value = (XtPointer)XtMalloc(sizeof(Atom)*(*length));
+			targetP = *(Atom**)value;
+			*targetP++ = XA_STRING;
+			memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
+			XtFree((char*)std_targets);
+			*type = XA_ATOM;
+			*format = 32;
+			return True;
+		}
+		return True;
+	}
+	return False;
 }
 
 
@@ -332,7 +384,13 @@
  */
 
 static void
-LoseSelection(Widget w, Atom *selection)
-{
-  iAmSelectionOwner = False;
+LoseSelection(Widget w, Atom *selection) {
+	if (*selection == XA_PRIMARY) {
+		if (dbg_sel) fprintf(stderr, "lost PRIMARY\n");
+  		PrimarySelectionOwner = False;
+	} else if (clipboard_atom != None && *selection == clipboard_atom) {
+		if (dbg_sel) fprintf(stderr, "lost CLIPBOARD\n");
+  		ClipboardSelectionOwner = False;
+	}
+	if (w) {}
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/shm.c
--- vnc_unixsrc.orig/vncviewer/shm.c	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/vncviewer/shm.c	2010-02-25 23:40:58.000000000 -0500
@@ -30,71 +30,113 @@
 static Bool caughtShmError = False;
 static Bool needShmCleanup = False;
 
-void
-ShmCleanup()
-{
-  fprintf(stderr,"ShmCleanup called\n");
-  if (needShmCleanup) {
-    shmdt(shminfo.shmaddr);
-    shmctl(shminfo.shmid, IPC_RMID, 0);
-    needShmCleanup = False;
-  }
+static int ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) {
+	caughtShmError = True;
+	if (dpy || error) {}
+	return 0;
 }
 
-static int
-ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error)
-{
-  caughtShmError = True;
-  return 0;
+void ShmDetach() {
+	if (needShmCleanup) {
+		XErrorHandler oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
+		fprintf(stderr,"ShmDetach called.\n");
+		XShmDetach(dpy, &shminfo);
+		XSync(dpy, False);
+		XSetErrorHandler(oldXErrorHandler);
+	}
 }
 
-XImage *
-CreateShmImage()
-{
-  XImage *image;
-  XErrorHandler oldXErrorHandler;
-
-  if (!XShmQueryExtension(dpy))
-    return NULL;
-
-  image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo,
-			  si.framebufferWidth, si.framebufferHeight);
-  if (!image) return NULL;
-
-  shminfo.shmid = shmget(IPC_PRIVATE,
-			 image->bytes_per_line * image->height,
-			 IPC_CREAT|0777);
+void ShmCleanup() {
+	if (needShmCleanup) {
+		fprintf(stderr,"ShmCleanup called.\n");
+		XSync(dpy, False);
+		shmdt(shminfo.shmaddr);
+		shmctl(shminfo.shmid, IPC_RMID, 0);
 
-  if (shminfo.shmid == -1) {
-    XDestroyImage(image);
-    return NULL;
-  }
-
-  shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
-
-  if (shminfo.shmaddr == (char *)-1) {
-    XDestroyImage(image);
-    shmctl(shminfo.shmid, IPC_RMID, 0);
-    return NULL;
-  }
+		needShmCleanup = False;
+	}
+}
 
-  shminfo.readOnly = True;
+Bool UsingShm() {
+	return needShmCleanup;
+}
 
-  oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
-  XShmAttach(dpy, &shminfo);
-  XSync(dpy, False);
-  XSetErrorHandler(oldXErrorHandler);
+int scale_round(int len, double fac);
+extern int scale_x, scale_y;
+extern double scale_factor_x, scale_factor_y;
 
-  if (caughtShmError) {
-    XDestroyImage(image);
-    shmdt(shminfo.shmaddr);
-    shmctl(shminfo.shmid, IPC_RMID, 0);
-    return NULL;
-  }
+XImage *
+CreateShmImage(int do_ycrop)
+{
+	XImage *image;
+	XErrorHandler oldXErrorHandler;
+	int ymax = si.framebufferHeight;
+	int xmax = si.framebufferWidth;
+
+	if (!XShmQueryExtension(dpy)) {
+		return NULL;
+	}
+	if (!appData.useShm) {
+		return NULL;
+	}
+	if (do_ycrop == -1) {
+		/* kludge to test for shm prescence */
+		return (XImage *) 0x1;
+	}
+
+	if (do_ycrop) {
+		ymax = appData.yCrop;
+	}
+
+	if (scale_x > 0) {
+		xmax = scale_round(xmax, scale_factor_x);
+		ymax = scale_round(ymax, scale_factor_y);
+	}
+
+	image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, xmax, ymax);
+	if (!image) {
+		return NULL;
+	}
+
+	shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT|0777);
+
+	if (shminfo.shmid == -1) {
+		XDestroyImage(image);
+		if (0) fprintf(stderr, "CreateShmImage: destroyed 'image' (1)\n");
+		return NULL;
+	}
+
+	shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
+
+	if (shminfo.shmaddr == (char *)-1) {
+		XDestroyImage(image);
+#if 0
+		fprintf(stderr, "CreateShmImage: destroyed 'image' (2)\n");
+#endif
+		shmctl(shminfo.shmid, IPC_RMID, 0);
+		return NULL;
+	}
+
+	shminfo.readOnly = True;
+
+	oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
+	XShmAttach(dpy, &shminfo);
+	XSync(dpy, False);
+	XSetErrorHandler(oldXErrorHandler);
+
+	if (caughtShmError) {
+		XDestroyImage(image);
+#if 0
+		fprintf(stderr, "CreateShmImage: destroyed 'image' (3)\n");
+#endif
+		shmdt(shminfo.shmaddr);
+		shmctl(shminfo.shmid, IPC_RMID, 0);
+		return NULL;
+	}
 
-  needShmCleanup = True;
+	needShmCleanup = True;
 
-  fprintf(stderr,"Using shared memory PutImage\n");
+	fprintf(stderr,"Using shared memory (PutImage ycrop=%d, Size %dx%d)\n", do_ycrop, xmax, ymax);
 
-  return image;
+	return image;
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/smake vnc_unixsrc/vncviewer/smake
--- vnc_unixsrc.orig/vncviewer/smake	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/smake	2007-02-19 12:28:05.000000000 -0500
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+PATH=`pwd`/../..:/usr/sfw/bin:/usr/ccs/bin:$PATH
+export PATH
+if [ "X$1" != "X" ]; then
+	"$@"
+else
+	make
+	strip vncviewer
+	ls -l vncviewer
+fi
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncviewer/sockets.c
--- vnc_unixsrc.orig/vncviewer/sockets.c	2001-01-14 22:54:18.000000000 -0500
+++ vnc_unixsrc/vncviewer/sockets.c	2010-04-18 11:41:07.000000000 -0400
@@ -22,17 +22,31 @@
  */
 
 #include <unistd.h>
+#include <time.h>
 #include <sys/socket.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <sys/un.h>
 #include <netdb.h>
 #include <fcntl.h>
 #include <assert.h>
 #include <vncviewer.h>
 
+#ifndef SOL_IPV6
+#ifdef  IPPROTO_IPV6
+#define SOL_IPV6 IPPROTO_IPV6
+#endif
+#endif
+
+/* Solaris (sysv?) needs INADDR_NONE */
+#ifndef INADDR_NONE
+#define INADDR_NONE ((in_addr_t) 0xffffffff)
+#endif
+
 void PrintInHex(char *buf, int len);
+extern void printChat(char *, Bool);
 
 Bool errorMessageOnReadFailure = True;
 
@@ -56,31 +70,396 @@
  */
 
 static Bool rfbsockReady = False;
+static Bool xfrsockReady = False;
+static XtInputId rfbsockId = 0;
+static XtInputId xfrsockId = 0;
+static int do_rfbsockId = 0;
+static int do_xfrsockId = 0;
+
 static void
 rfbsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id)
 {
-  rfbsockReady = True;
-  XtRemoveInput(*id);
+	rfbsockReady = True;
+#if 0
+	XtRemoveInput(*id);
+#endif
+	XtRemoveInput(rfbsockId);
+	if (do_xfrsockId) {
+		XtRemoveInput(xfrsockId);
+	}
+	if (clientData || fd || id) {}
 }
 
 static void
-ProcessXtEvents()
+xfrsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id)
 {
-  rfbsockReady = False;
-  XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask,
-		rfbsockReadyCallback, NULL);
-  while (!rfbsockReady) {
-    XtAppProcessEvent(appContext, XtIMAll);
-  }
+	xfrsockReady = True;
+	XtRemoveInput(xfrsockId);
+	if (do_rfbsockId) {
+		XtRemoveInput(rfbsockId);
+	}
+	if (clientData || fd || id) {}
+}
+
+
+extern int skip_XtUpdate;
+extern int skip_XtUpdateAll;
+extern int filexfer_sock, filexfer_listen;
+extern time_t start_listen;
+extern void CheckTextInput(void);
+extern time_t last_filexfer;
+
+static char fxfer[65536];
+int fxfer_size = 65536;
+
+int rfbsock_is_ready(void) {
+	fd_set fds;
+	struct timeval tv;
+
+	if (rfbsock < 0)  {
+		return 0;
+	}
+	FD_ZERO(&fds);
+	FD_SET(rfbsock,&fds);
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	if (select(rfbsock+1, &fds, NULL, NULL, &tv) > 0) {
+		if (FD_ISSET(rfbsock, &fds)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+time_t filexfer_start = 0;
+
+void CheckFileXfer() {
+	fd_set fds;
+	struct timeval tv;
+	int i, icnt = 0, igot = 0, bytes0 = 0, bytes = 0, grace = 0, n, list = 0;
+	int db = 0;
+
+	if (!appData.fileActive || (filexfer_sock < 0 && filexfer_listen < 0)) {
+		return;
+	}
+
+	if (filexfer_listen >= 0 && time(NULL) > start_listen + 30) {
+		fprintf(stderr, "filexfer closing aging listen socket.\n");
+		close(filexfer_listen);
+		filexfer_listen = -1;
+		return;
+	}
+if (0) fprintf(stderr, "In  CheckFileXfer\n");
+
+	if (filexfer_listen >=0) {
+		n = filexfer_listen;
+		list = 1;
+	} else {
+		n = filexfer_sock;
+	}
+
+	while (1) {
+		icnt++;
+		FD_ZERO(&fds);
+		FD_SET(n,&fds);
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+		if (select(n+1, &fds, NULL, NULL, &tv) > 0) {
+		    if (FD_ISSET(n, &fds)) {
+			if (list) {
+				if (filexfer_sock >= 0) {
+					fprintf(stderr, "filexfer close stale(?) filexfer_sock.\n");
+					close(filexfer_sock);
+					filexfer_sock = -1;
+				}
+				filexfer_sock = AcceptTcpConnection(filexfer_listen);
+				if (filexfer_sock >= 0) {
+					fprintf(stderr, "filexfer accept OK.\n");
+					close(filexfer_listen);
+					filexfer_listen = -1;
+					filexfer_start = last_filexfer = time(NULL);
+				} else {
+					fprintf(stderr, "filexfer accept failed.\n");
+				}
+				break;
+			} else {
+				ssize_t rn;
+				unsigned char hdr[12];
+				unsigned int len;
+				if (db) fprintf(stderr, "try read filexfer...\n");
+				if (hdr || len || i) {}
+#if 1
+				rn = read(n, fxfer, 1*8192);
+if (db) {
+	int i;
+	fprintf(stderr, "CFX HDR:");
+	for (i=0; i < 12; i++) {
+		fprintf(stderr, " %d", (int) fxfer[i]);
+	}
+	fprintf(stderr, " ?\n");
+}
+				if (0 || db) fprintf(stderr, "filexfer read[%d] %d.\n", icnt, rn);
+				if (rn < 0) {
+					fprintf(stderr, "filexfer bad read: %d\n", errno);
+					break;
+				} else if (rn == 0) {
+					fprintf(stderr, "filexfer gone.\n");
+					close(n);
+					filexfer_sock = -1;
+					last_filexfer = time(NULL);
+#if 0
+					fprintf(stderr, "last_filexfer-2a: %d\n", last_filexfer);
+#endif
+					appData.fileActive = False;
+					SendFramebufferUpdateRequest(0, 0, 1, 1, False);
+					return;
+				} else if (rn > 0) {
+					if (db > 1) write(2, fxfer, rn);
+					if (db) fprintf(stderr, "\n");
+					bytes += rn;
+					last_filexfer = time(NULL);
+#if 0
+					fprintf(stderr, "last_filexfer-2b: %d\n", last_filexfer);
+#endif
+
+					if (0) {
+						/* WE TRY TO FIX THIS IN THE JAVA NOW */
+						if (appData.ultraDSM) {
+							unsigned char msg = rfbFileTransfer;
+							unsigned char hdc = (unsigned char) fxfer[0];
+							if (msg == hdc) {
+								/* cross your fingers... */
+								WriteExact(rfbsock, (char *)&msg, 1);
+							}
+						}
+					}
+					if (!WriteExact(rfbsock, fxfer, rn)) {
+						return;
+					}
+					igot = 1;
+				}
+#else
+				/* not working, not always 7 msg type.	*/
+				rn = read(n, hdr, 12);
+				if (db) fprintf(stderr, "filexfer read %d.\n", rn);
+				if (rn == 0) {
+					fprintf(stderr, "filexfer gone.\n");
+					close(n);
+					filexfer_sock = -1;
+					last_filexfer = time(NULL);
+					return;
+				}
+				if (rn == 12) {
+					len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11];
+					if (db) fprintf(stderr, "n=%d len=%d\n", rn, len);
+					if (db > 1) write(2, hdr, rn);
+					if (db) fprintf(stderr, "\n");
+					WriteExact(rfbsock, hdr, rn);
+					if (len > 0) {
+						rn = read(len, fxfer, len);
+						if (!WriteExact(rfbsock, fxfer, len)) {
+							last_filexfer = time(NULL);
+							return;
+						}
+						if (db > 1) write(2, fxfer, len);
+					}
+					if (db) fprintf(stderr, "\n");
+				} else {
+					if (db) fprintf(stderr, "bad rn: %d\n", rn);
+				}
+				igot = 1;
+#endif
+			}
+		    }
+		} else {
+			if (bytes >= 8192) {
+				int ok = 0;
+				if (bytes0 == 0) {
+					ok = 1;
+				} else if (bytes >= bytes0 + 12) {
+					ok = 1;
+				} else if (grace < 20) {
+					ok = 1;
+				}
+				if (ok) {
+					grace++;
+					bytes0 = bytes;
+#if 0
+					fprintf(stderr, "grace: %d\n", grace);
+					/* forgot that this is about... */
+#endif
+					usleep(10 * 1000);
+					continue;
+				}
+			}
+			break;
+		}
+	}
+	if (igot) {
+		last_filexfer = time(NULL);
+#if 0
+		fprintf(stderr, "last_filexfer-2c: %d\n", last_filexfer);
+#endif
+	}
+#if 0
+fprintf(stderr, "Out CheckFileXfer\n");
+#endif
+	return;
+}
+
+static void check_term_chat(void) {
+	fd_set fds;
+	struct timeval tv;
+	int i, igot = -1, n = fileno(stdin);
+	char strs[100][512];
+	char buf[rfbTextMaxSize];
+
+	for (i=0; i < 100; i++) {
+		FD_ZERO(&fds);
+		FD_SET(n,&fds);
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+		if (select(n+1, &fds, NULL, NULL, &tv) > 0) {
+			if (FD_ISSET(n, &fds)) {
+				fgets(strs[i], 512, stdin);
+				igot = i;
+			} else {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+	buf[0] = '\0';
+	for (i=0; i <= igot; i++) {
+		if (strlen(buf) + strlen(strs[i]) < rfbTextMaxSize) {
+			strcat(buf, strs[i]);
+		} else {
+			SendTextChat(buf);
+			buf[0] = '0';
+		}
+	}
+	if (buf[0] != '\0') {
+		SendTextChat(buf);
+	}
+	if (igot >= 0) printChat("Send: ", False);
+}
+
+static time_t time_mark;
+extern int delay_filexfer;
+#include <sys/stat.h>
+
+extern double start_time;
+
+void ProcessXtEvents()
+{
+	int db = 0;
+	static int dyn = -1;
+	static int chat_was_active = 0;
+	int check_chat = 0;
+
+	if (dyn < 0) {
+		struct stat sb;
+		if (getenv("USER") && !strcmp(getenv("USER"), "runge")) {
+			if (stat("/tmp/nodyn", &sb) == 0) {
+				putenv("NOFTFBUPDATES=1");
+				unlink("/tmp/nodyn");
+			}
+		}
+		if (getenv("NOFTFBUPDATES")) {
+			dyn = 0;
+		} else {
+			dyn = 1;
+		}
+	}
+
+#if 0
+	if (0) fprintf(stderr, "ProcessXtEvents: %d  %.4f\n", skip_XtUpdateAll, dnow() - start_time);
+#endif
+
+	if (skip_XtUpdateAll) {
+		return;
+	}
+
+	/* text chat */
+	if (appData.chatActive ) {
+		check_chat = 1;
+	} else if (chat_was_active) {
+		static double last_check = 0.0;
+		double now = dnow();
+		if (now > last_check + 0.75) {
+			check_chat = 1;
+			last_check = now;
+		}
+	}
+	if (check_chat) {
+		if (appData.chatActive) {
+			chat_was_active = 1;
+		}
+		if (!appData.termChat) {
+			CheckTextInput();
+		} else {
+			check_term_chat();
+		}
+	}
+
+	if (skip_XtUpdate) {
+		return;
+	}
+
+	rfbsockReady = False;
+	xfrsockReady = False;
+	do_rfbsockId = 1;
+	rfbsockId = XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask,
+	    rfbsockReadyCallback, NULL);
+
+	do_xfrsockId = 0;
+	if (filexfer_sock >= 0) {
+		do_xfrsockId = 1;
+		xfrsockId = XtAppAddInput(appContext, filexfer_sock, (XtPointer)XtInputReadMask,
+		    xfrsockReadyCallback, NULL);
+	}
+
+	time_mark = time(NULL);
+
+	if (appData.fileActive) {
+		static int first = 1;
+		if (first) {
+			fprintf(stderr, "PXT: dynamic fb updates during filexfer: %d\n", dyn);
+			first = 0;
+		}
+	}
+
+	if (db) fprintf(stderr, "XtAppAddInput: ");
+	while (!rfbsockReady && !xfrsockReady) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		if (db) fprintf(stderr, ".");
+		if (dyn && filexfer_sock >= 0 && time(NULL) > time_mark + delay_filexfer) {
+			SendFramebufferUpdateRequest(0, 0, w, h, False);
+		}
+		XtAppProcessEvent(appContext, XtIMAll);
+	}
+	if (db) fprintf(stderr, " done. r: %d  x: %d\n", rfbsockReady, xfrsockReady);
+
+	if (xfrsockReady) {
+		CheckFileXfer();
+	}
 }
 
 Bool
 ReadFromRFBServer(char *out, unsigned int n)
 {
+#if 0
+	double start = dnow(), dn = n;
+#endif
   if (n <= buffered) {
     memcpy(out, bufoutptr, n);
     bufoutptr += n;
     buffered -= n;
+#if 0
+fprintf(stderr, "R0: %06d\n", (int) dn);
+#endif
     return True;
   }
 
@@ -119,6 +498,9 @@
     memcpy(out, bufoutptr, n);
     bufoutptr += n;
     buffered -= n;
+#if 0
+fprintf(stderr, "R1: %06d %06d %10.2f KB/sec\n", (int) dn, buffered+n, 1e-3 * (buffered+n)/(dnow() - start));
+#endif
     return True;
 
   } else {
@@ -146,11 +528,16 @@
       n -= i;
     }
 
+#if 0
+fprintf(stderr, "R2: %06d %06d %10.2f KB/sec\n", (int) dn, (int) dn, 1e-3 * (dn)/(dnow() - start));
+#endif
     return True;
   }
 }
 
 
+int currentMsg = -1;
+
 /*
  * Write an exact number of bytes, and don't return until you've sent them.
  */
@@ -158,81 +545,321 @@
 Bool
 WriteExact(int sock, char *buf, int n)
 {
-  fd_set fds;
-  int i = 0;
-  int j;
-
-  while (i < n) {
-    j = write(sock, buf + i, (n - i));
-    if (j <= 0) {
-      if (j < 0) {
-	if (errno == EWOULDBLOCK || errno == EAGAIN) {
-	  FD_ZERO(&fds);
-	  FD_SET(rfbsock,&fds);
+	fd_set fds;
+	int i = 0;
+	int j;
+
+	if (appData.ultraDSM && currentMsg >= 0) {
+		/* this is for goofy UltraVNC DSM send RFB msg char twice: */
+		unsigned char msg = (unsigned char) currentMsg;
+		currentMsg = -1;
+		if (!WriteExact(sock, (char *)&msg, sizeof(msg))) {
+			return False;
+		}
+	}
+	currentMsg = -1;
 
-	  if (select(rfbsock+1, NULL, &fds, NULL, NULL) <= 0) {
-	    fprintf(stderr,programName);
-	    perror(": select");
-	    return False;
-	  }
-	  j = 0;
-	} else {
-	  fprintf(stderr,programName);
-	  perror(": write");
-	  return False;
+	while (i < n) {
+		j = write(sock, buf + i, (n - i));
+		if (j <= 0) {
+		    if (j < 0) {
+			if (errno == EWOULDBLOCK || errno == EAGAIN) {
+				FD_ZERO(&fds);
+				FD_SET(rfbsock,&fds);
+
+				if (select(rfbsock+1, NULL, &fds, NULL, NULL) <= 0) {
+					fprintf(stderr,programName);
+					perror(": select");
+					return False;
+				}
+				j = 0;
+			} else {
+				fprintf(stderr,programName);
+				perror(": write");
+				return False;
+			}
+		    } else {
+			fprintf(stderr,"%s: write failed\n",programName);
+			return False;
+		    }
+		}
+		i += j;
 	}
-      } else {
-	fprintf(stderr,"%s: write failed\n",programName);
-	return False;
-      }
-    }
-    i += j;
-  }
-  return True;
+	return True;
 }
 
+int
+ConnectToUnixSocket(char *file) {
+	int sock;
+	struct sockaddr_un addr;
+	int i;
+
+	memset(&addr, 0, sizeof(struct sockaddr_un));
+
+	addr.sun_family = AF_UNIX;
+
+	for (i=0; i < 108; i++) {
+		addr.sun_path[i] = file[i];
+		if (file[i] == '\0') {
+			break;
+		}
+	}
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		fprintf(stderr,programName);
+		perror(": ConnectToUnixSocket: socket");
+		return -1;
+	}
+
+	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		fprintf(stderr, programName);
+		perror(": ConnectToUnixSocket: connect");
+		close(sock);
+		return -1;
+	}
+
+	return sock;
+}
+
+char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen) {
+#if defined(AF_INET6) && defined(NI_NUMERICHOST)
+        char name[200];
+	if (appData.noipv6) {
+                return strdup("unknown");
+        }
+        if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST) == 0) {
+                return strdup(name);
+        }
+#endif
+	if (paddr || addrlen) {}
+        return strdup("unknown");
+}
+
+char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen) {
+#if defined(AF_INET6)
+        char name[200];
+	if (appData.noipv6) {
+                return strdup("unknown");
+        }
+        if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, 0) == 0) {
+                return strdup(name);
+        }
+#endif
+	if (paddr || addrlen) {}
+        return strdup("unknown");
+}
+
+int dotted_ip(char *host, int partial) {
+	int len, dots = 0;
+	char *p = host;
+
+	if (!host) {
+		return 0;
+	}
+
+	if (!isdigit((unsigned char) host[0])) {
+		return 0;
+	}
+
+	len = strlen(host);
+	if (!partial && !isdigit((unsigned char) host[len-1])) {
+		return 0;
+	}
+
+	while (*p != '\0') {
+		if (*p == '.') dots++;
+		if (*p == '.' || isdigit((unsigned char) (*p))) {
+			p++;
+			continue;
+		}
+		return 0;
+	}
+	if (!partial && dots != 3) {
+		return 0;
+	}
+	return 1;
+}
 
 /*
  * ConnectToTcpAddr connects to the given TCP port.
  */
 
-int
-ConnectToTcpAddr(unsigned int host, int port)
-{
-  int sock;
-  struct sockaddr_in addr;
-  int one = 1;
-
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons(port);
-  addr.sin_addr.s_addr = host;
+int ConnectToTcpAddr(const char *hostname, int port) {
+	int sock = -1, one = 1;
+	unsigned int host;
+	struct sockaddr_in addr;
+
+	if (appData.noipv4) {
+		fprintf(stderr, "ipv4 is disabled via VNCVIEWER_NO_IPV4/-noipv4.\n");
+		goto try6;
+	}
 
-  sock = socket(AF_INET, SOCK_STREAM, 0);
-  if (sock < 0) {
-    fprintf(stderr,programName);
-    perror(": ConnectToTcpAddr: socket");
-    return -1;
-  }
+	if (!StringToIPAddr(hostname, &host)) {
+		fprintf(stderr, "Could not convert '%s' to ipv4 host address.\n", hostname);
+		goto try6;
+	}
 
-  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    fprintf(stderr,programName);
-    perror(": ConnectToTcpAddr: connect");
-    close(sock);
-    return -1;
-  }
+	memset(&addr, 0, sizeof(struct sockaddr_in));
 
-  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
-		 (char *)&one, sizeof(one)) < 0) {
-    fprintf(stderr,programName);
-    perror(": ConnectToTcpAddr: setsockopt");
-    close(sock);
-    return -1;
-  }
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = host;
+
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0) {
+		perror("ConnectToTcpAddr[ipv4]: socket");
+		sock = -1;
+		goto try6;
+	}
+
+	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		perror("ConnectToTcpAddr[ipv4]: connect");
+		close(sock);
+		sock = -1;
+		goto try6;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+		perror("ConnectToTcpAddr[ipv4]: setsockopt");
+		close(sock);
+		sock = -1;
+		goto try6;
+	}
 
-  return sock;
+	if (sock >= 0) {
+		return sock;
+	}
+
+	try6:
+
+#ifdef AF_INET6
+	if (!appData.noipv6) {
+		int err;
+		struct addrinfo *ai;
+		struct addrinfo hints;
+		char service[32], *host2, *q;
+
+		fprintf(stderr, "Trying ipv6 connection to '%s'\n", hostname);
+
+		memset(&hints, 0, sizeof(hints));
+		sprintf(service, "%d", port);
+
+		hints.ai_family = AF_UNSPEC;
+		hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+		hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+#ifdef AI_NUMERICSERV
+		hints.ai_flags |= AI_NUMERICSERV;
+#endif
+		if (!strcmp(hostname, "localhost")) {
+			host2 = strdup("::1");
+		} else if (!strcmp(hostname, "127.0.0.1")) {
+			host2 = strdup("::1");
+		} else if (hostname[0] == '[') {
+			host2 = strdup(hostname+1);
+		} else {
+			host2 = strdup(hostname);
+		}
+		q = strrchr(host2, ']');
+		if (q) {
+			*q = '\0';
+		}
+
+		err = getaddrinfo(host2, service, &hints, &ai);
+		if (err != 0) {
+			fprintf(stderr, "ConnectToTcpAddr[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
+			usleep(100 * 1000);
+			err = getaddrinfo(host2, service, &hints, &ai);
+		}
+		free(host2);
+
+		if (err != 0) {
+			fprintf(stderr, "ConnectToTcpAddr[ipv6]: getaddrinfo[%d]: %s (2nd try)\n", err, gai_strerror(err));
+		} else {
+			struct addrinfo *ap = ai;
+			while (ap != NULL) {
+				int fd = -1;
+				char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
+				if (s) {
+					fprintf(stderr, "ConnectToTcpAddr[ipv6]: trying ip-addr: '%s'\n", s);
+					free(s);
+				}
+				if (appData.noipv4) {
+					struct sockaddr_in6 *s6ptr;
+					if (ap->ai_family != AF_INET6) {
+						fprintf(stderr, "ConnectToTcpAddr[ipv6]: skipping AF_INET address under VNCVIEWER_NO_IPV4/-noipv4\n");
+						ap = ap->ai_next;
+						continue;
+					}
+#ifdef IN6_IS_ADDR_V4MAPPED
+					s6ptr = (struct sockaddr_in6 *) ap->ai_addr;
+					if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) {
+						fprintf(stderr, "ConnectToTcpAddr[ipv6]: skipping V4MAPPED address under VNCVIEWER_NO_IPV4/-noipv4\n");
+						ap = ap->ai_next;
+						continue;
+					}
+#endif
+				}
+
+				fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
+				if (fd == -1) {
+					perror("ConnectToTcpAddr[ipv6]: socket");
+				} else {
+					int dmsg = 0;
+					int res = connect(fd, ap->ai_addr, ap->ai_addrlen);
+#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+					if (res != 0) {
+						int zero = 0;
+						perror("ConnectToTcpAddr[ipv6]: connect");
+						dmsg = 1;
+						if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) {
+							fprintf(stderr, "ConnectToTcpAddr[ipv6]: trying again with IPV6_V6ONLY=0\n");
+							res = connect(fd, ap->ai_addr, ap->ai_addrlen);
+							dmsg = 0;
+						}
+					}
+#endif
+					if (res == 0) {
+						fprintf(stderr, "ConnectToTcpAddr[ipv6]: connect OK\n");
+						sock = fd;
+						break;
+					} else {
+						if (!dmsg) perror("ConnectToTcpAddr[ipv6]: connect");
+						close(fd);
+					}
+				}
+				ap = ap->ai_next;
+			}
+			freeaddrinfo(ai);
+		}
+		if (sock >= 0 && setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+			perror("ConnectToTcpAddr: setsockopt");
+			close(sock);
+			sock = -1;
+		}
+	}
+#endif
+	return sock;
 }
 
+Bool SocketPair(int fd[2]) {
+	if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) == -1) {
+		perror("socketpair");
+		return False;
+	}
+	return True;
+}
 
+Bool SetNoDelay(int sock) {
+	const int one = 1;
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+		perror("setsockopt");
+		return False;
+	}
+	return True;
+}
 
 /*
  * FindFreeTcpPort tries to find unused TCP port in the range
@@ -242,29 +869,31 @@
 int
 FindFreeTcpPort(void)
 {
-  int sock, port;
-  struct sockaddr_in addr;
+	int sock, port;
+	struct sockaddr_in addr;
 
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
+	memset(&addr, 0, sizeof(struct sockaddr_in));
 
-  sock = socket(AF_INET, SOCK_STREAM, 0);
-  if (sock < 0) {
-    fprintf(stderr,programName);
-    perror(": FindFreeTcpPort: socket");
-    return 0;
-  }
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
 
-  for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
-    addr.sin_port = htons((unsigned short)port);
-    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
-      close(sock);
-      return port;
-    }
-  }
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0) {
+		fprintf(stderr,programName);
+		perror(": FindFreeTcpPort: socket");
+		return 0;
+	}
+
+	for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
+		addr.sin_port = htons((unsigned short)port);
+		if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+			close(sock);
+			return port;
+		}
+	}
 
-  close(sock);
-  return 0;
+	close(sock);
+	return 0;
 }
 
 
@@ -272,47 +901,110 @@
  * ListenAtTcpPort starts listening at the given TCP port.
  */
 
-int
-ListenAtTcpPort(int port)
-{
-  int sock;
-  struct sockaddr_in addr;
-  int one = 1;
-
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons(port);
-  addr.sin_addr.s_addr = INADDR_ANY;
+int use_loopback = 0;
 
-  sock = socket(AF_INET, SOCK_STREAM, 0);
-  if (sock < 0) {
-    fprintf(stderr,programName);
-    perror(": ListenAtTcpPort: socket");
-    return -1;
-  }
+int ListenAtTcpPort(int port) {
+	int sock;
+	struct sockaddr_in addr;
+	int one = 1;
+
+	if (appData.noipv4) {
+		fprintf(stderr, "ipv4 is disabled via VNCVIEWER_NO_IPV4/-noipv4.\n");
+		return -1;
+	}
 
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-		 (const char *)&one, sizeof(one)) < 0) {
-    fprintf(stderr,programName);
-    perror(": ListenAtTcpPort: setsockopt");
-    close(sock);
-    return -1;
-  }
+	memset(&addr, 0, sizeof(struct sockaddr_in));
 
-  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    fprintf(stderr,programName);
-    perror(": ListenAtTcpPort: bind");
-    close(sock);
-    return -1;
-  }
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = INADDR_ANY;
 
-  if (listen(sock, 5) < 0) {
-    fprintf(stderr,programName);
-    perror(": ListenAtTcpPort: listen");
-    close(sock);
-    return -1;
-  }
+	if (getenv("VNCVIEWER_LISTEN_LOCALHOST") || use_loopback) {
+		addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	}
+
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0) {
+		perror("ListenAtTcpPort: socket");
+		return -1;
+	}
 
-  return sock;
+	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one)) < 0) {
+		perror("ListenAtTcpPort: setsockopt");
+		close(sock);
+		return -1;
+	}
+
+	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		perror("ListenAtTcpPort: bind");
+		close(sock);
+		return -1;
+	}
+
+	if (listen(sock, 32) < 0) {
+		perror("ListenAtTcpPort: listen");
+		close(sock);
+		return -1;
+	}
+
+	return sock;
+}
+
+int ListenAtTcpPort6(int port) {
+	int sock = -1;
+#ifdef AF_INET6
+	struct sockaddr_in6 sin;
+	int one = 1;
+
+	if (appData.noipv6) {
+		fprintf(stderr, "ipv6 is disabled via VNCVIEWER_NO_IPV6/-noipv6.\n");
+		return -1;
+	}
+
+	sock = socket(AF_INET6, SOCK_STREAM, 0);
+	if (sock < 0) {
+		perror("ListenAtTcpPort[ipv6]: socket");
+		return -1;
+	}
+
+	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
+		perror("ListenAtTcpPort[ipv6]: setsockopt1");
+		close(sock);
+		return -1;
+	}
+
+#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+	if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
+		perror("ListenAtTcpPort[ipv6]: setsockopt2");
+		close(sock);
+		return -1;
+	}
+#endif
+
+	memset((char *)&sin, 0, sizeof(sin));
+	sin.sin6_family = AF_INET6;
+	sin.sin6_port   = htons(port);
+	sin.sin6_addr   = in6addr_any;
+
+	if (getenv("VNCVIEWER_LISTEN_LOCALHOST") || use_loopback) {
+		sin.sin6_addr = in6addr_loopback;
+	}
+
+	if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+		perror("ListenAtTcpPort[ipv6]: bind");
+		close(sock);
+		return -1;
+	}
+
+	if (listen(sock, 32) < 0) {
+		perror("ListenAtTcpPort[ipv6]: listen");
+		close(sock);
+		return -1;
+	}
+
+#endif
+	if (port) {}
+	return sock;
 }
 
 
@@ -320,33 +1012,69 @@
  * AcceptTcpConnection accepts a TCP connection.
  */
 
-int
-AcceptTcpConnection(int listenSock)
-{
-  int sock;
-  struct sockaddr_in addr;
-  int addrlen = sizeof(addr);
-  int one = 1;
+int AcceptTcpConnection(int listenSock) {
+	int sock;
+	struct sockaddr_in addr;
+	int addrlen = sizeof(addr);
+	int one = 1;
+
+	sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
+	if (sock < 0) {
+		perror("AcceptTcpConnection: accept");
+		return -1;
+	}
 
-  sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
-  if (sock < 0) {
-    fprintf(stderr,programName);
-    perror(": AcceptTcpConnection: accept");
-    return -1;
-  }
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+		perror("AcceptTcpConnection: setsockopt");
+		close(sock);
+		return -1;
+	}
 
-  if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
-		 (char *)&one, sizeof(one)) < 0) {
-    fprintf(stderr,programName);
-    perror(": AcceptTcpConnection: setsockopt");
-    close(sock);
-    return -1;
-  }
+	return sock;
+}
+
+char *accept6_ipaddr = NULL;
+char *accept6_hostname = NULL;
+
+int AcceptTcpConnection6(int listenSock) {
+	int sock = -1;
+#ifdef AF_INET6
+	struct sockaddr_in6 addr;
+	socklen_t addrlen = sizeof(addr);
+	int one = 1;
+	char *name;
+
+	if (appData.noipv6) {
+		return -1;
+	}
+
+	sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
+	if (sock < 0) {
+		perror("AcceptTcpConnection[ipv6]: accept");
+		return -1;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+		perror("AcceptTcpConnection[ipv6]: setsockopt");
+		close(sock);
+		return -1;
+	}
 
-  return sock;
+	name = ipv6_getipaddr((struct sockaddr *) &addr, addrlen);
+	if (!name) name = strdup("unknown");
+	accept6_ipaddr = name;
+	fprintf(stderr, "AcceptTcpConnection6: ipv6 connection from: '%s'\n", name);
+
+	name = ipv6_getnameinfo((struct sockaddr *) &addr, addrlen);
+	if (!name) name = strdup("unknown");
+	accept6_hostname = name;
+#endif
+	if (listenSock) {}
+	return sock;
 }
 
 
+
 /*
  * SetNonBlocking sets a socket into non-blocking mode.
  */
@@ -379,7 +1107,7 @@
 
   *addr = inet_addr(str);
 
-  if (*addr != -1)
+  if (*addr != (unsigned int) -1)
     return True;
 
   hp = gethostbyname(str);
@@ -392,6 +1120,42 @@
   return False;
 }
 
+char *get_peer_ip(int sock) {
+	struct sockaddr_in saddr;
+	unsigned int saddr_len;
+	int saddr_port;
+	char *saddr_ip_str = NULL;
+
+	saddr_len = sizeof(saddr);
+	memset(&saddr, 0, sizeof(saddr));
+	saddr_port = -1;
+	if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+		saddr_ip_str = inet_ntoa(saddr.sin_addr);
+	}
+	if (! saddr_ip_str) {
+		saddr_ip_str = "unknown";
+	}
+	return strdup(saddr_ip_str);
+}
+
+char *ip2host(char *ip) {
+	char *str;
+	struct hostent *hp;
+	in_addr_t iaddr;
+
+	iaddr = inet_addr(ip);
+	if (iaddr == htonl(INADDR_NONE)) {
+		return strdup("unknown");
+	}
+
+	hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET);
+	if (!hp) {
+		return strdup("unknown");
+	}
+	str = strdup(hp->h_name);
+	return str;
+}
+
 
 /*
  * Test if the other end of a socket is on the same machine.
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tight.c vnc_unixsrc/vncviewer/tight.c
--- vnc_unixsrc.orig/vncviewer/tight.c	2002-04-30 09:07:31.000000000 -0400
+++ vnc_unixsrc/vncviewer/tight.c	2008-10-05 15:16:35.000000000 -0400
@@ -129,14 +129,21 @@
 #endif
 
 #if (BPP == 8)
-    gcv.foreground = (appData.useBGR233) ?
-      BGR233ToPixel[fill_colour] : fill_colour;
+    gcv.foreground = (appData.useBGR233) ?  BGR233ToPixel[fill_colour] : fill_colour;
+#else
+#if (BPP == 16)
+    gcv.foreground = (appData.useBGR565) ?  BGR565ToPixel[fill_colour] : fill_colour;
 #else
     gcv.foreground = fill_colour;
 #endif
+#endif
 
-    XChangeGC(dpy, gc, GCForeground, &gcv);
-    XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
+	if (!appData.useXserverBackingStore) {
+		FillScreen(rx, ry, rw, rh, gcv.foreground);
+	} else {
+		XChangeGC(dpy, gc, GCForeground, &gcv);
+		XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
+	}
     return True;
   }
 
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tmake vnc_unixsrc/vncviewer/tmake
--- vnc_unixsrc.orig/vncviewer/tmake	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/tmake	2009-10-25 10:31:22.000000000 -0400
@@ -0,0 +1,17 @@
+#!/bin/sh
+TURBOVNC_DIR=/home/runge/turbojpeg
+make clean
+(cd ../libvncauth || exit 1; make)
+if [ "X$1" = "X-a" ]; then
+	exit
+fi
+make CCOPTIONS=-DTURBOVNC EXTRA_LIBRARIES="-L$TURBOVNC_DIR -Xlinker --rpath=$TURBOVNC_DIR -Xlinker --rpath=/usr/local/lib -lturbojpeg"
+cp -p vncviewer vncviewer.turbovnc
+strip vncviewer.turbovnc
+ls -l vncviewer.turbovnc
+ldd   vncviewer.turbovnc
+
+echo
+make clean all
+ls -l vncviewer
+ldd   vncviewer
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tunnel.c vnc_unixsrc/vncviewer/tunnel.c
--- vnc_unixsrc.orig/vncviewer/tunnel.c	2003-07-31 04:03:49.000000000 -0400
+++ vnc_unixsrc/vncviewer/tunnel.c	2010-02-25 23:39:24.000000000 -0500
@@ -100,7 +100,6 @@
 		  int *pargc, char **argv, int tunnelArgIndex)
 {
   char *pdisplay;
-  int port;
 
   if (tunnelArgIndex >= *pargc - 1)
     usage();
@@ -132,6 +131,7 @@
 {
   char *colonPos;
   int len, portOffset;
+  int disp;
 
   if (tunnelArgIndex >= *pargc - 2)
     usage();
@@ -150,10 +150,17 @@
       len--;
       portOffset = 0;
     }
-    if (!len || strspn(colonPos, "-0123456789") != len) {
+    if (!len || (int) strspn(colonPos, "-0123456789") != len) {
       usage();
     }
+#if 0
     *remotePort = atoi(colonPos) + portOffset;
+#else
+    disp = atoi(colonPos);
+    if (portOffset != 0 && disp >= 100)
+      portOffset = 0;
+    *remotePort = disp + portOffset;
+#endif
   }
 
   sprintf(lastArgv, "localhost::%d", localPort);
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/tight.c vnc_unixsrc/vncviewer/turbovnc/tight.c
--- vnc_unixsrc.orig/vncviewer/turbovnc/tight.c	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/turbovnc/tight.c	2008-08-20 13:35:58.000000000 -0400
@@ -0,0 +1,613 @@
+/*
+ *  Copyright (C) 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ *  Copyright (C) 2004 Landmark Graphics Corporation.  All Rights Reserved.
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * tight.c - handle ``tight'' encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple
+ * times by rfbproto.c, each time with a different definition of the
+ * macro BPP. For each value of BPP, this file defines a function
+ * which handles a tight-encoded rectangle with BPP bits per pixel.
+ *
+ */
+
+#define TIGHT_MIN_TO_COMPRESS 12
+
+#define CARDBPP CONCAT2E(CARD,BPP)
+#define filterPtrBPP CONCAT2E(filterPtr,BPP)
+
+#define HandleTightBPP CONCAT2E(HandleTight,BPP)
+#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
+#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
+#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
+#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
+#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
+#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
+
+#if BPP != 8
+#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
+#endif
+
+#ifndef RGB_TO_PIXEL
+
+#define RGB_TO_PIXEL(bpp,r,g,b)						\
+  (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift |		\
+   ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift |	\
+   ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL(bpp,r,g,b)                                       \
+   ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255             \
+    << myFormat.redShift |                                              \
+    (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255           \
+    << myFormat.greenShift |                                            \
+    (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255            \
+    << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b)						\
+  (((CARD32)(r) & 0xFF) << myFormat.redShift |				\
+   ((CARD32)(g) & 0xFF) << myFormat.greenShift |			\
+   ((CARD32)(b) & 0xFF) << myFormat.blueShift)
+
+#endif
+
+extern XImage *image;
+
+/* Type declarations */
+
+typedef void (*filterPtrBPP)(int, int, int);
+
+/* Prototypes */
+
+static int InitFilterCopyBPP (int rw, int rh);
+static int InitFilterPaletteBPP (int rw, int rh);
+static int InitFilterGradientBPP (int rw, int rh);
+static void FilterCopyBPP (int srcx, int srcy, int numRows);
+static void FilterPaletteBPP (int srcx, int srcy, int numRows);
+static void FilterGradientBPP (int srcx, int srcy, int numRows);
+
+static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
+
+/* Definitions */
+
+static Bool
+HandleTightBPP (int rx, int ry, int rw, int rh)
+{
+  CARDBPP fill_colour;
+  XGCValues gcv;
+  CARD8 comp_ctl;
+  CARD8 filter_id;
+  filterPtrBPP filterFn;
+  z_streamp zs;
+  int err, stream_id, compressedLen, bitsPixel;
+  int bufferSize, rowSize, numRows;
+  Bool readUncompressed = False;
+  CARDBPP *rawData;
+
+  if (!ReadFromRFBServer((char *)&comp_ctl, 1))
+    return False;
+
+  /* Flush zlib streams if we are told by the server to do so. */
+  for (stream_id = 0; stream_id < 4; stream_id++) {
+    if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
+      if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
+	  zlibStream[stream_id].msg != NULL)
+	fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
+      zlibStreamActive[stream_id] = False;
+    }
+    comp_ctl >>= 1;
+  }
+
+  if ((comp_ctl & rfbTightNoZlib) == rfbTightNoZlib) {
+     comp_ctl &= ~(rfbTightNoZlib);
+     readUncompressed = True;
+  }
+
+  /* Handle solid rectangles. */
+  if (comp_ctl == rfbTightFill) {
+#if BPP == 32
+    if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+	myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+      if (!ReadFromRFBServer(buffer, 3))
+	return False;
+      fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
+    } else {
+      if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+	return False;
+    }
+#else
+    if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+	return False;
+#endif
+
+#if (BPP == 8)
+    gcv.foreground = (appData.useBGR233) ?
+      BGR233ToPixel[fill_colour] : fill_colour;
+#else
+    gcv.foreground = fill_colour;
+#endif
+
+    FillRectangle(&gcv, rx, ry, rw, rh);
+    return True;
+  }
+
+#if BPP == 8
+  if (comp_ctl == rfbTightJpeg) {
+    fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
+    return False;
+  }
+#else
+  if (comp_ctl == rfbTightJpeg) {
+    return DecompressJpegRectBPP(rx, ry, rw, rh);
+  }
+#endif
+
+  /* Quit on unsupported subencoding value. */
+  if (comp_ctl > rfbTightMaxSubencoding) {
+    fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
+    return False;
+  }
+
+  /*
+   * Here primary compression mode handling begins.
+   * Data was processed with optional filter + zlib compression.
+   */
+
+  /* First, we should identify a filter to use. */
+  if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+    if (!ReadFromRFBServer((char*)&filter_id, 1))
+      return False;
+
+    switch (filter_id) {
+    case rfbTightFilterCopy:
+      filterFn = FilterCopyBPP;
+      bitsPixel = InitFilterCopyBPP(rw, rh);
+      break;
+    case rfbTightFilterPalette:
+      filterFn = FilterPaletteBPP;
+      bitsPixel = InitFilterPaletteBPP(rw, rh);
+      break;
+    case rfbTightFilterGradient:
+      filterFn = FilterGradientBPP;
+      bitsPixel = InitFilterGradientBPP(rw, rh);
+      break;
+    default:
+      fprintf(stderr, "Tight encoding: unknown filter code received.\n");
+      return False;
+    }
+  } else {
+    filterFn = FilterCopyBPP;
+    bitsPixel = InitFilterCopyBPP(rw, rh);
+  }
+  if (bitsPixel == 0) {
+    fprintf(stderr, "Tight encoding: error receiving palette.\n");
+    return False;
+  }
+
+  /* Determine if the data should be decompressed or just copied. */
+  rowSize = (rw * bitsPixel + 7) / 8;
+  bufferSize = -1;
+  if (rh * rowSize < TIGHT_MIN_TO_COMPRESS)
+    bufferSize = rh * rowSize;
+  else if (readUncompressed) {
+    bufferSize = (int)ReadCompactLen();
+  }
+  if (bufferSize != -1) {
+    uncompressedData = (char *)realloc(uncompressedData, bufferSize);
+    if (!uncompressedData) {
+      fprintf(stderr, "Memory allocation error\n");
+      return False;
+    }
+    if (!ReadFromRFBServer(uncompressedData, bufferSize))
+      return False;
+    filterFn(rx, ry, rh);
+    if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh);
+    if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh);
+
+    return True;
+  }
+
+  /* Read the length (1..3 bytes) of compressed data following. */
+  compressedLen = (int)ReadCompactLen();
+  if (compressedLen <= 0) {
+    fprintf(stderr, "Incorrect data received from the server.\n");
+    return False;
+  }
+
+  /* Now let's initialize compression stream if needed. */
+  stream_id = comp_ctl & 0x03;
+  zs = &zlibStream[stream_id];
+  if (!zlibStreamActive[stream_id]) {
+    zs->zalloc = Z_NULL;
+    zs->zfree = Z_NULL;
+    zs->opaque = Z_NULL;
+    err = inflateInit(zs);
+    if (err != Z_OK) {
+      if (zs->msg != NULL)
+	fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
+      return False;
+    }
+    zlibStreamActive[stream_id] = True;
+  }
+
+  /* Read, decode and draw actual pixel data in a loop. */
+
+  compressedData = (char *)realloc(compressedData, compressedLen);
+  if (!compressedData) {
+    fprintf(stderr, "Memory allocation error\n");
+    return False;
+  }
+  uncompressedData = (char *)realloc(uncompressedData, rh * rowSize);
+  if (!uncompressedData) {
+    fprintf(stderr, "Memory allocation error\n");
+    return False;
+  }
+
+  if (!ReadFromRFBServer(compressedData, compressedLen))
+    return False;
+  zs->next_in = (Bytef *)compressedData;
+  zs->avail_in = compressedLen;
+  zs->next_out = (Bytef *)uncompressedData;
+  zs->avail_out = rh * rowSize;
+
+  err = inflate(zs, Z_SYNC_FLUSH);
+  if (err != Z_OK && err != Z_STREAM_END) {
+    if (zs->msg != NULL) {
+      fprintf(stderr, "Inflate error: %s.\n", zs->msg);
+    } else {
+      fprintf(stderr, "Inflate error: %d.\n", err);
+    }
+    return False;
+  }
+
+  filterFn(rx, ry, rh);
+  if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh);
+  if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh);
+
+  return True;
+}
+
+/*----------------------------------------------------------------------------
+ *
+ * Filter stuff.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool cutZeros;
+     static int rectWidth, rectColors;
+     static CARD8 tightPalette[256*4];
+     static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
+*/
+
+static int
+InitFilterCopyBPP (int rw, int rh)
+{
+  rectWidth = rw;
+
+#if BPP == 32
+  if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+      myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+    cutZeros = True;
+    return 24;
+  } else {
+    cutZeros = False;
+  }
+#endif
+
+  return BPP;
+}
+
+static void
+FilterCopyBPP (int srcx, int srcy, int numRows)
+{
+  CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line
+                                         + srcx * image->bits_per_pixel/8];
+  int dstw = image->bytes_per_line / (image->bits_per_pixel / 8);
+  int y;
+#if BPP == 32
+  int x;
+#endif
+
+  if (appData.useBGR233) {
+    dst = (CARDBPP *)buffer;
+    dstw = rectWidth;
+  }
+
+#if BPP == 32
+  if (cutZeros) {
+    for (y = 0; y < numRows; y++) {
+      for (x = 0; x < rectWidth; x++) {
+	dst[y*dstw+x] =
+	  RGB24_TO_PIXEL32(uncompressedData[(y*rectWidth+x)*3],
+			   uncompressedData[(y*rectWidth+x)*3+1],
+			   uncompressedData[(y*rectWidth+x)*3+2]);
+      }
+    }
+    return;
+  }
+#endif
+
+  for (y = 0; y < numRows; y++)
+    memcpy (&dst[y*dstw], &uncompressedData[y*rectWidth], rectWidth * (BPP / 8));
+}
+
+static int
+InitFilterGradientBPP (int rw, int rh)
+{
+  int bits;
+
+  bits = InitFilterCopyBPP(rw, rh);
+  if (cutZeros)
+    memset(tightPrevRow, 0, rw * 3);
+  else
+    memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
+
+  return bits;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24 (int srcx, int srcy, int numRows)
+{
+  CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line
+                                         + srcx * image->bits_per_pixel/8];
+  int dstw = image->bytes_per_line / (image->bits_per_pixel / 8);
+  int x, y, c;
+  CARD8 thisRow[2048*3];
+  CARD8 pix[3];
+  int est[3];
+
+  if (appData.useBGR233) {
+    dst = (CARDBPP *)buffer;
+    dstw = rectWidth;
+  }
+
+  for (y = 0; y < numRows; y++) {
+
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = tightPrevRow[c] + uncompressedData[y*rectWidth*3+c];
+      thisRow[c] = pix[c];
+    }
+    dst[y*dstw] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
+		 (int)tightPrevRow[(x-1)*3+c];
+	if (est[c] > 0xFF) {
+	  est[c] = 0xFF;
+	} else if (est[c] < 0x00) {
+	  est[c] = 0x00;
+	}
+	pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
+	thisRow[x*3+c] = pix[c];
+      }
+      dst[y*dstw+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+    }
+
+    memcpy(tightPrevRow, thisRow, rectWidth * 3);
+  }
+}
+
+#endif
+
+static void
+FilterGradientBPP (int srcx, int srcy, int numRows)
+{
+  int x, y, c;
+  CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line
+                                         + srcx * image->bits_per_pixel/8];
+  int dstw = image->bytes_per_line / (image->bits_per_pixel / 8);
+  CARDBPP *src = (CARDBPP *)uncompressedData;
+  CARD16 *thatRow = (CARD16 *)tightPrevRow;
+  CARD16 thisRow[2048*3];
+  CARD16 pix[3];
+  CARD16 max[3];
+  int shift[3];
+  int est[3];
+
+  if (appData.useBGR233) {
+    dst = (CARDBPP *)buffer;
+    dstw = rectWidth;
+  }
+
+#if BPP == 32
+  if (cutZeros) {
+    FilterGradient24(srcx, srcy, numRows);
+    return;
+  }
+#endif
+
+  max[0] = myFormat.redMax;
+  max[1] = myFormat.greenMax;
+  max[2] = myFormat.blueMax;
+
+  shift[0] = myFormat.redShift;
+  shift[1] = myFormat.greenShift;
+  shift[2] = myFormat.blueShift;
+
+  for (y = 0; y < numRows; y++) {
+
+    /* First pixel in a row */
+    for (c = 0; c < 3; c++) {
+      pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
+      thisRow[c] = pix[c];
+    }
+    dst[y*dstw] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+
+    /* Remaining pixels of a row */
+    for (x = 1; x < rectWidth; x++) {
+      for (c = 0; c < 3; c++) {
+	est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
+	if (est[c] > (int)max[c]) {
+	  est[c] = (int)max[c];
+	} else if (est[c] < 0) {
+	  est[c] = 0;
+	}
+	pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
+	thisRow[x*3+c] = pix[c];
+      }
+      dst[y*dstw+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+    }
+    memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
+  }
+}
+
+static int
+InitFilterPaletteBPP (int rw, int rh)
+{
+  int i;
+  CARD8 numColors;
+  CARDBPP *palette = (CARDBPP *)tightPalette;
+
+  rectWidth = rw;
+
+  if (!ReadFromRFBServer((char*)&numColors, 1))
+    return 0;
+
+  rectColors = (int)numColors;
+  if (++rectColors < 2)
+    return 0;
+
+#if BPP == 32
+  if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+      myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+    if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
+      return 0;
+    for (i = rectColors - 1; i >= 0; i--) {
+      palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+				    tightPalette[i*3+1],
+				    tightPalette[i*3+2]);
+    }
+    return (rectColors == 2) ? 1 : 8;
+  }
+#endif
+
+  if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
+    return 0;
+
+  return (rectColors == 2) ? 1 : 8;
+}
+
+static void
+FilterPaletteBPP (int srcx, int srcy, int numRows)
+{
+  int x, y, b, w;
+  CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line
+                                         + srcx * image->bits_per_pixel/8];
+  int dstw = image->bytes_per_line / (image->bits_per_pixel / 8);
+  CARD8 *src = (CARD8 *)uncompressedData;
+  CARDBPP *palette = (CARDBPP *)tightPalette;
+
+  if (appData.useBGR233) {
+    dst = (CARDBPP *)buffer;
+    dstw = rectWidth;
+  }
+
+  if (rectColors == 2) {
+    w = (rectWidth + 7) / 8;
+    for (y = 0; y < numRows; y++) {
+      for (x = 0; x < rectWidth / 8; x++) {
+	for (b = 7; b >= 0; b--)
+	  dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+      }
+      for (b = 7; b >= 8 - rectWidth % 8; b--) {
+	dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+      }
+    }
+  } else {
+    for (y = 0; y < numRows; y++)
+      for (x = 0; x < rectWidth; x++)
+	dst[y*dstw+x] = palette[(int)src[y*rectWidth+x]];
+  }
+}
+
+#if BPP != 8
+
+/*----------------------------------------------------------------------------
+ *
+ * JPEG decompression.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool jpegError;
+     static struct jpeg_source_mgr jpegSrcManager;
+     static JOCTET *jpegBufferPtr;
+     static size_t *jpegBufferLen;
+*/
+
+static Bool
+DecompressJpegRectBPP(int x, int y, int w, int h)
+{
+  int compressedLen;
+  char *dstptr;
+  int ps, flags=0;
+
+  compressedLen = (int)ReadCompactLen();
+  if (compressedLen <= 0) {
+    fprintf(stderr, "Incorrect data received from the server.\n");
+    return False;
+  }
+
+  compressedData = (char *)realloc(compressedData, compressedLen);
+  if (compressedData == NULL) {
+    fprintf(stderr, "Memory allocation error.\n");
+    return False;
+  }
+
+  if (!ReadFromRFBServer(compressedData, compressedLen)) {
+    return False;
+  }
+
+  if(!tjhnd) {
+    if((tjhnd=tjInitDecompress())==NULL) {
+      fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr());
+      return False;
+    }
+  }     
+
+  ps=image->bits_per_pixel/8;
+  if(myFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST;
+  if(myFormat.redShift==16 && myFormat.blueShift==0)
+    flags|=TJ_BGR;
+  if(myFormat.bigEndian) flags^=TJ_BGR;
+
+  dstptr=&image->data[image->bytes_per_line*y+x*ps];
+  if(tjDecompress(tjhnd, (unsigned char *)compressedData, (unsigned long)compressedLen,
+    (unsigned char *)dstptr, w, image->bytes_per_line, h, ps, flags)==-1) {
+    fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr());
+    return False;
+  }
+
+  if (!appData.doubleBuffer)
+    CopyImageToScreen(x, y, w, h);
+
+  return True;
+}
+
+#endif
+
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h
--- vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h	2008-04-03 04:28:56.000000000 -0400
@@ -0,0 +1,229 @@
+/* Copyright (C)2004 Landmark Graphics
+ * Copyright (C)2005, 2006 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE)
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+#define DLLCALL
+
+/* Subsampling */
+#define NUMSUBOPT 4
+
+enum {TJ_444=0, TJ_422, TJ_411, TJ_GRAYSCALE};
+
+/* Flags */
+#define TJ_BGR       1
+#define TJ_BOTTOMUP  2
+#define TJ_FORCEMMX  8   /* Force IPP to use MMX code even if SSE available */
+#define TJ_FORCESSE  16  /* Force IPP to use SSE1 code even if SSE2 available */
+#define TJ_FORCESSE2 32  /* Force IPP to use SSE2 code (useful if auto-detect is not working properly) */
+#define TJ_ALPHAFIRST 64 /* BGR buffer is ABGR and RGB buffer is ARGB */
+#define TJ_FORCESSE3 128 /* Force IPP to use SSE3 code (useful if auto-detect is not working properly) */
+
+typedef void* tjhandle;
+
+#define TJPAD(p) (((p)+3)&(~3))
+#ifndef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* API follows */
+
+
+/*
+  tjhandle tjInitCompress(void)
+
+  Creates a new JPEG compressor instance, allocates memory for the structures,
+  and returns a handle to the instance.  Most applications will only
+  need to call this once at the beginning of the program or once for each
+  concurrent thread.  Don't try to create a new instance every time you
+  compress an image, because this will cause performance to suffer.
+
+  RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
+
+
+/*
+  int tjCompress(tjhandle j,
+     unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+     unsigned char *dstbuf, unsigned long *size,
+     int jpegsubsamp, int jpegqual, int flags)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitCompress()
+  [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in
+     RGB(A) or BGR(A) form
+  [INPUT] width =  width (in pixels) of the source image
+  [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
+     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+     is padded to the nearest 32-bit boundary, such as is the case for Windows
+     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
+     as long as the pitch is greater than 0.)
+  [INPUT] height = height (in pixels) of the source image
+  [INPUT] pixelsize = size (in bytes) of each pixel in the source image
+     RGBA and BGRA: 4, RGB and BGR: 3
+  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+     the JPEG image.  Use the macro TJBUFSIZE(width, height) to determine
+     the appropriate size for this buffer based on the image width and height.
+  [OUTPUT] size = pointer to unsigned long which receives the size (in bytes)
+     of the compressed image
+  [INPUT] jpegsubsamp = Specifies either 4:1:1, 4:2:2, or 4:4:4 subsampling.
+     When the image is converted from the RGB to YCbCr colorspace as part of the
+     JPEG compression process, every other Cb and Cr (chrominance) pixel can be
+     discarded to produce a smaller image with little perceptible loss of
+     image clarity (the human eye is more sensitive to small changes in
+     brightness than small changes in color.)
+
+     TJ_411: 4:1:1 subsampling.  Discards every other Cb, Cr pixel in both
+        horizontal and vertical directions.
+     TJ_422: 4:2:2 subsampling.  Discards every other Cb, Cr pixel only in
+        the horizontal direction.
+     TJ_444: no subsampling.
+     TJ_GRAYSCALE: Generate grayscale JPEG image
+
+  [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.)
+  [INPUT] flags = the bitwise OR of one or more of the following
+
+     TJ_BGR: The components of each pixel in the source image are stored in
+        B,G,R order, not R,G,B
+     TJ_BOTTOMUP: The source image is stored in bottom-up (Windows) order,
+        not top-down
+     TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+     TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+     TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+     TJ_FORCESSE3: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE3 code (bypass CPU auto-detection)
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjCompress(tjhandle j,
+	unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+	unsigned char *dstbuf, unsigned long *size,
+	int jpegsubsamp, int jpegqual, int flags);
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
+
+/*
+  tjhandle tjInitDecompress(void)
+
+  Creates a new JPEG decompressor instance, allocates memory for the
+  structures, and returns a handle to the instance.  Most applications will
+  only need to call this once at the beginning of the program or once for each
+  concurrent thread.  Don't try to create a new instance every time you
+  decompress an image, because this will cause performance to suffer.
+
+  RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
+
+
+/*
+  int tjDecompressHeader(tjhandle j,
+     unsigned char *srcbuf, unsigned long size,
+     int *width, int *height)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitDecompress()
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+     to decompress
+  [INPUT] size = size of the JPEG image buffer (in bytes)
+  [OUTPUT] width = width (in pixels) of the JPEG image
+  [OUTPUT] height = height (in pixels) of the JPEG image
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
+	unsigned char *srcbuf, unsigned long size,
+	int *width, int *height);
+
+
+/*
+  int tjDecompress(tjhandle j,
+     unsigned char *srcbuf, unsigned long size,
+     unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+     int flags)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitDecompress()
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+     to decompress
+  [INPUT] size = size of the JPEG image buffer (in bytes)
+  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+     the bitmap image.  This buffer should normally be pitch*height
+     bytes in size, although this pointer may also be used to decompress into
+     a specific region of a larger buffer.
+  [INPUT] width =  width (in pixels) of the destination image
+  [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the
+     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+     is padded to the nearest 32-bit boundary, such as is the case for Windows
+     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
+     as long as the pitch is greater than 0.)
+  [INPUT] height = height (in pixels) of the destination image
+  [INPUT] pixelsize = size (in bytes) of each pixel in the destination image
+     RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3
+  [INPUT] flags = the bitwise OR of one or more of the following
+
+     TJ_BGR: The components of each pixel in the destination image should be
+        written in B,G,R order, not R,G,B
+     TJ_BOTTOMUP: The destination image should be stored in bottom-up
+        (Windows) order, not top-down
+     TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+     TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+     TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompress(tjhandle j,
+	unsigned char *srcbuf, unsigned long size,
+	unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+	int flags);
+
+
+/*
+  int tjDestroy(tjhandle h)
+
+  Frees structures associated with a compression or decompression instance
+  
+  [INPUT] h = instance handle (returned from a previous call to
+     tjInitCompress() or tjInitDecompress()
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDestroy(tjhandle h);
+
+
+/*
+  char *tjGetErrorStr(void)
+  
+  Returns a descriptive error message explaining why the last command failed
+*/
+DLLEXPORT char* DLLCALL tjGetErrorStr(void);
+
+#ifdef __cplusplus
+}
+#endif
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer._man vnc_unixsrc/vncviewer/vncviewer._man
--- vnc_unixsrc.orig/vncviewer/vncviewer._man	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/vncviewer._man	2010-04-11 23:30:24.000000000 -0400
@@ -0,0 +1,829 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for X vncviewer
+.\"
+.\" Copyright (C) 1998 Marcus.Brinkmann@ruhr-uni-bochum.de
+.\" Copyright (C) 2000,2001 Red Hat, Inc.
+.\" Copyright (C) 2001-2003 Constantin Kaplinsky <const@ce.cctpu.edu.ru>
+.\" Copyright (C) 2006-2010 Karl J. Runge <runge@karlrunge.com>
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file LICENCE.TXT that comes with the
+.\" TightVNC distribution.
+.\"
+.TH ssvncviewer 1 "April 2010" "" "SSVNC"
+.SH NAME
+ssvncviewer \- an X viewer client for VNC
+.SH SYNOPSIS
+.B ssvncviewer
+.RI [\| options \|]
+.RI [\| host \|][\| :display \|]
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI [\| host \|][\| ::port \|]
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI exec=[\| cmd+args... \|]
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI fd=n
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI /path/to/unix/socket
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.IR \-listen
+.RI [\| display \|]
+.br
+.B ssvncviewer
+.IR \-help
+.br
+.SH DESCRIPTION
+.B ssvncviewer
+is an Xt\-based client application for the VNC (Virtual Network
+Computing) system. It can connect to any VNC\-compatible server such
+as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment
+of a different machine.
+
+ssvncviewer is an enhanced version of the tightvnc unix viewer that can
+take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers.
+See below for the description of these features.
+
+You can use F8 to display a pop\-up utility menu. Press F8 twice to
+pass single F8 to the remote side.
+.SH OPTIONS
+.TP
+\fB\-help\fR
+Prints a short usage notice to stderr.
+.TP
+\fB\-listen\fR
+Make the viewer listen on port 5500+\fIdisplay\fR for reverse
+connections from a server. WinVNC supports reverse connections using
+the "Add New Client" menu option, or the \-connect command line
+option. \fBXvnc\fR requires the use of the helper program
+\fBvncconnect\fR.
+.TP
+\fB\-via\fR \fIgateway\fR
+Automatically create encrypted TCP tunnel to the \fIgateway\fR machine
+before connection, connect to the \fIhost\fR through that tunnel
+(TightVNC\-specific). By default, this option invokes SSH local port
+forwarding, assuming that SSH client binary can be accessed as
+/usr/bin/ssh. Note that when using the \fB\-via\fR option, the host
+machine name should be specified as known to the gateway machine, e.g. 
+"localhost" denotes the \fIgateway\fR, not the machine where vncviewer
+was launched. See the ENVIRONMENT section below for the information on
+configuring the \fB\-via\fR option.
+.TP
+\fB\-shared\fR
+When connecting, specify that a shared connection is requested. In
+TightVNC, this is the default mode, allowing you to share the desktop
+with other clients already using it.
+.TP
+\fB\-noshared\fR
+When connecting, specify that the session may not be shared. This
+would either disconnect other connected clients or refuse your
+connection, depending on the server configuration.
+.TP
+\fB\-viewonly\fR
+Disable transfer of mouse and keyboard events from the client to the
+server.
+.TP
+\fB\-fullscreen\fR
+Start in full\-screen mode. Please be aware that operating in
+full\-screen mode may confuse X window managers. Typically, such
+conflicts cause incorrect handling of input focus or make the viewer
+window disappear mysteriously. See the grabKeyboard setting in the
+RESOURCES section below for a method to solve input focus problem.
+.TP
+\fB\-noraiseonbeep\fR
+By default, the viewer shows and raises its window on remote beep
+(bell) event. This option disables such behaviour
+(TightVNC\-specific).
+.TP
+\fB\-user\fR \fIusername\fR
+User name for Unix login authentication. Default is to use current
+Unix user name. If this option was given, the viewer will prefer Unix
+login authentication over the standard VNC authentication.
+.TP
+\fB\-passwd\fR \fIpasswd\-file\fR
+File from which to get the password (as generated by the
+\fBvncpasswd\fR(1) program). This option affects only the standard VNC
+authentication.
+.TP
+\fB\-encodings\fR \fIencoding\-list\fR
+TightVNC supports several different compression methods to encode
+screen updates; this option specifies a set of them to use in order of
+preference. Encodings are specified separated with spaces, and must
+thus be enclosed in quotes if more than one is specified.  Commas may be used to avoid spaces.
+Available encodings, in default order for a remote connection, are
+"copyrect tight hextile zlib corre rre raw". For a local connection
+(to the same machine), the default order to try is "raw copyrect tight
+hextile zlib corre rre". Raw encoding is always assumed as a last option
+if no other encoding can be used for some reason. For more information
+on encodings, see the section ENCODINGS below.
+.TP
+\fB\-bgr233\fR
+Always use the BGR233 format to encode pixel data. This reduces
+network traffic, but colors may be represented inaccurately. The
+bgr233 format is an 8\-bit "true color" format, with 2 bits blue, 3
+bits green, and 3 bits red.
+.TP
+\fB\-owncmap\fR
+Try to use a PseudoColor visual and a private colormap. This allows
+the VNC server to control the colormap.
+.TP
+\fB\-truecolour\fR, \fB\-truecolor\fR
+Try to use a TrueColor visual.
+.TP
+\fB\-depth\fR \fIdepth\fR
+On an X server which supports multiple TrueColor visuals of different
+depths, attempt to use the specified one (in bits per pixel); if
+successful, this depth will be requested from the VNC server.
+.TP
+\fB\-compresslevel \fIlevel\fR
+Use specified compression \fIlevel\fR (0..9) for "tight" and "zlib"
+encodings (TightVNC\-specific). Level 1 uses minimum of CPU time and
+achieves weak compression ratios, while level 9 offers best
+compression but is slow in terms of CPU time consumption on the server
+side. Use high levels with very slow network connections, and low
+levels when working over high\-speed LANs. It's not recommended to use
+compression level 0, reasonable choices start from the level 1.
+.TP
+\fB\-quality \fIlevel\fR
+Use the specified JPEG quality \fIlevel\fR (0..9) for the "tight"
+encoding (TightVNC\-specific). Quality level 0 denotes bad image
+quality but very impressive compression ratios, while level 9 offers
+very good image quality at lower compression ratios. Note that the
+"tight" encoder uses JPEG to encode only those screen areas that look
+suitable for lossy compression, so quality level 0 does not always
+mean unacceptable image quality.
+.TP
+\fB\-nojpeg\fR
+Disable lossy JPEG compression in Tight encoding (TightVNC\-specific). 
+Disabling JPEG compression is not a good idea in typical cases, as
+that makes the Tight encoder less efficient. You might want to use
+this option if it's absolutely necessary to achieve perfect image
+quality (see also the \fB\-quality\fR option).
+.TP
+\fB\-nocursorshape\fR
+Disable cursor shape updates, protocol extensions used to handle
+remote cursor movements locally on the client side
+(TightVNC\-specific). Using cursor shape updates decreases delays with
+remote cursor movements, and can improve bandwidth usage dramatically. 
+.TP
+\fB\-x11cursor\fR
+Use a real X11 cursor with X-style cursor shape updates, instead of
+drawing the remote cursor on the framebuffer. This option also
+disables the dot cursor, and disables cursor position updates in
+non-fullscreen mode.
+.TP
+\fB\-autopass\fR
+Read a plain-text password from stdin. This option affects only the
+standard VNC authentication.
+
+.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS
+.TP
+Enhanced TightVNC Viewer (SSVNC) web page is located at:
+.TP
+http://www.karlrunge.com/x11vnc/ssvnc.html
+.TP
+Note: ZRLE and ZYWRLE encodings are now supported.
+.TP
+Note: F9 is shortcut to Toggle FullScreen mode.
+.TP
+Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1
+to allow more than one incoming VNC server at a time.
+This is the same as -multilisten described below.  Set
+SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n"
+simultaneous reverse connections.
+
+If the host:port is specified as "exec=command args..."
+then instead of making a TCP/IP socket connection to the
+remote VNC server, "command args..." is executed and the
+viewer is attached to its stdio.  This enables tunnelling
+established via an external command, e.g. an stunnel(8)
+that does not involve a listening socket.
+This mode does not work for -listen reverse connections.
+
+If the host:port is specified as "fd=n" then it is assumed
+n is an already opened file descriptor to the socket. (i.e
+the parent did fork+exec)
+
+If the host:port contains a '/' it is interpreted as a
+unix-domain socket (AF_LOCAL insead of AF_INET)
+.TP
+\fB\-multilisten\fR
+As in -listen (reverse connection listening) except
+allow more than one incoming VNC server to be connected
+at a time.  The default for -listen of only one at a
+time tries to play it safe by not allowing anyone on
+the network to put (many) desktops on your screen over
+a long window of time. Use -multilisten for no limit.
+.TP
+\fB\-acceptpopup\fR
+In \fB\-listen\fR (reverse connection listening) mode when
+a reverse VNC connection comes in show a popup asking
+whether to Accept or Reject the connection.  The IP
+address of the connecting host is shown.  Same as
+setting the env. var. SSVNC_ACCEPT_POPUP=1.
+.TP
+\fB\-acceptpopupsc\fR
+As in \fB\-acceptpopup\fR except assume UltraVNC Single
+Click (SC) server.  Retrieve User and ComputerName
+info from UltraVNC Server and display in the Popup.
+.TP
+\fB\-use64\fR
+In \fB\-bgr233\fR mode, use 64 colors instead of 256.
+.TP
+\fB\-bgr222\fR
+Same as \fB\-use64\fR.
+.TP
+\fB\-use8\fR
+In \fB\-bgr233\fR mode, use 8 colors instead of 256.
+.TP
+\fB\-bgr111\fR
+Same as \fB\-use8\fR.
+.TP
+\fB\-16bpp\fR
+If the vnc viewer X display is depth 24 at 32bpp
+request a 16bpp format from the VNC server to cut
+network traffic by up to 2X, then tranlate the
+pixels to 32bpp locally.
+.TP
+\fB\-bgr565\fR
+Same as \fB\-16bpp\fR.
+.TP
+\fB\-grey\fR
+Use a grey scale for the 16- and 8\fB\-bpp\fR modes.
+.TP
+\fB\-alpha\fR
+Use alphablending transparency for local cursors
+requires: x11vnc server, both client and server
+must be 32bpp and same endianness.
+.TP
+\fB\-scale\fR \fIstr\fR
+Scale the desktop locally.  The string "str" can
+a floating point ratio, e.g. "0.9", or a fraction,
+e.g. "3/4", or WxH, e.g. 1280x1024.  Use "fit"
+to fit in the current screen size.  Use "auto" to
+fit in the window size.  "str" can also be set by
+the env. var. SSVNC_SCALE.
+
+If you observe mouse trail painting errors, enable
+X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.)
+
+Note that scaling is done in software and so can be
+slow and requires more memory.  Some speedup Tips:
+
+ZRLE is faster than Tight in this mode.  When
+scaling is first detected, the encoding will
+be automatically switched to ZRLE.  Use the
+Popup menu if you want to go back to Tight.
+Set SSVNC_PRESERVE_ENCODING=1 to disable this.
+
+Use a solid background on the remote side.
+(e.g. manually or via x11vnc \fB\-solid\fR ...)
+
+If the remote server is x11vnc, try client
+side caching: x11vnc \fB\-ncache\fR 10 ...
+.TP
+\fB\-ycrop\fR n
+Only show the top n rows of the framebuffer.  For
+use with x11vnc \fB\-ncache\fR client caching option
+to help "hide" the pixel cache region.
+Use a negative value (e.g. \fB\-1\fR) for autodetection.
+Autodetection will always take place if the remote
+fb height is more than 2 times the width.
+.TP
+\fB\-sbwidth\fR n
+Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR),
+default is very narrow: 2 pixels, it is narrow to
+avoid distraction in \fB\-ycrop\fR mode.
+.TP
+\fB\-nobell\fR
+Disable bell.
+.TP
+\fB\-rawlocal\fR
+Prefer raw encoding for localhost, default is
+no, i.e. assumes you have a SSH tunnel instead.
+.TP
+\fB\-notty\fR
+Try to avoid using the terminal for interactive
+responses: use windows for messages and prompting
+instead.  Messages will also be printed to terminal.
+.TP
+\fB\-sendclipboard\fR
+Send the X CLIPBOARD selection (i.e. Ctrl+C,
+Ctrl+V) instead of the X PRIMARY selection (mouse
+select and middle button paste.)
+.TP
+\fB\-sendalways\fR
+Whenever the mouse enters the VNC viewer main
+window, send the selection to the VNC server even if
+it has not changed.  This is like the Xt resource
+translation SelectionToVNC(always)
+.TP
+\fB\-recvtext\fR
+str   When cut text is received from the VNC server,
+ssvncviewer will set both the X PRIMARY and the
+X CLIPBOARD local selections.  To control which
+is set, specify 'str' as 'primary', 'clipboard',
+or 'both' (the default.)
+.TP
+\fB\-graball\fR
+Grab the entire X server when in fullscreen mode,
+needed by some old window managers like fvwm2.
+.TP
+\fB\-popupfix\fR
+Warp the popup back to the pointer position,
+needed by some old window managers like fvwm2.
+.TP
+\fB\-grabkbd\fR
+Grab the X keyboard when in fullscreen mode,
+needed by some window managers. Same as \fB\-grabkeyboard\fR.
+\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable.
+.TP
+\fB\-bs\fR, \fB\-nobs\fR
+Whether or not to use X server Backingstore for the
+main viewer window.  The default is to not, mainly
+because most Linux, etc, systems X servers disable
+*all* Backingstore by default.  To re\fB\-enable\fR it put
+
+Option "Backingstore"
+
+in the Device section of /etc/X11/xorg.conf.
+In \fB\-bs\fR mode with no X server backingstore, whenever an
+area of the screen is re\fB\-exposed\fR it must go out to the
+VNC server to retrieve the pixels. This is too slow.
+
+In \fB\-nobs\fR mode, memory is allocated by the viewer to
+provide its own backing of the main viewer window. This
+actually makes some activities faster (changes in large
+regions) but can appear to "flash" too much.
+.TP
+\fB\-noshm\fR
+Disable use of MIT shared memory extension (not recommended)
+.TP
+\fB\-termchat\fR
+Do the UltraVNC chat in the terminal vncviewer is in
+instead of in an independent window.
+.TP
+\fB\-unixpw\fR \fIstr\fR
+Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a
+string that allows many ways to enter the Unix Username
+and Unix Password.  These characters: username, newline,
+password, newline are sent to the VNC server after any VNC
+authentication has taken place.  Under x11vnc they are
+used for the \fB\-unixpw\fR login.  Other VNC servers could do
+something similar.
+
+You can also indicate "str" via the environment
+variable SSVNC_UNIXPW.
+
+Note that the Escape key is actually sent first to tell
+x11vnc to not echo the Unix Username back to the VNC
+viewer. Set SSVNC_UNIXPW_NOESC=1 to override this.
+
+If str is ".", then you are prompted at the command line
+for the username and password in the normal way.  If str is
+"-" the stdin is read via getpass(3) for username@password.
+Otherwise if str is a file, it is opened and the first line
+read is taken as the Unix username and the 2nd as the
+password. If str prefixed by "rm:" the file is removed
+after reading. Otherwise, if str has a "@" character,
+it is taken as username@password. Otherwise, the program
+exits with an error. Got all that?
+.TP
+\fB-repeater\fR \fIstr\fR
+This is for use with UltraVNC repeater proxy described
+here: http://www.uvnc.com/addons/repeater.html.  The "str"
+is the ID string to be sent to the repeater.  E.g. ID:1234
+It can also be the hostname and port or display of the VNC
+server, e.g. 12.34.56.78:0 or snoopy.com:1.  Note that when
+using -repeater, the host:dpy on the cmdline is the repeater
+server, NOT the VNC server.  The repeater will connect you.
+
+Example: vncviewer ... -repeater ID:3333 repeat.host:5900
+
+Example: vncviewer ... -repeater vhost:0 repeat.host:5900
+
+Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a
+Single Click III (SSL) repeater (repeater_SSL.exe) and you
+are passing the SSL part of the connection through stunnel, socat, etc.
+This way the magic UltraVNC string 'testB' needed to work with the
+repeater is sent to it.
+.TP
+\fB-rfbversion\fR \fIstr\fR
+Set the advertised RFB version.  E.g.: -rfbversion 3.6  For some
+servers, e.g. UltraVNC this needs to be done.
+.TP
+\fB-ultradsm\fR
+UltraVNC has symmetric private encryption DSM plugins.  See
+http://www.uvnc.com/features/encryption.html.  It is assumed
+you are using a unix program (e.g. our ultravnc_dsm_helper) to
+encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO
+THAT supply -ultradsm to tell THIS viewer to modify the RFB
+data sent so as to work with the UltraVNC Server.  For some
+reason, each RFB msg type must be sent twice under DSM.
+.TP
+\fB\-mslogon\fR \fIuser\fR
+Use Windows MS Logon to an UltraVNC server.  Supply the
+username or "1" to be prompted.  The default is to
+autodetect the UltraVNC MS Logon server and prompt for
+the username and password.
+
+IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman
+exchange is very weak and can be brute forced to recover
+your username and password in a few seconds of CPU
+time.  To be safe, be sure to use an additional encrypted
+tunnel (e.g. SSL or SSH) for the entire VNC session.
+.TP
+\fB\-chatonly\fR
+Try to be a client that only does UltraVNC text chat. This
+mode is used by x11vnc to present a chat window on the physical
+X11 console (i.e. to chat with the person at the display).
+.TP
+\fB-env\fR \fIVAR=VALUE\fR
+To save writing a shell script to set environment
+variables, specify as many as you need on the command line.  For example,
+-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi
+.TP
+\fB\-noipv6\fR
+Disable all IPv6 sockets.  Same as VNCVIEWER_NO_IPV6=1.
+.TP
+\fB\-noipv4\fR
+Disable all IPv4 sockets.  Same as VNCVIEWER_NO_IPV4=1.
+.TP
+\fB\-printres\fR
+Print out the Ssvnc X resources (appdefaults) and
+then exit. You can save them to a file and customize them (e.g. the
+keybindings and Popup menu)  Then point to the file via
+XENVIRONMENT or XAPPLRESDIR.
+.TP
+\fB\-pipeline\fR
+Like TurboVNC, request the next framebuffer update as soon
+as possible instead of waiting until the end of the current
+framebuffer update coming in.  Helps 'pipeline' the updates.
+This is currently the default, use \fB-nopipeline\fR to disable.
+.TP
+\fB\-appshare\fR
+Enable features for use with x11vnc's \fB\-appshare\fR mode where
+instead of sharing the full desktop only the application's
+windows are shared.  Viewer multilisten mode is used to
+create the multiple windows: \fB\-multilisten\fR is implied.
+See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode.
+Features enabled in the viewer under \fB\-appshare\fR are:
+Minimum extra text in the title, auto \fB\-ycrop\fR is disabled,
+x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel,
+x11vnc initial window position hints.  See also Escape Keys
+below for additional key and mouse bindings.
+.TP
+\fB\-escape \fR\fIstr\fR
+This sets the 'Escape Keys' modifier sequence and enables
+escape keys mode.  When the modifier keys escape sequence
+is held down, the next keystroke is interpreted locally
+to perform a special action instead of being sent to the
+remote VNC server.
+
+Use '\fB\-escape\fR default' for the default modifier sequence.
+(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L)
+
+Here are the 'Escape Keys: Help+Set' instructions from the Popup:
+
+Escape Keys:  Enter a comma separated list of modifier keys to be the 'escape
+sequence'.  When these keys are held down, the next keystroke is
+interpreted locally to invoke a special action instead of being sent to
+the remote VNC server.  In other words, a set of 'Hot Keys'.
+
+Here is the list of local key mappings to special actions:
+
+r: refresh desktop  b: toggle bell  c: toggle full-color
+
+f: file transfer    x: x11cursor    z: toggle Tight/ZRLE
+
+l: full screen      g: graball      e: escape keys dialog
+
+s: scale dialog     +: scale up (=) -: scale down (_)
+
+t: text chat                        a: alphablend cursor
+
+V: toggle viewonly  Q: quit viewer  123456: UltraVNC scale 1/n
+
+Arrow keys: pan the viewport about 10% for each keypress.
+
+PageUp/PageDown: pan the viewport by a screenful vertically.
+
+Home/End: pan the viewport by a screenful horizontally.
+
+KeyPad Arrows: pan the viewport by 1 pixel for each keypress.
+
+Dragging the Mouse with Button1 pressed also pans the viewport.
+
+Clicking Mouse Button3 brings up the Popup Menu.
+
+The above mappings are \fBalways\fR active in ViewOnly mode, unless you set
+the Escape Keys value to 'never'.
+
+x11vnc -appshare hot-keys:  x11vnc has a simple application sharing mode
+that enables the viewer-side to move, resize, or raise the remote toplevel
+windows.  To enable it, hold down Shift + the Escape Keys and press these:
+
+Arrow keys: move the remote window around in its desktop.
+
+PageUp/PageDn/Home/End:  resize the remote window.
+
++/-: raise or lower the remote window.
+
+M or Button1 move win to local position;  D or Button3: delete remote win.
+
+If the Escape Keys value below is set to 'default' then a default list of
+of modifier keys is used.  For Unix it is: Alt_L,Super_L and for MacOSX it
+is Control_L,Meta_L.  Note: the Super_L key usually has a Windows(TM) Flag
+on it.  Also note the _L and _R mean the key is on the LEFT or RIGHT side
+of the keyboard.
+
+On Unix   the default is Alt and Windows keys on Left side of keyboard.
+On MacOSX the default is Control and Command keys on Left side of keyboard.
+
+Example: Press and hold the Alt and Windows keys on the LEFT side of the
+keyboard and then press 'c' to toggle the full-color state.  Or press 't'
+to toggle the ultravnc Text Chat window, etc.
+
+To use something besides the default, supply a comma separated list (or a
+single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L
+Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.
+.TP
+\fB New Popup actions:\fR
+
+ ViewOnly:                ~ -viewonly
+ Disable Bell:            ~ -nobell
+ Cursor Shape:            ~ -nocursorshape
+ X11 Cursor:              ~ -x11cursor
+ Cursor Alphablend:       ~ -alpha
+ Toggle Tight/Hextile:    ~ -encodings hextile...
+ Toggle Tight/ZRLE:       ~ -encodings zrle...
+ Toggle ZRLE/ZYWRLE:      ~ -encodings zywrle...
+ Quality Level            ~ -quality (both Tight and ZYWRLE)
+ Compress Level           ~ -compresslevel
+ Disable JPEG:            ~ -nojpeg  (Tight)
+ Pipeline Updates         ~ -pipeline
+
+ Full Color                 as many colors as local screen allows.
+ Grey scale (16 & 8-bpp)  ~ -grey, for low colors 16/8bpp modes only.
+ 16 bit color (BGR565)    ~ -16bpp / -bgr565
+ 8  bit color (BGR233)    ~ -bgr233
+ 256 colors               ~ -bgr233 default # of colors.
+  64 colors               ~ -bgr222 / -use64
+   8 colors               ~ -bgr111 / -use8
+ Scale Viewer             ~ -scale
+ Escape Keys: Toggle      ~ -escape
+ Escape Keys: Help+Set    ~ -escape
+ Set Y Crop (y-max)       ~ -ycrop
+ Set Scrollbar Width      ~ -sbwidth
+ XGrabServer              ~ -graball
+
+ UltraVNC Extensions:
+
+   Set 1/n Server Scale     Ultravnc ext. Scale desktop by 1/n.
+   Text Chat                Ultravnc ext. Do Text Chat.
+   File Transfer            Ultravnc ext. File xfer via Java helper.
+   Single Window            Ultravnc ext. Grab and view a single window.
+                            (select then click on the window you want).
+   Disable Remote Input     Ultravnc ext. Try to prevent input and
+                            viewing of monitor at physical display.
+
+ Note: the Ultravnc extensions only apply to servers that support
+       them.  x11vnc/libvncserver supports some of them.
+
+ Send Clipboard not Primary  ~ -sendclipboard
+ Send Selection Every time   ~ -sendalways
+
+.SH ENCODINGS
+The server supplies information in whatever format is desired by the
+client, in order to make the client as easy as possible to implement. 
+If the client represents itself as able to use multiple formats, the
+server will choose one.
+
+.I Pixel format
+refers to the representation of an individual pixel. The most common
+formats are 24 and 16 bit "true\-color" values, and 8\-bit "color map"
+representations, where an arbitrary map converts the color number to
+RGB values.
+
+.I Encoding
+refers to how a rectangle of pixels are sent (all pixel information in
+VNC is sent as rectangles). All rectangles come with a header giving
+the location and size of the rectangle and an encoding type used by
+the data which follows. These types are listed below.
+.TP
+.B Raw
+The raw encoding simply sends width*height pixel values. All clients
+are required to support this encoding type. Raw is also the fastest
+when the server and viewer are on the same machine, as the connection
+speed is essentially infinite and raw encoding minimizes processing
+time.
+.TP
+.B CopyRect
+The Copy Rectangle encoding is efficient when something is being
+moved; the only data sent is the location of a rectangle from which
+data should be copied to the current location. Copyrect could also be
+used to efficiently transmit a repeated pattern.
+.TP
+.B RRE
+The Rise\-and\-Run\-length\-Encoding is basically a 2D version of
+run\-length encoding (RLE). In this encoding, a sequence of identical
+pixels are compressed to a single value and repeat count. In VNC, this
+is implemented with a background color, and then specifications of an
+arbitrary number of subrectangles and color for each. This is an
+efficient encoding for large blocks of constant color.
+.TP
+.B CoRRE
+This is a minor variation on RRE, using a maximum of 255x255 pixel
+rectangles. This allows for single\-byte values to be used, reducing
+packet size. This is in general more efficient, because the savings
+from sending 1\-byte values generally outweighs the losses from the
+(relatively rare) cases where very large regions are painted the same
+color.
+.TP
+.B Hextile
+Here, rectangles are split up in to 16x16 tiles, which are sent in a
+predetermined order. The data within the tiles is sent either raw or
+as a variant on RRE. Hextile encoding is usually the best choice for
+using in high\-speed network environments (e.g. Ethernet local\-area
+networks).
+.TP
+.B Zlib
+Zlib is a very simple encoding that uses zlib library to compress raw
+pixel data. This encoding achieves good compression, but consumes a
+lot of CPU time. Support for this encoding is provided for
+compatibility with VNC servers that might not understand Tight
+encoding which is more efficient than Zlib in nearly all real\-life
+situations.
+.TP
+.B Tight
+Like Zlib encoding, Tight encoding uses zlib library to compress the
+pixel data, but it pre\-processes data to maximize compression ratios,
+and to minimize CPU usage on compression. Also, JPEG compression may
+be used to encode color\-rich screen areas (see the description of
+\-quality and \-nojpeg options above). Tight encoding is usually the
+best choice for low\-bandwidth network environments (e.g. slow modem
+connections).
+.TP
+.B ZRLE
+The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding
+to the unix tightvnc viewer.
+.TP
+.B ZYWRLE
+The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE
+encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ 
+to the unix tightvnc viewer.
+.SH RESOURCES
+X resources that \fBvncviewer\fR knows about, aside from the
+normal Xt resources, are as follows:
+.TP
+.B shareDesktop
+Equivalent of \fB\-shared\fR/\fB\-noshared\fR options. Default true.
+.TP
+.B viewOnly
+Equivalent of \fB\-viewonly\fR option. Default false.
+.TP
+.B fullScreen
+Equivalent of \fB\-fullscreen\fR option. Default false.
+.TP
+.B grabKeyboard
+Grab keyboard in full-screen mode. This can help to solve problems
+with losing keyboard focus. Default false.
+.TP
+.B raiseOnBeep
+Equivalent of \fB\-noraiseonbeep\fR option, when set to false. Default
+true.
+.TP
+.B passwordFile
+Equivalent of \fB\-passwd\fR option.
+.TP
+.B userLogin
+Equivalent of \fB\-user\fR option.
+.TP
+.B passwordDialog
+Whether to use a dialog box to get the password (true) or get it from
+the tty (false). Irrelevant if \fBpasswordFile\fR is set. Default
+false.
+.TP
+.B encodings
+Equivalent of \fB\-encodings\fR option.
+.TP
+.B compressLevel
+Equivalent of \fB\-compresslevel\fR option (TightVNC\-specific).
+.TP
+.B qualityLevel
+Equivalent of \fB\-quality\fR option (TightVNC\-specific).
+.TP
+.B enableJPEG
+Equivalent of \fB\-nojpeg\fR option, when set to false. Default true.
+.TP
+.B useRemoteCursor
+Equivalent of \fB\-nocursorshape\fR option, when set to false
+(TightVNC\-specific). Default true.
+.TP
+.B useBGR233
+Equivalent of \fB\-bgr233\fR option. Default false.
+.TP
+.B nColours
+When using BGR233, try to allocate this many "exact" colors from the
+BGR233 color cube. When using a shared colormap, setting this resource
+lower leaves more colors for other X clients. Irrelevant when using
+truecolor. Default is 256 (i.e. all of them).
+.TP
+.B useSharedColours
+If the number of "exact" BGR233 colors successfully allocated is less
+than 256 then the rest are filled in using the "nearest" colors
+available. This resource says whether to only use the "exact" BGR233
+colors for this purpose, or whether to use other clients' "shared"
+colors as well. Default true (i.e. use other clients' colors).
+.TP
+.B forceOwnCmap
+Equivalent of \fB\-owncmap\fR option. Default false.
+.TP
+.B forceTrueColour
+Equivalent of \fB\-truecolour\fR option. Default false.
+.TP
+.B requestedDepth
+Equivalent of \fB\-depth\fR option.
+.TP
+.B useSharedMemory
+Use MIT shared memory extension if on the same machine as the X
+server. Default true.
+.TP
+.B wmDecorationWidth, wmDecorationHeight
+The total width and height taken up by window manager decorations.
+This is used to calculate the maximum size of the VNC viewer window. 
+Default is width 4, height 24.
+.TP
+.B bumpScrollTime, bumpScrollPixels
+When in full screen mode and the VNC desktop is bigger than the X
+display, scrolling happens whenever the mouse hits the edge of the
+screen. The maximum speed of scrolling is bumpScrollPixels pixels
+every bumpScrollTime milliseconds. The actual speed of scrolling will
+be slower than this, of course, depending on how fast your machine is. 
+Default 20 pixels every 25 milliseconds.
+.TP
+.B popupButtonCount
+The number of buttons in the popup window. See the README file for
+more information on how to customize the buttons.
+.TP
+.B debug
+For debugging. Default false.
+.TP
+.B rawDelay, copyRectDelay
+For debugging, see the README file for details. Default 0 (off).
+.SH ENVIRONMENT
+When started with the \fB\-via\fR option, vncviewer reads the
+\fBVNC_VIA_CMD\fR environment variable, expands patterns beginning
+with the "%" character, and executes result as a command assuming that
+it would create TCP tunnel that should be used for VNC connection. If
+not set, this environment variable defaults to "/usr/bin/ssh -f -L
+%L:%H:%R %G sleep 20".
+
+The following patterns are recognized in the \fBVNC_VIA_CMD\fR (note
+that all the patterns %G, %H, %L and %R must be present in the command
+template):
+.TP
+.B %%
+A literal "%";
+.TP
+.B %G
+gateway host name;
+.TP
+.B %H
+remote VNC host name, as known to the gateway;
+.TP
+.B %L
+local TCP port number;
+.TP
+.B %R
+remote TCP port number.
+.SH SEE ALSO
+\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1),
+\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html
+.SH AUTHORS
+Original VNC was developed in AT&T Laboratories Cambridge. TightVNC
+additions was implemented by Constantin Kaplinsky. Many other people
+participated in development, testing and support.  Karl J. Runge 
+added all of the SSVNC related features and improvements.
+
+\fBMan page authors:\fR
+.br
+Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>,
+.br
+Terran Melconian <terran@consistent.org>,
+.br
+Tim Waugh <twaugh@redhat.com>,
+.br
+Constantin Kaplinsky <const@ce.cctpu.edu.ru>
+.br
+Karl J. Runge <runge@karlrunge.com>
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncviewer/vncviewer.c
--- vnc_unixsrc.orig/vncviewer/vncviewer.c	2004-01-13 09:22:05.000000000 -0500
+++ vnc_unixsrc/vncviewer/vncviewer.c	2010-04-18 12:43:47.000000000 -0400
@@ -22,6 +22,8 @@
  */
 
 #include "vncviewer.h"
+#include <ctype.h>
+#include <X11/Xaw/Toggle.h>
 
 char *programName;
 XtAppContext appContext;
@@ -29,11 +31,274 @@
 
 Widget toplevel;
 
+extern void raiseme(int force);
+extern void CreateChat(void);
+
+void set_sbwidth(int sbw) {
+	char *q, *p, t[5];
+	int i, k, N = 4;
+	int db = 0;
+
+	if (sbw < 1) {
+		sbw = 2;
+	} else if (sbw > 100) {
+		sbw = 100;
+	}
+	if (db) fprintf(stderr, "sbw: %d\n", sbw);
+
+	sprintf(t, "%4d", sbw);
+	k = 0;
+	while (fallback_resources[k] != NULL) {
+		q = strstr(fallback_resources[k], "horizontal.height: ");
+		if (!q) {
+			q = strstr(fallback_resources[k], "vertical.width: ");
+		}
+		if (q) {
+			p = strdup(fallback_resources[k]);
+			q = strstr(p, ":   ");
+			if (q) {
+				q++;
+				q++;
+				for (i=0; i < N; i++) {
+					*(q+i) = t[i];
+				}
+				fallback_resources[k] = p;
+				if (db) fprintf(stderr, "res: %s\n\n", p);
+			}
+		}
+		k++;
+	}
+}
+
+void min_title(void) {
+	char *q;
+	int k;
+
+	k = 0;
+	while (fallback_resources[k] != NULL) {
+		q = strstr(fallback_resources[k], "Ssvnc.title: ");
+		if (q) {
+			fallback_resources[k] = strdup("Ssvnc.title: %s");
+		}
+		k++;
+	}
+}
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+void unixpw(char *instr, int vencrypt_plain) {
+	char *str, *q, *infile = NULL;
+	FILE *in;
+	int i, rmfile = 0;
+	struct stat sb;
+	int N = 99;
+	char username[100], passwd[100];
+	static int did = 0;
+
+	if (did) {
+		return;
+	}
+	did = 1;
+
+	for (i=0; i<100; i++) {
+		username[i] = '\0';
+		passwd[i] = '\0';
+	}
+
+	if (instr == NULL) {
+		return;
+	} else if (!strcmp(instr, "")) {
+		return;
+	}
+
+	str = strdup(instr);
+	
+	if (strstr(str, "rm:") == str) {
+		rmfile = 1;
+		infile = str + strlen("rm:");
+	} else if (stat(str, &sb) == 0) {
+		infile = str;
+	}
+	if (!strcmp(str, ".")) {
+		char *p;
+		if (!use_tty()) {
+			char *u;
+			fprintf(stderr, "\nEnter Unix Username and Password in the popups.\n");
+			u = DoUserDialog();
+			if (strlen(u) >= 100) {
+				exit(1);
+			}
+			sprintf(username, u);
+			p = DoPasswordDialog();
+		} else {
+			raiseme(1);
+			fprintf(stderr, "\nUnix Username: ");
+			if (fgets(username, N, stdin) == NULL) {
+				exit(1);
+			}
+			p = getpass("Unix Password: ");
+		}
+		if (! p) {
+			exit(1);
+		}
+		strncpy(passwd, p, N);
+		fprintf(stderr, "\n");
+		
+	} else if (!strcmp(str, "-")) {
+		char *p, *q;
+		if (!use_tty()) {
+			fprintf(stderr, "\nEnter unixuser@unixpasswd in the popup.\n");
+			p = DoPasswordDialog();
+		} else {
+			raiseme(1);
+			p = getpass("unixuser@unixpasswd: ");
+		}
+		if (! p) {
+			exit(1);
+		}
+		q = strchr(p, '@');
+		if (! q) {
+			exit(1);
+		}
+		*q = '\0';
+		strncpy(username, p, N);
+		strncpy(passwd, q+1, N);
+		
+	} else if (infile) {
+		in = fopen(infile, "r");	
+		if (in == NULL) {
+			fprintf(stderr, "failed to open -unixpw file.\n");
+			exit(1);
+		}
+		if (fgets(username, N, in) == NULL) {
+			exit(1);
+		}
+		if (fgets(passwd, N, in) == NULL) {
+			exit(1);
+		}
+		fclose(in);
+		fprintf(stderr, "read username@passwd from file: %s\n", infile);
+		if (rmfile) {
+			fprintf(stderr, "deleting username@passwd file:  %s\n", infile);
+			unlink(infile);
+		}
+	} else if (strchr(str, '@'))  {
+		char *q = strchr(str, '@');
+		*q = '\0';
+		strncpy(username, str, N);
+		strncpy(passwd, q+1, N);
+	} else {
+		exit(1);
+	}
+
+	free(str);
+	
+	if (vencrypt_plain) {
+		CARD32 ulen, plen;
+		char *q;
+
+		q = strrchr(username, '\n');
+		if (q) *q = '\0';
+		q = strrchr(passwd, '\n');
+		if (q) *q = '\0';
+
+		ulen = Swap32IfLE((CARD32)strlen(username));
+		plen = Swap32IfLE((CARD32)strlen(passwd));
+
+		if (!WriteExact(rfbsock, (char *)&ulen, 4) ||
+		    !WriteExact(rfbsock, (char *)&plen, 4)) {
+			return;
+		}
+
+		if (!WriteExact(rfbsock, username, strlen(username)) ||
+		    !WriteExact(rfbsock, passwd, strlen(passwd))) {
+			return;
+		}
+		return;
+	}
+
+
+	if (! getenv("SSVNC_UNIXPW_NOESC")) {
+		SendKeyEvent(XK_Escape, 1);
+		SendKeyEvent(XK_Escape, 0);
+	}
+
+	q = username;
+	while (*q != '\0' && *q != '\n') {
+		char c = *q;
+		if (c >= 0x20 && c <= 0x07e) {
+			KeySym ks = (KeySym) c;
+			SendKeyEvent(ks, 1);
+			SendKeyEvent(ks, 0);
+		}
+		q++;
+	}
+
+	SendKeyEvent(XK_Return, 1);
+	SendKeyEvent(XK_Return, 0);
+	
+	q = passwd;
+	while (*q != '\0' && *q != '\n') {
+		char c = *q;
+		if (c >= 0x20 && c <= 0x07e) {
+			KeySym ks = (KeySym) c;
+			SendKeyEvent(ks, 1);
+			SendKeyEvent(ks, 0);
+		}
+		q++;
+	}
+
+	SendKeyEvent(XK_Return, 1);
+	SendKeyEvent(XK_Return, 0);
+}
+
+static void chat_window_only(void) {
+	if (appData.chatOnly) {
+		static double last_time = 0.0;
+		if (dnow() > last_time + 1.5) {
+			XSync(dpy, False);
+			XUnmapWindow(dpy, XtWindow(toplevel));
+		}
+	}
+}
+
+int saw_appshare = 0;
+
 int
 main(int argc, char **argv)
 {
-  int i;
-  programName = argv[0];
+	int i, save_sbw, saw_listen = 0;
+	char *pw_loc = NULL;
+	programName = argv[0];
+
+	if (strrchr(programName, '/') != NULL) {
+		programName = strrchr(programName, '/') + 1;
+	}
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-env")) {
+			if (i+1 < argc) {
+				char *estr = argv[i+1];
+				if (strchr(estr, '=')) {
+					putenv(estr);
+				}
+			}
+		}
+		if (!strcmp(argv[i], "-noipv4")) {
+			putenv("VNCVIEWER_NO_IPV4=1");
+		}
+		if (!strcmp(argv[i], "-noipv6")) {
+			putenv("VNCVIEWER_NO_IPV6=1");
+		}
+	}
+	if (getenv("VNCVIEWER_NO_IPV4")) {
+		appData.noipv4 = True;
+	}
+	if (getenv("VNCVIEWER_NO_IPV6")) {
+		appData.noipv6 = True;
+	}
 
   /* The -listen option is used to make us a daemon process which listens for
      incoming connections from servers, rather than actively connecting to a
@@ -45,89 +310,1744 @@
      listenForIncomingConnections() returns, setting the listenSpecified
      flag. */
 
-  for (i = 1; i < argc; i++) {
-    if (strcmp(argv[i], "-listen") == 0) {
-      listenForIncomingConnections(&argc, argv, i);
-      break;
-    }
-    if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) {
-      if (!createTunnel(&argc, argv, i))
-	exit(1);
-      break;
-    }
-  }
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-appshare")) {
+			putenv("SSVNC_MULTIPLE_LISTEN=1");
+			fprintf(stderr, "Enabling -multilisten mode for 'x11vnc -appshare' usage.\n\n");
+			saw_appshare = 1;
+		}
+		if (!strcmp(argv[i], "-multilisten")) {
+			putenv("SSVNC_MULTIPLE_LISTEN=1");
+			saw_listen = 2;
+		}
+		if (!strcmp(argv[i], "-listen")) {
+			saw_listen = 1;
+		}
+		if (!strcmp(argv[i], "-acceptpopup")) {
+			putenv("SSVNC_ACCEPT_POPUP=1");
+		}
+		if (!strcmp(argv[i], "-acceptpopupsc")) {
+			putenv("SSVNC_ACCEPT_POPUP_SC=1");
+		}
+		if (strstr(argv[i], " pw=") != NULL) {
+			pw_loc = strstr(argv[i], " pw=") + 1;
+		}
+	}
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-appshare") && !saw_listen) {
+			listenForIncomingConnections(&argc, argv, i);
+			break;
+		}
+		if (!strcmp(argv[i], "-multilisten")) {
+			listenForIncomingConnections(&argc, argv, i);
+			break;
+		}
+		if (!strcmp(argv[i], "-listen")) {
+			listenForIncomingConnections(&argc, argv, i);
+			break;
+		}
+		if (!strcmp(argv[i], "-tunnel") || !strcmp(argv[i], "-via")) {
+			if (!createTunnel(&argc, argv, i)) {
+				exit(1);
+			}
+			break;
+		}
+		if (!strcmp(argv[i], "-printres") || !strcmp(argv[i], "-res")) {
+			int j = 0;
+			fprintf(stdout, "\n! Ssvnc fallback X resources:\n\n");
+			while (1) {
+				char *p = fallback_resources[j++];
+				int k = 0;
+				if (p == NULL) break;
+				while (*p != '\0') {
+					fprintf(stdout, "%c", *p);
+					if (k > 0 && *p == 'n' && *(p-1) == '\\') {
+						fprintf(stdout, "\\\n");
+					}
+					p++; k++;
+				}
+				fprintf(stdout, "\n\n");
+			}
+			exit(0);	
+		}
+	}
+
+
+	if (argc > 1 && strstr(argv[1], "-h") == argv[1]) {
+		usage();
+		return 0;
+	}
 
   /* Call the main Xt initialisation function.  It parses command-line options,
      generating appropriate resource specs, and makes a connection to the X
      display. */
 
-  toplevel = XtVaAppInitialize(&appContext, "Vncviewer",
-			       cmdLineOptions, numCmdLineOptions,
-			       &argc, argv, fallback_resources,
-			       XtNborderWidth, 0, NULL);
+	if (saw_appshare || getenv("VNCVIEWER_MIN_TITLE")) {
+		min_title();
+	}
+	appData.sbWidth = 0;
+	if (getenv("VNCVIEWER_SBWIDTH")) {
+		int sbw = atoi(getenv("VNCVIEWER_SBWIDTH"));
+		if (sbw > 0) {
+			appData.sbWidth = sbw;
+		}
+	}
+	if (appData.sbWidth == 0) {
+		int i, sbw = 0;
+		for (i = 1; i < argc - 1; i++) {
+			if (!strcmp(argv[i], "-sbwidth")) {
+				sbw = atoi(argv[i+1]);
+			}
+		}
+		if (sbw > 0) {
+			appData.sbWidth = sbw;
+		}
+	}
+	save_sbw = appData.sbWidth;
+	if (save_sbw > 0) {
+		set_sbwidth(save_sbw);
+	} else {
+		set_sbwidth(6);
+	}
+
+	toplevel = XtVaAppInitialize(&appContext, "Ssvnc", cmdLineOptions,
+	    numCmdLineOptions, &argc, argv, fallback_resources,
+	    XtNborderWidth, 0, NULL);
 
-  dpy = XtDisplay(toplevel);
+	dpy = XtDisplay(toplevel);
 
   /* Interpret resource specs and process any remaining command-line arguments
      (i.e. the VNC server name).  If the server name isn't specified on the
      command line, getArgsAndResources() will pop up a dialog box and wait
      for one to be entered. */
 
-  GetArgsAndResources(argc, argv);
+	GetArgsAndResources(argc, argv);
+
+	if (saw_appshare) {
+		appData.appShare = True;
+	}
+
+	if (save_sbw) {
+		appData.sbWidth = save_sbw;
+	}
+
+	if (appData.chatOnly) {
+		appData.encodingsString = "raw hextile";
+	}
+
+	if (pw_loc != NULL) {
+		char *q = pw_loc;
+		while (*q != '\0' && !isspace(*q)) {
+			*q = ' ';
+			q++;
+		}
+	}
 
   /* Unless we accepted an incoming connection, make a TCP connection to the
      given VNC server */
 
-  if (!listenSpecified) {
-    if (!ConnectToRFBServer(vncServerHost, vncServerPort)) exit(1);
-  }
+	if (appData.repeaterUltra == NULL) {
+		if (getenv("SSVNC_REPEATER") != NULL) {
+			appData.repeaterUltra = strdup(getenv("SSVNC_REPEATER"));
+		}
+	}
+
+	if (!listenSpecified) {
+		if (!ConnectToRFBServer(vncServerHost, vncServerPort)) {
+			exit(1);
+		}
+		if (appData.repeaterUltra != NULL) {
+			char tmp[256];
+			if (strstr(appData.repeaterUltra, "SCIII=") == appData.repeaterUltra) {
+				appData.repeaterUltra = strdup(appData.repeaterUltra + strlen("SCIII="));
+				fprintf(stderr, "sending 'testB' to ultravnc SC III SSL repeater...\n");
+				WriteExact(rfbsock, "testB" , 5); 
+			}
+			if (ReadFromRFBServer(tmp, 12)) {
+				tmp[12] = '\0';
+				fprintf(stderr, "repeater 1st proto line: '%s'\n", tmp);
+				if (strstr(tmp, "RFB 000.000") == tmp) {
+					int i;
+					for (i=0; i<256; i++) {
+						tmp[i] = '\0';
+					}
+					for (i=0; i<250; i++) {
+						if (i >= (int) strlen(appData.repeaterUltra)) {
+							break;
+						}
+						tmp[i] = appData.repeaterUltra[i];
+					}
+					fprintf(stderr, "sending '%s' to repeater...\n", tmp);
+					WriteExact(rfbsock, tmp, 250); 
+				}
+			} else {
+				fprintf(stderr, "repeater NO proto line!\n");
+			}
+		}
+	}
 
   /* Initialise the VNC connection, including reading the password */
 
-  if (!InitialiseRFBConnection()) exit(1);
+	if (!InitialiseRFBConnection()) {
+		Cleanup();
+		exit(1);
+	}
+	if (appData.unixPW != NULL) {
+		unixpw(appData.unixPW, 0);
+	} else if (getenv("SSVNC_UNIXPW")) {
+		unixpw(getenv("SSVNC_UNIXPW"), 0);
+	}
 
   /* Create the "popup" widget - this won't actually appear on the screen until
      some user-defined event causes the "ShowPopup" action to be invoked */
 
-  CreatePopup();
+	CreatePopup();
+	CreateScaleN();
+	CreateTurboVNC();
+	CreateQuality();
+	CreateCompress();
+	CreateChat();
 
   /* Find the best pixel format and X visual/colormap to use */
 
-  SetVisualAndCmap();
+	SetVisualAndCmap();
 
   /* Create the "desktop" widget, and perform initialisation which needs doing
      before the widgets are realized */
 
-  ToplevelInitBeforeRealization();
+	ToplevelInitBeforeRealization();
 
-  DesktopInitBeforeRealization();
+	DesktopInitBeforeRealization();
 
   /* "Realize" all the widgets, i.e. actually create and map their X windows */
 
-  XtRealizeWidget(toplevel);
+	XtRealizeWidget(toplevel);
 
   /* Perform initialisation that needs doing after realization, now that the X
      windows exist */
 
-  InitialiseSelection();
+	InitialiseSelection();
 
-  ToplevelInitAfterRealization();
+	ToplevelInitAfterRealization();
 
-  DesktopInitAfterRealization();
+	DesktopInitAfterRealization();
 
   /* Tell the VNC server which pixel format and encodings we want to use */
 
-  SetFormatAndEncodings();
+	SetFormatAndEncodings();
+
+	if (appData.chatOnly) {
+		chat_window_only();
+		ToggleTextChat(0, NULL, NULL, NULL);
+	}
 
   /* Now enter the main loop, processing VNC messages.  X events will
      automatically be processed whenever the VNC connection is idle. */
 
-  while (1) {
-    if (!HandleRFBServerMessage())
-      break;
-  }
+	while (1) {
+		if (!HandleRFBServerMessage()) {
+			break;
+		}
+		if (appData.chatOnly) {
+			chat_window_only();
+		}
+	}
+
+	Cleanup();
+
+	return 0;
+}
+
+/*
+ * Toggle8bpp
+ */
+
+static int last_ncolors = 0;
+static int save_useBGR233 = 0;
+static Bool save_useBGR565 = False;
+
+static Widget b8    = NULL;
+static Widget b16   = NULL;
+static Widget bfull = NULL;
+
+int do_format_change = 0;
+int do_cursor_change = 0;
+double do_fb_update = 0.0;
+static void schedule_format_change(void) {
+	do_format_change = 1;
+	do_cursor_change = 0;
+}
+extern double dnow(void);
+static void schedule_fb_update(void) {
+	do_fb_update = dnow();
+}
+static void init_format_change(void) {
+	appDataNew.useBGR233       = appData.useBGR233;
+	appDataNew.useBGR565       = appData.useBGR565;
+	appDataNew.useGreyScale    = appData.useGreyScale;
+	appDataNew.enableJPEG      = appData.enableJPEG;
+	appDataNew.encodingsString = appData.encodingsString;
+	appDataNew.useRemoteCursor = appData.useRemoteCursor;
+	appDataNew.useX11Cursor    = appData.useX11Cursor;
+	appDataNew.useRawLocal     = appData.useRawLocal;
+	appDataNew.qualityLevel    = appData.qualityLevel;
+	appDataNew.compressLevel   = appData.compressLevel;
+}
+void cutover_format_change(void) {
+	appData.useBGR233       = appDataNew.useBGR233;
+	appData.useBGR565       = appDataNew.useBGR565;
+	appData.useGreyScale    = appDataNew.useGreyScale;
+	appData.enableJPEG      = appDataNew.enableJPEG;
+	appData.encodingsString = appDataNew.encodingsString;
+	appData.useRemoteCursor = appDataNew.useRemoteCursor;
+	appData.useX11Cursor    = appDataNew.useX11Cursor;
+	appData.useRawLocal     = appDataNew.useRawLocal;
+	appData.qualityLevel    = appDataNew.qualityLevel;
+	appData.compressLevel   = appDataNew.compressLevel;
+}
+
+void
+Toggle8bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	fprintf(stderr, "Toggle8bpp: %d\n", appData.useBGR233);
+	b8 = w;
+	init_format_change();
+	if (appData.useBGR233) {
+		last_ncolors = appData.useBGR233;
+		appDataNew.useBGR233 = 0;
+		appDataNew.useBGR565 = save_useBGR565;
+		fprintf(stderr, "8bpp: off\n");
+	} else {
+		if (!last_ncolors) last_ncolors = 256;
+		appDataNew.useBGR233 = last_ncolors;
+		save_useBGR565 = appData.useBGR565;
+		appDataNew.useBGR565 = False;
+		fprintf(stderr, "8bpp: on (%d colors)\n", appDataNew.useBGR233);
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+
+void
+Toggle16bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	fprintf(stderr, "Toggle16bpp: %d\n", appData.useBGR565);
+	b16 = w;
+	init_format_change();
+	if (appData.useBGR565) {
+		appDataNew.useBGR565 = False;
+		appDataNew.useBGR233 = save_useBGR233;
+		fprintf(stderr, "16bpp: off\n");
+	} else {
+		appDataNew.useBGR565 = True;
+		save_useBGR233 = appData.useBGR233;
+		appDataNew.useBGR233 = 0;
+		fprintf(stderr, "16bpp: on\n");
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleFullColor(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	fprintf(stderr, "ToggleFullColor\n");
+	bfull = w;
+	init_format_change();
+	if (appData.useBGR565 || appData.useBGR233) {
+		save_useBGR565 = appData.useBGR565;
+		appDataNew.useBGR565 = False;
+		save_useBGR233 = appData.useBGR233;
+		appDataNew.useBGR233 = 0;
+		fprintf(stderr, "FullColor: on\n");
+	} else {
+		if (save_useBGR565) {
+			appDataNew.useBGR565 = True;
+			appDataNew.useBGR233 = 0;
+			fprintf(stderr, "FullColor off -> 16bpp.\n");
+		} else {
+			appDataNew.useBGR565 = False;
+			if (!save_useBGR233) save_useBGR233 = 256;
+			appDataNew.useBGR233 = save_useBGR233;
+			fprintf(stderr, "FullColor off -> 8bpp.\n");
+		}
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.grabAll) {
+		appData.grabAll = False;
+	} else {
+		appData.grabAll = True;
+	}
+	fprintf(stderr, "ToggleXGrab, current=%d\n", appData.grabAll);
+	/* always ungrab to be sure, fullscreen will handle the rest */
+	XUngrabServer(dpy);
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.escapeActive) {
+		appData.escapeActive = False;
+	} else {
+		appData.escapeActive = True;
+	}
+	if (w || ev || params || num_params) {}
+}
+
+/*
+ * ToggleNColors
+ */
+
+static Widget w256 = NULL;
+static Widget w64  = NULL;
+static Widget w8   = NULL;
+
+void
+Toggle256Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	w256 = w;
+	if (appData.useBGR233 != 256) {
+		fprintf(stderr, "256 colors: on\n");
+		init_format_change();
+		last_ncolors = appDataNew.useBGR233 = 256;
+		save_useBGR565 = appData.useBGR565;
+		appDataNew.useBGR565 = False;
+		schedule_format_change();
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Toggle64Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	w64 = w;
+	if (appData.useBGR233 != 64) {
+		fprintf(stderr, "64 colors: on\n");
+		init_format_change();
+		last_ncolors = appDataNew.useBGR233 = 64;
+		save_useBGR565 = appData.useBGR565;
+		appDataNew.useBGR565 = False;
+		schedule_format_change();
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Toggle8Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	w8 = w;
+	if (appData.useBGR233 != 8) {
+		fprintf(stderr, "8 colors: on\n");
+		init_format_change();
+		last_ncolors = appDataNew.useBGR233 = 8;
+		save_useBGR565 = appData.useBGR565;
+		appDataNew.useBGR565 = False;
+		schedule_format_change();
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleGreyScale(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	fprintf(stderr, "ToggleGreyScale\n");
+	init_format_change();
+	if (appData.useGreyScale) {
+		appDataNew.useGreyScale = False;
+		fprintf(stderr, "greyscale: off\n");
+	} else {
+		appDataNew.useGreyScale = True;
+		fprintf(stderr, "greyscale: on\n");
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+/*
+ * ToggleJPEG
+ */
+
+void
+ToggleJPEG(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_format_change();
+	if (appData.enableJPEG) {
+		appDataNew.enableJPEG = False;
+		fprintf(stderr, "JPEG: off\n");
+	} else {
+		appDataNew.enableJPEG = True;
+		fprintf(stderr, "JPEG: on\n");
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+/*
+ * ToggleTightZRLE
+ */
+
+static Bool usingZRLE = False;
+static Bool usingZYWRLE = False;
+static Bool usingHextile = False;
+extern int skip_maybe_sync;
+
+void
+ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char prefTight[] = "copyrect tight zrle zywrle zlib hextile corre rre raw";
+	char prefZRLE[]  = "copyrect zrle zywrle tight zlib hextile corre rre raw";
+	init_format_change();
+	usingHextile = False;
+	if (! appData.encodingsString) {
+		appDataNew.encodingsString = strdup(prefZRLE);
+		usingZRLE = True;
+		fprintf(stderr, "prefer: ZRLE\n");
+	} else {
+		char *t, *z;
+		static int first = 1;
+		t = strstr(appData.encodingsString, "tight");
+		z = strstr(appData.encodingsString, "zrle");
+		if (first && usingZRLE) {
+			appDataNew.encodingsString = strdup(prefTight);
+			usingZRLE = False;
+			usingZYWRLE = False;
+		} else if (! t) {
+			appDataNew.encodingsString = strdup(prefZRLE);
+			usingZRLE = True;
+			fprintf(stderr, "prefer: ZRLE\n");
+		} else if (! z) {
+			appDataNew.encodingsString = strdup(prefTight);
+			usingZRLE = False;
+			usingZYWRLE = False;
+			skip_maybe_sync = 0;
+			fprintf(stderr, "prefer: Tight\n");
+		} else {
+			if (t < z) {
+				appDataNew.encodingsString = strdup(prefZRLE);
+				usingZRLE = True;
+				fprintf(stderr, "prefer: ZRLE\n");
+			} else {
+				appDataNew.encodingsString = strdup(prefTight);
+				usingZRLE = False;
+				usingZYWRLE = False;
+				skip_maybe_sync = 0;
+				fprintf(stderr, "prefer: Tight\n");
+			}
+		}
+		first = 0;
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char prefZYWRLE[] = "copyrect zywrle zrle tight zlib hextile corre rre raw";
+	char prefZRLE[]   = "copyrect zrle zywrle tight zlib hextile corre rre raw";
+	init_format_change();
+	usingZRLE = True;
+	usingHextile = False;
+	if (! appData.encodingsString) {
+		appDataNew.encodingsString = strdup(prefZYWRLE);
+		usingZYWRLE = True;
+		fprintf(stderr, "prefer: ZYWRLE\n");
+	} else {
+		char *z, *w;
+		w = strstr(appData.encodingsString, "zywrle");
+		z = strstr(appData.encodingsString, "zrle");
+		if (usingZYWRLE) {
+			appDataNew.encodingsString = strdup(prefZRLE);
+			fprintf(stderr, "prefer: ZRLE\n");
+			usingZYWRLE = False;
+			skip_maybe_sync = 0;
+		} else {
+			appDataNew.encodingsString = strdup(prefZYWRLE);
+			fprintf(stderr, "prefer: ZYWRLE\n");
+			usingZYWRLE = True;
+		}
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char prefTight[]   = "copyrect tight zrle zywrle zlib hextile corre rre raw";
+	char prefHextile[] = "copyrect hextile tight zrle zywrle zlib corre rre raw";
+	init_format_change();
+	usingZRLE = False;
+	usingZYWRLE = False;
+	if (! appData.encodingsString) {
+		appDataNew.encodingsString = strdup(prefHextile);
+		usingHextile = True;
+		fprintf(stderr, "prefer: Hextile\n");
+	} else {
+		char *t, *z;
+		static int first = 1;
+		t = strstr(appData.encodingsString, "tight");
+		z = strstr(appData.encodingsString, "hextile");
+		if (first && usingHextile) {
+			appDataNew.encodingsString = strdup(prefTight);
+			usingHextile = False;
+		} else if (! t) {
+			appDataNew.encodingsString = strdup(prefHextile);
+			usingHextile = True;
+			fprintf(stderr, "prefer: Hextile\n");
+		} else if (! z) {
+			appDataNew.encodingsString = strdup(prefTight);
+			usingHextile = False;
+			skip_maybe_sync = 0;
+			fprintf(stderr, "prefer: Tight\n");
+		} else {
+			if (t < z) {
+				appDataNew.encodingsString = strdup(prefHextile);
+				usingHextile = True;
+				fprintf(stderr, "prefer: Hextile\n");
+			} else {
+				appDataNew.encodingsString = strdup(prefTight);
+				usingHextile = False;
+				skip_maybe_sync = 0;
+				fprintf(stderr, "prefer: Tight\n");
+			}
+		}
+		first = 0;
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void scale_check_zrle(void) {
+	static int didit = 0;
+	if (didit) {
+		return;
+	}
+	didit = 1;
+	if (getenv("SSVNC_PRESERVE_ENCODING")) {
+		return;
+	}
+	if (!usingZRLE && !usingHextile) {
+		Widget w = 0;
+		fprintf(stderr, "\nSwitching to faster ZRLE encoding in client-side scaling mode.\n");
+		fprintf(stderr, "Switch back to Tight via the Popup menu if you prefer it.\n\n");
+		ToggleTightZRLE(w, NULL, NULL, NULL);
+	}
+}
+
+/*
+ * ToggleViewOnly
+ */
+
+void
+ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.viewOnly) {
+		appData.viewOnly = False;
+		fprintf(stderr, "viewonly: off\n");
+	} else {
+		appData.viewOnly = True;
+		fprintf(stderr, "viewonly: on\n");
+	}
+	Xcursors(1);
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleCursorShape(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_format_change();
+	if (appData.useRemoteCursor) {
+		appDataNew.useRemoteCursor = False;
+		fprintf(stderr, "useRemoteCursor: off\n");
+	} else {
+		appDataNew.useRemoteCursor = True;
+		fprintf(stderr, "useRemoteCursor: on\n");
+	}
+	schedule_format_change();
+	if (!appDataNew.useRemoteCursor) {
+		do_cursor_change = 1;
+	} else {
+		do_cursor_change = -1;
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleCursorAlpha(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useCursorAlpha) {
+		appData.useCursorAlpha = False;
+		fprintf(stderr, "useCursorAlpha: off\n");
+	} else {
+		appData.useCursorAlpha = True;
+		fprintf(stderr, "useCursorAlpha: on\n");
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleX11Cursor(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_format_change();
+	if (appData.useX11Cursor) {
+		appDataNew.useX11Cursor = False;
+		fprintf(stderr, "useX11Cursor: off\n");
+	} else {
+		appDataNew.useX11Cursor = True;
+		fprintf(stderr, "useX11Cursor: on\n");
+	}
+	schedule_format_change();
+	do_cursor_change = 1;
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleBell(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBell) {
+		appData.useBell = False;
+		fprintf(stderr, "useBell: off\n");
+	} else {
+		appData.useBell = True;
+		fprintf(stderr, "useBell: on\n");
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleRawLocal(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_format_change();
+	if (appData.useRawLocal) {
+		appDataNew.useRawLocal = False;
+		fprintf(stderr, "useRawLocal: off\n");
+	} else {
+		appDataNew.useRawLocal = True;
+		fprintf(stderr, "useRawLocal: on\n");
+	}
+	schedule_format_change();
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleServerInput(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.serverInput) {
+		appData.serverInput= False;
+		fprintf(stderr, "serverInput: off\n");
+		SendServerInput(True);
+	} else {
+		appData.serverInput = True;
+		fprintf(stderr, "serverInput: on\n");
+		SendServerInput(False);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.pipelineUpdates) {
+		appData.pipelineUpdates= False;
+		fprintf(stderr, "pipeline-update: off\n");
+	} else {
+		appData.pipelineUpdates = True;
+		fprintf(stderr, "pipeline-update: on\n");
+	}
+	/* XXX request one to be sure? */
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.sendClipboard) {
+		appData.sendClipboard= False;
+		fprintf(stderr, "Send CLIPBOARD Selection: off (send PRIMARY instead)\n");
+	} else {
+		appData.sendClipboard = True;
+		fprintf(stderr, "Send CLIPBOARD Selection: on (do not send PRIMARY)\n");
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+ToggleSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.sendAlways) {
+		appData.sendAlways= False;
+		fprintf(stderr, "Send Selection Always: off\n");
+	} else {
+		appData.sendAlways = True;
+		fprintf(stderr, "Send Selection Always: on\n");
+	}
+	if (w || ev || params || num_params) {}
+}
+
+
+Bool _sw1_ = False;	/* XXX this is a weird bug... */
+Bool _sw2_ = False;
+Bool _sw3_ = False;
+Bool selectingSingleWindow = False;
+
+extern Cursor bogoCursor;
+
+void
+ToggleSingleWindow(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.singleWindow) {
+		appData.singleWindow= False;
+		fprintf(stderr, "singleWindow: off\n");
+		SendSingleWindow(-1, -1);
+	} else {
+		appData.singleWindow = True;
+		selectingSingleWindow = True;
+		fprintf(stderr, "singleWindow: on\n");
+		if (bogoCursor != None) {
+			XDefineCursor(dpy, desktopWin, bogoCursor);
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void raiseme(int force);
+void AppendChatInput(char *);
+
+extern void ShowChat(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void ShowFile(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern Bool SendTextChatFinished(void);
+
+
+void printChat(char *str, Bool raise) {
+	if (appData.termChat) {
+		if (raise) {
+			raiseme(0);
+		}
+		fprintf(stderr, str);
+	} else {
+		if (raise) {
+			ShowChat(0, 0, 0, 0);
+		}
+		AppendChatInput(str);
+	}
+}
+
+void
+ToggleTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.chatActive) {
+		printChat("\n*SentClose*\n\n", False);
+		SendTextChatClose();
+		SendTextChatFinished();
+		HideChat(0, NULL, NULL, NULL);
+		appData.chatActive= False;
+	} else {
+		ShowChat(0, 0, 0, 0);
+		SendTextChatOpen();
+		if (appData.termChat) {
+			printChat("\n*SentOpen*\n\nSend: ", True);
+		} else {
+			printChat("\n*SentOpen*\n", True);
+		}
+		appData.chatActive = True;
+	}
+	if (w || ev || params || num_params) {}
+}
+
+extern int filexfer_sock;
+extern pid_t java_helper;
+#define KILLJAVA
+#ifdef KILLJAVA
+#include <signal.h>
+#endif
+
+void
+ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	static double last_start = 0.0;
+	if (appData.fileActive) {
+#if 0
+		HideFile(w, ev, params, num_params);
+		appData.fileActive = False;
+#endif
+#ifndef KILLJAVA
+		if (filexfer_sock >= 0) {
+			close(filexfer_sock);
+		}
+#else
+		if (java_helper != 0) {
+			int i;
+			if (dnow() < last_start + 6.0) {
+				fprintf(stderr, "skipping early kill of java helper (less than 5 secs)\n");
+			} else {
+				for (i=1; i<=5; i++) {
+					pid_t p = java_helper + i;
+					fprintf(stderr, "trying to kill java helper: %d\n", p);
+					if (kill(p, SIGTERM) == 0) {
+						java_helper = 0;
+						break;
+					}
+				}
+			}
+		}
+#endif
+	} else {
+		ShowFile(w, ev, params, num_params);
+		appData.fileActive = True;
+		last_start = dnow();
+	}
+	if (w || ev || params || num_params) {}
+}
+
+static int fooHandler(Display *dpy, XErrorEvent *error) {
+	if (dpy || error) {}
+	return 0;
+}
+
+void raiseme(int force) {
+	if ((force || appData.termChat) && getenv("WINDOWID")) {
+		unsigned long w;
+		if (sscanf(getenv("WINDOWID"), "%lu", &w) == 1)  {
+			;
+		} else if (sscanf(getenv("WINDOWID"), "0x%lx", &w) == 1)  {
+			;
+		} else {
+			w = 0;
+		}
+		if (w != 0) {
+			XErrorHandler old = XSetErrorHandler(fooHandler);
+			XMapRaised(dpy, (Window) w);
+			XSync(dpy, False);
+			XSetErrorHandler(old);
+		}
+	}
+}
+
+void set_server_scale(int n) {
+	if (n >= 1 && n < 100) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		appData.serverScale = n;
+		SendServerScale(n);
+		if (0) SendFramebufferUpdateRequest(0, 0, w, h, False);
+		schedule_fb_update();
+	}
+}
+
+void
+DoServerScale(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char str[100], *s, *q;
+	int n;
+	if (1) {
+		s = DoScaleNDialog();
+	} else {
+		raiseme(1);
+		fprintf(stderr, "\n\n\a\nEnter integer n for 1/n server scaling: ");
+		str[0] = '\0';
+		fgets(str, 100, stdin); 
+		s = str;
+		q = strstr(str, "\n");
+		if (q) *q = '\0';
+	}
+	if (s[0] != '\0') {
+		n = atoi(s);
+		set_server_scale(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void set_server_quality(int n) {
+	fprintf(stderr, "set_quality: %d\n", n);
+	if (n >= 0 && n <= 9) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		init_format_change();
+		appDataNew.qualityLevel = n;
+		SendFramebufferUpdateRequest(0, 0, w, h, False);
+		schedule_format_change();
+	}
+}
+
+void
+DoServerQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char str[100], *s, *q;
+	int n;
+	if (1) {
+		s = DoQualityDialog();
+	} else {
+		raiseme(1);
+		fprintf(stderr, "\n\n\a\nEnter integer 1 <= n <= 9 for quality setting: ");
+		str[0] = '\0';
+		fgets(str, 100, stdin); 
+		s = str;
+		q = strstr(str, "\n");
+		if (q) *q = '\0';
+	}
+	if (s[0] != '\0') {
+		n = atoi(s);
+		set_server_quality(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void set_server_compress(int n) {
+	fprintf(stderr, "set_compress: %d\n", n);
+	if (n >= 0 && n <= 9) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		init_format_change();
+		appDataNew.compressLevel = n;
+		SendFramebufferUpdateRequest(0, 0, w, h, False);
+		schedule_format_change();
+	}
+}
+
+void
+DoServerCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char str[100], *s, *q;
+	int n;
+	if (1) {
+		s = DoCompressDialog();
+	} else {
+		raiseme(1);
+		fprintf(stderr, "\n\n\a\nEnter integer 1 <= n <= 9 for compress level setting: ");
+		str[0] = '\0';
+		fgets(str, 100, stdin); 
+		s = str;
+		q = strstr(str, "\n");
+		if (q) *q = '\0';
+	}
+	if (s[0] != '\0') {
+		n = atoi(s);
+		set_server_compress(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+extern void rescale_image(void);
+extern void get_scale_values(double *fx, double *fy);
+
+void
+SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char *s;
+	s = DoScaleDialog();
+	if (s[0] != '\0') {
+#if 0
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+#endif
+		double fx, fy;
+		int fs = 0;
+		if (appData.scale != NULL && !strcmp(s, appData.scale)) {
+			return;
+		}
+		
+		if (!strcasecmp(s, "none")) {
+			appData.scale = NULL;
+		} else if (!strcmp(s, "1.0")) {
+			appData.scale = NULL;
+		} else if (!strcmp(s, "1")) {
+			appData.scale = NULL;
+		} else {
+			appData.scale = strdup(s);
+		}
+		if (appData.scale != NULL) {
+			get_scale_values(&fx, &fy);
+			if (fx <= 0.0 || fy <= 0.0) {
+				appData.scale = NULL;
+				return;
+			}
+		}
+		
+		if (appData.fullScreen) {
+			fs = 1;
+			FullScreenOff();
+		}
+		rescale_image();
+		if (fs) {
+			FullScreenOn();
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetEscapeKeys(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char *s;
+	s = DoEscapeKeysDialog();
+	fprintf(stderr, "set escape keys: '%s'\n", s);
+	if (s[0] != '\0') {
+		appData.escapeKeys = strdup(s);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void set_ycrop(int n) {
+	if (n >= 1) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+		appData.yCrop = n;
+		ReDoDesktop();
+		SendFramebufferUpdateRequest(0, 0, w, h, False);
+		schedule_fb_update();
+	}
+}
 
-  Cleanup();
+void
+SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char str[100], *q, *s;
+	int n;
+	if (1) {
+		s = DoYCropDialog();
+	} else {
+		raiseme(1);
+		fprintf(stderr, "\n\n\a\nEnter pixel size n -ycrop maximum y-height: ");
+		str[0] = '\0';
+		fgets(str, 100, stdin); 
+		s = str;
+		q = strstr(str, "\n");
+		if (q) *q = '\0';
+	}
+	if (s[0] != '\0') {
+		n = atoi(s);
+		set_ycrop(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void set_scbar(int n) {
+	if (n >= 1) {
+		int w = si.framebufferWidth;
+		int h = si.framebufferHeight;
+fprintf(stderr, "set_scbat: %d\n", n);
+		appData.sbWidth = n;
+		ReDoDesktop();
+		SendFramebufferUpdateRequest(0, 0, w, h, False);
+		schedule_fb_update();
+	}
+}
+
+void
+SetScbar(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	char str[100], *q, *s;
+	int n;
+	if (1) {
+		s = DoScbarDialog();
+	} else {
+		raiseme(1);
+		fprintf(stderr, "\n\n\a\nEnter pixel size n scrollbar width: ");
+		str[0] = '\0';
+		fgets(str, 100, stdin); 
+		s = str;
+		q = strstr(str, "\n");
+		if (q) *q = '\0';
+	}
+	if (s[0] != '\0') {
+		n = atoi(s);
+		set_scbar(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		set_server_scale(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void UpdateQual(void) {
+	SetFormatAndEncodings();
+	UpdateSubsampButtons();
+	UpdateQualSlider();
+}
+
+extern double latency;
+
+static void LosslessRefresh(void) {
+	String encodings = appData.encodingsString;
+	int compressLevel = appData.compressLevel;
+	int qual = appData.qualityLevel;
+	Bool enableJPEG = appData.enableJPEG;
+	appData.qualityLevel = -1;
+	appData.enableJPEG = False;
+	appData.encodingsString = "tight copyrect";
+	appData.compressLevel = 1;
+	SetFormatAndEncodings();
+	SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False);
+	if (latency > 0.0) {
+		if (0) usleep((int) latency * 1000);
+	}
+	appData.qualityLevel = qual;
+	appData.enableJPEG = enableJPEG;
+	appData.encodingsString = encodings;
+	appData.compressLevel = compressLevel;
+	SetFormatAndEncodings();
+}
+
+static void QualHigh(void) {
+	appData.encodingsString = "tight copyrect";
+	if(appData.useBGR233 || appDataNew.useBGR565) {
+		fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n");
+	} else {
+		appData.enableJPEG = True;
+	}
+	appData.subsampLevel = TVNC_1X;
+	appData.qualityLevel = 95;
+	UpdateQual();
+}
+
+static void QualMed(void) {
+	appData.encodingsString = "tight copyrect";
+	if(appData.useBGR233 || appDataNew.useBGR565) {
+		fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n");
+	} else {
+		appData.enableJPEG = True;
+	}
+	appData.subsampLevel = TVNC_2X;
+	appData.qualityLevel = 80;
+	UpdateQual();
+}
+
+static void QualLow(void) {
+	appData.encodingsString = "tight copyrect";
+	if(appData.useBGR233 || appDataNew.useBGR565) {
+		fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n");
+	} else {
+		appData.enableJPEG = True;
+	}
+	appData.subsampLevel = TVNC_4X;
+	appData.qualityLevel = 30;
+	UpdateQual();
+}
+
+static void QualLossless(void) {
+	appData.encodingsString = "tight copyrect";
+	appData.enableJPEG = False;
+	appData.compressLevel = 0;
+	UpdateQual();
+}
 
-  return 0;
+static void QualLosslessWAN(void) {
+	appData.encodingsString = "tight copyrect";
+	appData.enableJPEG = False;
+	appData.compressLevel = 1;
+	UpdateQual();
+}
+
+void
+SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		if (0) fprintf(stderr, "SetTurboVNC: %d\n", n);
+		if (n == 1) {
+			QualHigh();
+		} else if (n == 2) {
+			QualMed();
+		} else if (n == 3) {
+			QualLow();
+		} else if (n == 4) {
+			QualLossless();
+		} else if (n == 5) {
+			QualLosslessWAN();
+		} else if (n == 6) {
+			appData.subsampLevel = TVNC_1X;
+			UpdateQual();
+		} else if (n == 7) {
+			appData.subsampLevel = TVNC_2X;
+			UpdateQual();
+		} else if (n == 8) {
+			appData.subsampLevel = TVNC_4X;
+			UpdateQual();
+		} else if (n == 9) {
+			appData.subsampLevel = TVNC_GRAY;
+			UpdateQual();
+		} else if (n == 10) {
+			LosslessRefresh();
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		set_server_quality(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		set_server_compress(n);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+GotChatText(char *str, int len)
+{
+	static char *b = NULL;
+	static int blen = -1;
+	int i, k;
+	if (appData.termChat) {
+		printChat("\nChat: ", True);
+	} else {
+		printChat("Chat: ", True);
+	}
+
+	if (len < 0) len = 0;
+
+	if (blen < len+1) {
+		if (b) free(b);
+		blen = 2 * (len + 10);
+		b = (char *) malloc(blen);
+	}
+
+	k = 0;
+	for (i=0; i < len; i++) {
+		if (str[i] != '\r') {
+			b[k++] = str[i];
+		}
+	}
+	b[k] = '\0';
+	b[len] = '\0';
+	printChat(b, True);
+	
+	if (appData.termChat) {
+		if (strstr(str, "\n")) {
+			printChat("Send: ", True);
+		} else {
+			printChat("\nSend: ", True);
+		}
+	}
+}
+
+void
+SetViewOnlyState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.viewOnly) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.enableJPEG) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetQualityState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		if (appData.qualityLevel == n) {
+			XtVaSetValues(w, XtNstate, True, NULL);
+		} else {
+			XtVaSetValues(w, XtNstate, False, NULL);
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetCompressState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		if (appData.compressLevel == n) {
+			XtVaSetValues(w, XtNstate, True, NULL);
+		} else {
+			XtVaSetValues(w, XtNstate, False, NULL);
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetScaleNState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (*num_params != 0) {
+		int n = atoi(params[0]);
+		if (appData.serverScale == n || (appData.serverScale >= 6 && n >= 6)) {
+			XtVaSetValues(w, XtNstate, True, NULL);
+		} else {
+			XtVaSetValues(w, XtNstate, False, NULL);
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Set8bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR233) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (b16   != NULL) {
+			XtVaSetValues(b16,   XtNstate, False, NULL);
+		}
+		if (bfull != NULL) {
+			XtVaSetValues(bfull, XtNstate, False, NULL);
+		}
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Set16bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR565) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (b8    != NULL) {
+			XtVaSetValues(b8,    XtNstate, False, NULL);
+		}
+		if (bfull != NULL) {
+			XtVaSetValues(bfull, XtNstate, False, NULL);
+		}
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetFullColorState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR565 || appData.useBGR233) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (b8  != NULL) {
+			XtVaSetValues(b8,  XtNstate, False, NULL);
+		}
+		if (b16 != NULL) {
+			XtVaSetValues(b16, XtNstate, False, NULL);
+		}
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetXGrabState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.grabAll) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetEscapeKeysState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.escapeActive) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Set256ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR233 == 256) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (w64  != NULL) {
+			XtVaSetValues(w64 , XtNstate, False, NULL);
+		}
+		if (w8   != NULL) {
+			XtVaSetValues(w8  , XtNstate, False, NULL);
+		}
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Set64ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR233 == 64) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (w256 != NULL) {
+			XtVaSetValues(w256, XtNstate, False, NULL);
+		}
+		if (w8   != NULL) {
+			XtVaSetValues(w8  , XtNstate, False, NULL);
+		}
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+Set8ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBGR233 == 8) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+		if (w256 != NULL) {
+			XtVaSetValues(w256, XtNstate, False, NULL);
+		}
+		if (w64  != NULL) {
+			XtVaSetValues(w64 , XtNstate, False, NULL);
+		}
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetGreyScaleState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useGreyScale) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+static void init_state(void) {
+	static int first = 1;
+	if (first && appData.encodingsString) {
+		char *t, *z, *y, *h;
+		char *str = appData.encodingsString;
+		int len = strlen(str);
+
+		t = strstr(str, "tight");
+		z = strstr(str, "zrle");
+		y = strstr(str, "zywrle");
+		h = strstr(str, "hextile");
+
+		if (!t) t = str + len;
+		if (!z) z = str + len;
+		if (!y) y = str + len;
+		if (!h) h = str + len;
+
+		usingZRLE = False;
+		usingZYWRLE = False;
+		usingHextile = False;
+
+		if (t < z && t < y && t < h) {
+			;
+		} else if (z < t && z < y && z < h) {
+			usingZRLE = True;
+		} else if (y < t && y < z && y < h) {
+			usingZYWRLE = True;
+			usingZRLE = True;
+		} else if (h < t && h < z && h < y) {
+			usingHextile = True;
+		}
+	}
+	first = 0;
+
+}
+
+void
+SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_state();
+	if (usingZRLE) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_state();
+	if (usingHextile) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	init_state();
+	if (usingZYWRLE) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useRemoteCursor) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useCursorAlpha) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useX11Cursor) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useBell) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.useRawLocal) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (!appData.serverInput) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (!appData.pipelineUpdates) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (!appData.sendClipboard) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (!appData.sendAlways) {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.singleWindow) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.chatActive) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
+}
+
+void
+SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+	if (appData.fileActive) {
+		XtVaSetValues(w, XtNstate, True, NULL);
+	} else {
+		XtVaSetValues(w, XtNstate, False, NULL);
+	}
+	if (w || ev || params || num_params) {}
 }
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncviewer/vncviewer.h
--- vnc_unixsrc.orig/vncviewer/vncviewer.h	2004-03-11 13:14:40.000000000 -0500
+++ vnc_unixsrc/vncviewer/vncviewer.h	2010-04-17 22:29:42.000000000 -0400
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <X11/IntrinsicP.h>
@@ -51,7 +52,13 @@
 			     (((l) & 0x0000ff00) << 8)  | \
 			     (((l) & 0x000000ff) << 24))  : (l))
 
-#define MAX_ENCODINGS 20
+#define Swap32IfBE(l) \
+    (*(char *)&endianTest ? (l) : ((((l) & 0xff000000) >> 24) | \
+			     (((l) & 0x00ff0000) >> 8)  | \
+			     (((l) & 0x0000ff00) << 8)  | \
+			     (((l) & 0x000000ff) << 24)) )
+
+#define MAX_ENCODINGS 24
 
 #define FLASH_PORT_OFFSET 5400
 #define LISTEN_PORT_OFFSET 5500
@@ -64,60 +71,133 @@
 #define DEFAULT_VIA_CMD     \
   (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20")
 
+#define TVNC_SAMPOPT 4
+enum {TVNC_1X=0, TVNC_4X, TVNC_2X, TVNC_GRAY};
 
-/* argsresources.c */
-
-typedef struct {
-  Bool shareDesktop;
-  Bool viewOnly;
-  Bool fullScreen;
-  Bool grabKeyboard;
-  Bool raiseOnBeep;
-
-  String encodingsString;
-
-  Bool useBGR233;
-  int nColours;
-  Bool useSharedColours;
-  Bool forceOwnCmap;
-  Bool forceTrueColour;
-  int requestedDepth;
-
-  Bool useShm;
-
-  int wmDecorationWidth;
-  int wmDecorationHeight;
-
-  char *userLogin;
-
-  char *passwordFile;
-  Bool passwordDialog;
-
-  int rawDelay;
-  int copyRectDelay;
+#if 0
+static const char *subsampLevel2str[TVNC_SAMPOPT] = {
+  "1X", "4X", "2X", "Gray"
+};
+#endif
+#ifdef TURBOVNC
+#define rfbTightNoZlib 0x0A
+#define rfbTurboVncVendor "TRBO"
+#define rfbJpegQualityLevel1       0xFFFFFE01
+#define rfbJpegQualityLevel100     0xFFFFFE64
+#define rfbJpegSubsamp1X           0xFFFFFD00
+#define rfbJpegSubsamp4X           0xFFFFFD01
+#define rfbJpegSubsamp2X           0xFFFFFD02
+#define rfbJpegSubsampGray         0xFFFFFD03
+#endif
+
+/* for debugging width, height, etc */
+#if 0
+#define XtVaSetValues printf("%s:%d\n", __FILE__, __LINE__); XtVaSetValues
+#endif
 
-  Bool debug;
 
-  int popupButtonCount;
+/* argsresources.c */
 
-  int bumpScrollTime;
-  int bumpScrollPixels;
+typedef struct {
+	Bool shareDesktop;
+	Bool viewOnly;
+	Bool fullScreen;
+	Bool grabKeyboard;
+	Bool raiseOnBeep;
+
+	String encodingsString;
+
+	int useBGR233;
+	int nColours;
+	Bool useSharedColours;
+	Bool forceOwnCmap;
+	Bool forceTrueColour;
+	int requestedDepth;
+	Bool useBGR565;
+	Bool useGreyScale;
+
+	Bool grabAll;
+	Bool useXserverBackingStore;
+	Bool overrideRedir;
+	Bool popupFix;
+
+	Bool useShm;
+	Bool termChat;
+
+	int wmDecorationWidth;
+	int wmDecorationHeight;
+
+	char *userLogin;
+	char *unixPW;
+	char *msLogon;
+	char *repeaterUltra;
+	Bool ultraDSM;
+	Bool acceptPopup;
+	char *rfbVersion;
+
+	char *passwordFile;
+	Bool passwordDialog;
+	Bool notty;
+
+	int rawDelay;
+	int copyRectDelay;
+
+	int yCrop;
+	int sbWidth;
+	Bool useCursorAlpha;
+	Bool useRawLocal;
+
+	Bool debug;
+
+	int popupButtonCount;
+	int popupButtonBreak;
+
+	int bumpScrollTime;
+	int bumpScrollPixels;
+
+	int compressLevel;
+	int qualityLevel;
+	Bool enableJPEG;
+	Bool useRemoteCursor;
+	Bool useX11Cursor;
+	Bool useBell;
+	Bool autoPass;
+
+	Bool serverInput;
+	Bool singleWindow;
+	int serverScale;
+	Bool chatActive;
+	Bool chatOnly;
+	Bool fileActive;
+
+	char *scale;
+	char *escapeKeys;
+	Bool appShare;
+	Bool escapeActive;
+	Bool pipelineUpdates;
+
+	Bool sendClipboard;
+	Bool sendAlways;
+	char *recvText;
+
+	/* only for turbovnc mode */
+	String subsampString;
+	int subsampLevel;
+	Bool doubleBuffer;
 
-  int compressLevel;
-  int qualityLevel;
-  Bool enableJPEG;
-  Bool useRemoteCursor;
-  Bool useX11Cursor;
-  Bool autoPass;
+	Bool noipv4;
+	Bool noipv6;
 
 } AppData;
 
 extern AppData appData;
+extern AppData appDataNew;
 
 extern char *fallback_resources[];
 extern char vncServerHost[];
 extern int vncServerPort;
 extern Bool listenSpecified;
+extern pid_t listenParent;
 extern int listenPort, flashPort;
 
 extern XrmOptionDescRec cmdLineOptions[];
@@ -130,10 +210,11 @@
 /* colour.c */
 
 extern unsigned long BGR233ToPixel[];
+extern unsigned long BGR565ToPixel[];
 
 extern Colormap cmap;
 extern Visual *vis;
-extern unsigned int visdepth, visbpp;
+extern unsigned int visdepth, visbpp, isLSB;
 
 extern void SetVisualAndCmap();
 
@@ -155,15 +236,60 @@
 extern GC srcGC, dstGC;
 extern Dimension dpyWidth, dpyHeight;
 
+extern int appshare_0_hint;
+extern int appshare_x_hint;
+extern int appshare_y_hint;
+
 extern void DesktopInitBeforeRealization();
 extern void DesktopInitAfterRealization();
+extern void Xcursors(int set);
 extern void SendRFBEvent(Widget w, XEvent *event, String *params,
 			 Cardinal *num_params);
 extern void CopyDataToScreen(char *buf, int x, int y, int width, int height);
+extern void FillScreen(int x, int y, int width, int height, unsigned long fill);
 extern void SynchroniseScreen();
 
+extern void ReDoDesktop();
+extern void DesktopCursorOff();
+extern void put_image(int x1, int y1, int x2, int y2, int width, int height, int solid);
+extern void copy_rect(int x, int y, int width, int height, int src_x, int src_y);
+
+extern void releaseAllPressedModifiers(void);
+extern void fs_grab(int check);
+extern void fs_ungrab(int check);
+
 /* dialogs.c */
 
+extern int use_tty(void);
+
+extern void ScaleDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoScaleDialog();
+
+extern void EscapeDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoEscapeKeysDialog();
+
+extern void YCropDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoYCropDialog();
+
+extern void ScbarDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoScbarDialog();
+
+extern void ScaleNDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoScaleNDialog();
+
+extern void QualityDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoQualityDialog();
+
+extern void CompressDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoCompressDialog();
+
 extern void ServerDialogDone(Widget w, XEvent *event, String *params,
 			     Cardinal *num_params);
 extern char *DoServerDialog();
@@ -171,6 +297,10 @@
 			     Cardinal *num_params);
 extern char *DoPasswordDialog();
 
+extern void UserDialogDone(Widget w, XEvent *event, String *params,
+			     Cardinal *num_params);
+extern char *DoUserDialog();
+
 /* fullscreen.c */
 
 extern void ToggleFullScreen(Widget w, XEvent *event, String *params,
@@ -181,6 +311,13 @@
 extern void FullScreenOn();
 extern void FullScreenOff();
 
+extern int net_wm_supported(void);
+
+extern void JumpLeft(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void JumpRight(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void JumpUp(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void JumpDown(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
 /* listen.c */
 
 extern void listenForIncomingConnections();
@@ -196,6 +333,8 @@
 		       Cardinal *num_params);
 extern void Quit(Widget w, XEvent *event, String *params,
 		 Cardinal *num_params);
+extern void HideChat(Widget w, XEvent *event, String *params,
+		 Cardinal *num_params);
 extern void Cleanup();
 
 /* popup.c */
@@ -207,6 +346,29 @@
 		      Cardinal *num_params);
 extern void CreatePopup();
 
+extern void HideScaleN(Widget w, XEvent *event, String *params,
+		      Cardinal *num_params);
+extern void CreateScaleN();
+
+extern void HideTurboVNC(Widget w, XEvent *event, String *params,
+		      Cardinal *num_params);
+extern void CreateTurboVNC();
+extern void UpdateSubsampButtons();
+extern void UpdateQualSlider();
+extern void UpdateQual();
+
+extern void HideQuality(Widget w, XEvent *event, String *params,
+		      Cardinal *num_params);
+extern void CreateQuality();
+
+extern void HideCompress(Widget w, XEvent *event, String *params,
+		      Cardinal *num_params);
+extern void CreateCompress();
+
+extern void Noop(Widget w, XEvent *event, String *params,
+		      Cardinal *num_params);
+
+extern int CreateMsg(char *msg, int wait);
 /* rfbproto.c */
 
 extern int rfbsock;
@@ -229,8 +391,19 @@
 extern Bool SendClientCutText(char *str, int len);
 extern Bool HandleRFBServerMessage();
 
+extern Bool SendServerInput(Bool enabled);
+extern Bool SendSingleWindow(int x, int y);
+extern Bool SendServerScale(int n);
+
+extern Bool SendTextChat(char *str);
+extern Bool SendTextChatOpen(void);
+extern Bool SendTextChatClose(void);
+extern Bool SendTextChatFinish(void);
+
 extern void PrintPixelFormat(rfbPixelFormat *format);
 
+extern double dnow(void);
+
 /* selection.c */
 
 extern void InitialiseSelection();
@@ -241,8 +414,10 @@
 
 /* shm.c */
 
-extern XImage *CreateShmImage();
+extern XImage *CreateShmImage(int do_ycrop);
 extern void ShmCleanup();
+extern void ShmDetach();
+extern Bool UsingShm();
 
 /* sockets.c */
 
@@ -252,11 +427,19 @@
 extern Bool WriteExact(int sock, char *buf, int n);
 extern int FindFreeTcpPort(void);
 extern int ListenAtTcpPort(int port);
-extern int ConnectToTcpAddr(unsigned int host, int port);
+extern int ListenAtTcpPort6(int port);
+extern int dotted_ip(char *host, int partial);
+extern int ConnectToTcpAddr(const char *hostname, int port);
+extern int ConnectToUnixSocket(char *file);
 extern int AcceptTcpConnection(int listenSock);
+extern int AcceptTcpConnection6(int listenSock);
 extern Bool SetNonBlocking(int sock);
+extern Bool SetNoDelay(int sock);
+extern Bool SocketPair(int fd[2]);
 
 extern int StringToIPAddr(const char *str, unsigned int *addr);
+extern char *get_peer_ip(int sock);
+extern char *ip2host(char *ip);
 extern Bool SameMachine(int sock);
 
 /* tunnel.c */
@@ -271,3 +454,82 @@
 extern XtAppContext appContext;
 extern Display* dpy;
 extern Widget toplevel;
+
+extern void GotChatText(char *str, int len);
+extern void unixpw(char *instr, int vencrypt_plain);
+
+extern void Toggle8bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Toggle16bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleFullColor(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Toggle256Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Toggle64Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Toggle8Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleGreyScale(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleJPEG(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleCursorShape(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleCursorAlpha(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleX11Cursor(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleBell(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleRawLocal(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleServerInput(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleSingleWindow(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetEscapeKeys(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void DoServerScale(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void DoServerQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void DoServerCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetScbar(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ShowScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ShowTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ShowQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ShowCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void ToggleTermTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+
+extern void scale_check_zrle(void);
+
+extern void SetViewOnlyState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetScaleNState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetQualityState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetCompressState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Set8bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Set16bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetFullColorState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Set256ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Set64ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void Set8ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetGreyScaleState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetTermTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetXGrabState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+extern void SetEscapeKeysState(Widget w, XEvent *ev, String *params, Cardinal *num_params);
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vncviewer/vncviewer.man
--- vnc_unixsrc.orig/vncviewer/vncviewer.man	2004-03-11 13:14:40.000000000 -0500
+++ vnc_unixsrc/vncviewer/vncviewer.man	2010-04-11 23:30:24.000000000 -0400
@@ -5,38 +5,55 @@
 .\" Copyright (C) 1998 Marcus.Brinkmann@ruhr-uni-bochum.de
 .\" Copyright (C) 2000,2001 Red Hat, Inc.
 .\" Copyright (C) 2001-2003 Constantin Kaplinsky <const@ce.cctpu.edu.ru>
+.\" Copyright (C) 2006-2010 Karl J. Runge <runge@karlrunge.com>
 .\"
 .\" You may distribute under the terms of the GNU General Public
 .\" License as specified in the file LICENCE.TXT that comes with the
 .\" TightVNC distribution.
 .\"
-.TH vncviewer 1 "January 2003" "" "TightVNC"
+.TH ssvncviewer 1 "April 2010" "" "SSVNC"
 .SH NAME
-vncviewer \- an X viewer client for VNC
+ssvncviewer \- an X viewer client for VNC
 .SH SYNOPSIS
-.B vncviewer
+.B ssvncviewer
 .RI [\| options \|]
 .RI [\| host \|][\| :display \|]
 .br
-.B vncviewer
+.B ssvncviewer
 .RI [\| options \|]
 .RI [\| host \|][\| ::port \|]
 .br
-.B vncviewer
+.B ssvncviewer
+.RI [\| options \|]
+.RI exec=[\| cmd+args... \|]
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI fd=n
+.br
+.B ssvncviewer
+.RI [\| options \|]
+.RI /path/to/unix/socket
+.br
+.B ssvncviewer
 .RI [\| options \|]
 .IR \-listen
 .RI [\| display \|]
 .br
-.B vncviewer
+.B ssvncviewer
 .IR \-help
 .br
 .SH DESCRIPTION
-.B vncviewer
+.B ssvncviewer
 is an Xt\-based client application for the VNC (Virtual Network
 Computing) system. It can connect to any VNC\-compatible server such
-as \fBXvnc\fR or WinVNC, allowing you to control desktop environment
+as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment
 of a different machine.
 
+ssvncviewer is an enhanced version of the tightvnc unix viewer that can
+take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers.
+See below for the description of these features.
+
 You can use F8 to display a pop\-up utility menu. Press F8 twice to
 pass single F8 to the remote side.
 .SH OPTIONS
@@ -102,13 +119,13 @@
 TightVNC supports several different compression methods to encode
 screen updates; this option specifies a set of them to use in order of
 preference. Encodings are specified separated with spaces, and must
-thus be enclosed in quotes if more than one is specified. Available
-encodings, in default order for a remote connection, are "copyrect
-tight hextile zlib corre rre raw". For a local connection (to the same
-machine), the default order to try is "raw copyrect tight hextile zlib
-corre rre". Raw encoding is always assumed as a last option if no
-other encoding can be used for some reason. For more information on
-encodings, see the section ENCODINGS below.
+thus be enclosed in quotes if more than one is specified.  Commas may be used to avoid spaces.
+Available encodings, in default order for a remote connection, are
+"copyrect tight hextile zlib corre rre raw". For a local connection
+(to the same machine), the default order to try is "raw copyrect tight
+hextile zlib corre rre". Raw encoding is always assumed as a last option
+if no other encoding can be used for some reason. For more information
+on encodings, see the section ENCODINGS below.
 .TP
 \fB\-bgr233\fR
 Always use the BGR233 format to encode pixel data. This reduces
@@ -168,6 +185,424 @@
 \fB\-autopass\fR
 Read a plain-text password from stdin. This option affects only the
 standard VNC authentication.
+
+.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS
+.TP
+Enhanced TightVNC Viewer (SSVNC) web page is located at:
+.TP
+http://www.karlrunge.com/x11vnc/ssvnc.html
+.TP
+Note: ZRLE and ZYWRLE encodings are now supported.
+.TP
+Note: F9 is shortcut to Toggle FullScreen mode.
+.TP
+Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1
+to allow more than one incoming VNC server at a time.
+This is the same as -multilisten described below.  Set
+SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n"
+simultaneous reverse connections.
+
+If the host:port is specified as "exec=command args..."
+then instead of making a TCP/IP socket connection to the
+remote VNC server, "command args..." is executed and the
+viewer is attached to its stdio.  This enables tunnelling
+established via an external command, e.g. an stunnel(8)
+that does not involve a listening socket.
+This mode does not work for -listen reverse connections.
+
+If the host:port is specified as "fd=n" then it is assumed
+n is an already opened file descriptor to the socket. (i.e
+the parent did fork+exec)
+
+If the host:port contains a '/' it is interpreted as a
+unix-domain socket (AF_LOCAL insead of AF_INET)
+.TP
+\fB\-multilisten\fR
+As in -listen (reverse connection listening) except
+allow more than one incoming VNC server to be connected
+at a time.  The default for -listen of only one at a
+time tries to play it safe by not allowing anyone on
+the network to put (many) desktops on your screen over
+a long window of time. Use -multilisten for no limit.
+.TP
+\fB\-acceptpopup\fR
+In \fB\-listen\fR (reverse connection listening) mode when
+a reverse VNC connection comes in show a popup asking
+whether to Accept or Reject the connection.  The IP
+address of the connecting host is shown.  Same as
+setting the env. var. SSVNC_ACCEPT_POPUP=1.
+.TP
+\fB\-acceptpopupsc\fR
+As in \fB\-acceptpopup\fR except assume UltraVNC Single
+Click (SC) server.  Retrieve User and ComputerName
+info from UltraVNC Server and display in the Popup.
+.TP
+\fB\-use64\fR
+In \fB\-bgr233\fR mode, use 64 colors instead of 256.
+.TP
+\fB\-bgr222\fR
+Same as \fB\-use64\fR.
+.TP
+\fB\-use8\fR
+In \fB\-bgr233\fR mode, use 8 colors instead of 256.
+.TP
+\fB\-bgr111\fR
+Same as \fB\-use8\fR.
+.TP
+\fB\-16bpp\fR
+If the vnc viewer X display is depth 24 at 32bpp
+request a 16bpp format from the VNC server to cut
+network traffic by up to 2X, then tranlate the
+pixels to 32bpp locally.
+.TP
+\fB\-bgr565\fR
+Same as \fB\-16bpp\fR.
+.TP
+\fB\-grey\fR
+Use a grey scale for the 16- and 8\fB\-bpp\fR modes.
+.TP
+\fB\-alpha\fR
+Use alphablending transparency for local cursors
+requires: x11vnc server, both client and server
+must be 32bpp and same endianness.
+.TP
+\fB\-scale\fR \fIstr\fR
+Scale the desktop locally.  The string "str" can
+a floating point ratio, e.g. "0.9", or a fraction,
+e.g. "3/4", or WxH, e.g. 1280x1024.  Use "fit"
+to fit in the current screen size.  Use "auto" to
+fit in the window size.  "str" can also be set by
+the env. var. SSVNC_SCALE.
+
+If you observe mouse trail painting errors, enable
+X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.)
+
+Note that scaling is done in software and so can be
+slow and requires more memory.  Some speedup Tips:
+
+ZRLE is faster than Tight in this mode.  When
+scaling is first detected, the encoding will
+be automatically switched to ZRLE.  Use the
+Popup menu if you want to go back to Tight.
+Set SSVNC_PRESERVE_ENCODING=1 to disable this.
+
+Use a solid background on the remote side.
+(e.g. manually or via x11vnc \fB\-solid\fR ...)
+
+If the remote server is x11vnc, try client
+side caching: x11vnc \fB\-ncache\fR 10 ...
+.TP
+\fB\-ycrop\fR n
+Only show the top n rows of the framebuffer.  For
+use with x11vnc \fB\-ncache\fR client caching option
+to help "hide" the pixel cache region.
+Use a negative value (e.g. \fB\-1\fR) for autodetection.
+Autodetection will always take place if the remote
+fb height is more than 2 times the width.
+.TP
+\fB\-sbwidth\fR n
+Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR),
+default is very narrow: 2 pixels, it is narrow to
+avoid distraction in \fB\-ycrop\fR mode.
+.TP
+\fB\-nobell\fR
+Disable bell.
+.TP
+\fB\-rawlocal\fR
+Prefer raw encoding for localhost, default is
+no, i.e. assumes you have a SSH tunnel instead.
+.TP
+\fB\-notty\fR
+Try to avoid using the terminal for interactive
+responses: use windows for messages and prompting
+instead.  Messages will also be printed to terminal.
+.TP
+\fB\-sendclipboard\fR
+Send the X CLIPBOARD selection (i.e. Ctrl+C,
+Ctrl+V) instead of the X PRIMARY selection (mouse
+select and middle button paste.)
+.TP
+\fB\-sendalways\fR
+Whenever the mouse enters the VNC viewer main
+window, send the selection to the VNC server even if
+it has not changed.  This is like the Xt resource
+translation SelectionToVNC(always)
+.TP
+\fB\-recvtext\fR
+str   When cut text is received from the VNC server,
+ssvncviewer will set both the X PRIMARY and the
+X CLIPBOARD local selections.  To control which
+is set, specify 'str' as 'primary', 'clipboard',
+or 'both' (the default.)
+.TP
+\fB\-graball\fR
+Grab the entire X server when in fullscreen mode,
+needed by some old window managers like fvwm2.
+.TP
+\fB\-popupfix\fR
+Warp the popup back to the pointer position,
+needed by some old window managers like fvwm2.
+.TP
+\fB\-grabkbd\fR
+Grab the X keyboard when in fullscreen mode,
+needed by some window managers. Same as \fB\-grabkeyboard\fR.
+\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable.
+.TP
+\fB\-bs\fR, \fB\-nobs\fR
+Whether or not to use X server Backingstore for the
+main viewer window.  The default is to not, mainly
+because most Linux, etc, systems X servers disable
+*all* Backingstore by default.  To re\fB\-enable\fR it put
+
+Option "Backingstore"
+
+in the Device section of /etc/X11/xorg.conf.
+In \fB\-bs\fR mode with no X server backingstore, whenever an
+area of the screen is re\fB\-exposed\fR it must go out to the
+VNC server to retrieve the pixels. This is too slow.
+
+In \fB\-nobs\fR mode, memory is allocated by the viewer to
+provide its own backing of the main viewer window. This
+actually makes some activities faster (changes in large
+regions) but can appear to "flash" too much.
+.TP
+\fB\-noshm\fR
+Disable use of MIT shared memory extension (not recommended)
+.TP
+\fB\-termchat\fR
+Do the UltraVNC chat in the terminal vncviewer is in
+instead of in an independent window.
+.TP
+\fB\-unixpw\fR \fIstr\fR
+Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a
+string that allows many ways to enter the Unix Username
+and Unix Password.  These characters: username, newline,
+password, newline are sent to the VNC server after any VNC
+authentication has taken place.  Under x11vnc they are
+used for the \fB\-unixpw\fR login.  Other VNC servers could do
+something similar.
+
+You can also indicate "str" via the environment
+variable SSVNC_UNIXPW.
+
+Note that the Escape key is actually sent first to tell
+x11vnc to not echo the Unix Username back to the VNC
+viewer. Set SSVNC_UNIXPW_NOESC=1 to override this.
+
+If str is ".", then you are prompted at the command line
+for the username and password in the normal way.  If str is
+"-" the stdin is read via getpass(3) for username@password.
+Otherwise if str is a file, it is opened and the first line
+read is taken as the Unix username and the 2nd as the
+password. If str prefixed by "rm:" the file is removed
+after reading. Otherwise, if str has a "@" character,
+it is taken as username@password. Otherwise, the program
+exits with an error. Got all that?
+.TP
+\fB-repeater\fR \fIstr\fR
+This is for use with UltraVNC repeater proxy described
+here: http://www.uvnc.com/addons/repeater.html.  The "str"
+is the ID string to be sent to the repeater.  E.g. ID:1234
+It can also be the hostname and port or display of the VNC
+server, e.g. 12.34.56.78:0 or snoopy.com:1.  Note that when
+using -repeater, the host:dpy on the cmdline is the repeater
+server, NOT the VNC server.  The repeater will connect you.
+
+Example: vncviewer ... -repeater ID:3333 repeat.host:5900
+
+Example: vncviewer ... -repeater vhost:0 repeat.host:5900
+
+Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a
+Single Click III (SSL) repeater (repeater_SSL.exe) and you
+are passing the SSL part of the connection through stunnel, socat, etc.
+This way the magic UltraVNC string 'testB' needed to work with the
+repeater is sent to it.
+.TP
+\fB-rfbversion\fR \fIstr\fR
+Set the advertised RFB version.  E.g.: -rfbversion 3.6  For some
+servers, e.g. UltraVNC this needs to be done.
+.TP
+\fB-ultradsm\fR
+UltraVNC has symmetric private encryption DSM plugins.  See
+http://www.uvnc.com/features/encryption.html.  It is assumed
+you are using a unix program (e.g. our ultravnc_dsm_helper) to
+encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO
+THAT supply -ultradsm to tell THIS viewer to modify the RFB
+data sent so as to work with the UltraVNC Server.  For some
+reason, each RFB msg type must be sent twice under DSM.
+.TP
+\fB\-mslogon\fR \fIuser\fR
+Use Windows MS Logon to an UltraVNC server.  Supply the
+username or "1" to be prompted.  The default is to
+autodetect the UltraVNC MS Logon server and prompt for
+the username and password.
+
+IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman
+exchange is very weak and can be brute forced to recover
+your username and password in a few seconds of CPU
+time.  To be safe, be sure to use an additional encrypted
+tunnel (e.g. SSL or SSH) for the entire VNC session.
+.TP
+\fB\-chatonly\fR
+Try to be a client that only does UltraVNC text chat. This
+mode is used by x11vnc to present a chat window on the physical
+X11 console (i.e. to chat with the person at the display).
+.TP
+\fB-env\fR \fIVAR=VALUE\fR
+To save writing a shell script to set environment
+variables, specify as many as you need on the command line.  For example,
+-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi
+.TP
+\fB\-noipv6\fR
+Disable all IPv6 sockets.  Same as VNCVIEWER_NO_IPV6=1.
+.TP
+\fB\-noipv4\fR
+Disable all IPv4 sockets.  Same as VNCVIEWER_NO_IPV4=1.
+.TP
+\fB\-printres\fR
+Print out the Ssvnc X resources (appdefaults) and
+then exit. You can save them to a file and customize them (e.g. the
+keybindings and Popup menu)  Then point to the file via
+XENVIRONMENT or XAPPLRESDIR.
+.TP
+\fB\-pipeline\fR
+Like TurboVNC, request the next framebuffer update as soon
+as possible instead of waiting until the end of the current
+framebuffer update coming in.  Helps 'pipeline' the updates.
+This is currently the default, use \fB-nopipeline\fR to disable.
+.TP
+\fB\-appshare\fR
+Enable features for use with x11vnc's \fB\-appshare\fR mode where
+instead of sharing the full desktop only the application's
+windows are shared.  Viewer multilisten mode is used to
+create the multiple windows: \fB\-multilisten\fR is implied.
+See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode.
+Features enabled in the viewer under \fB\-appshare\fR are:
+Minimum extra text in the title, auto \fB\-ycrop\fR is disabled,
+x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel,
+x11vnc initial window position hints.  See also Escape Keys
+below for additional key and mouse bindings.
+.TP
+\fB\-escape \fR\fIstr\fR
+This sets the 'Escape Keys' modifier sequence and enables
+escape keys mode.  When the modifier keys escape sequence
+is held down, the next keystroke is interpreted locally
+to perform a special action instead of being sent to the
+remote VNC server.
+
+Use '\fB\-escape\fR default' for the default modifier sequence.
+(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L)
+
+Here are the 'Escape Keys: Help+Set' instructions from the Popup:
+
+Escape Keys:  Enter a comma separated list of modifier keys to be the 'escape
+sequence'.  When these keys are held down, the next keystroke is
+interpreted locally to invoke a special action instead of being sent to
+the remote VNC server.  In other words, a set of 'Hot Keys'.
+
+Here is the list of local key mappings to special actions:
+
+r: refresh desktop  b: toggle bell  c: toggle full-color
+
+f: file transfer    x: x11cursor    z: toggle Tight/ZRLE
+
+l: full screen      g: graball      e: escape keys dialog
+
+s: scale dialog     +: scale up (=) -: scale down (_)
+
+t: text chat                        a: alphablend cursor
+
+V: toggle viewonly  Q: quit viewer  123456: UltraVNC scale 1/n
+
+Arrow keys: pan the viewport about 10% for each keypress.
+
+PageUp/PageDown: pan the viewport by a screenful vertically.
+
+Home/End: pan the viewport by a screenful horizontally.
+
+KeyPad Arrows: pan the viewport by 1 pixel for each keypress.
+
+Dragging the Mouse with Button1 pressed also pans the viewport.
+
+Clicking Mouse Button3 brings up the Popup Menu.
+
+The above mappings are \fBalways\fR active in ViewOnly mode, unless you set
+the Escape Keys value to 'never'.
+
+x11vnc -appshare hot-keys:  x11vnc has a simple application sharing mode
+that enables the viewer-side to move, resize, or raise the remote toplevel
+windows.  To enable it, hold down Shift + the Escape Keys and press these:
+
+Arrow keys: move the remote window around in its desktop.
+
+PageUp/PageDn/Home/End:  resize the remote window.
+
++/-: raise or lower the remote window.
+
+M or Button1 move win to local position;  D or Button3: delete remote win.
+
+If the Escape Keys value below is set to 'default' then a default list of
+of modifier keys is used.  For Unix it is: Alt_L,Super_L and for MacOSX it
+is Control_L,Meta_L.  Note: the Super_L key usually has a Windows(TM) Flag
+on it.  Also note the _L and _R mean the key is on the LEFT or RIGHT side
+of the keyboard.
+
+On Unix   the default is Alt and Windows keys on Left side of keyboard.
+On MacOSX the default is Control and Command keys on Left side of keyboard.
+
+Example: Press and hold the Alt and Windows keys on the LEFT side of the
+keyboard and then press 'c' to toggle the full-color state.  Or press 't'
+to toggle the ultravnc Text Chat window, etc.
+
+To use something besides the default, supply a comma separated list (or a
+single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L
+Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.
+.TP
+\fB New Popup actions:\fR
+
+ ViewOnly:                ~ -viewonly
+ Disable Bell:            ~ -nobell
+ Cursor Shape:            ~ -nocursorshape
+ X11 Cursor:              ~ -x11cursor
+ Cursor Alphablend:       ~ -alpha
+ Toggle Tight/Hextile:    ~ -encodings hextile...
+ Toggle Tight/ZRLE:       ~ -encodings zrle...
+ Toggle ZRLE/ZYWRLE:      ~ -encodings zywrle...
+ Quality Level            ~ -quality (both Tight and ZYWRLE)
+ Compress Level           ~ -compresslevel
+ Disable JPEG:            ~ -nojpeg  (Tight)
+ Pipeline Updates         ~ -pipeline
+
+ Full Color                 as many colors as local screen allows.
+ Grey scale (16 & 8-bpp)  ~ -grey, for low colors 16/8bpp modes only.
+ 16 bit color (BGR565)    ~ -16bpp / -bgr565
+ 8  bit color (BGR233)    ~ -bgr233
+ 256 colors               ~ -bgr233 default # of colors.
+  64 colors               ~ -bgr222 / -use64
+   8 colors               ~ -bgr111 / -use8
+ Scale Viewer             ~ -scale
+ Escape Keys: Toggle      ~ -escape
+ Escape Keys: Help+Set    ~ -escape
+ Set Y Crop (y-max)       ~ -ycrop
+ Set Scrollbar Width      ~ -sbwidth
+ XGrabServer              ~ -graball
+
+ UltraVNC Extensions:
+
+   Set 1/n Server Scale     Ultravnc ext. Scale desktop by 1/n.
+   Text Chat                Ultravnc ext. Do Text Chat.
+   File Transfer            Ultravnc ext. File xfer via Java helper.
+   Single Window            Ultravnc ext. Grab and view a single window.
+                            (select then click on the window you want).
+   Disable Remote Input     Ultravnc ext. Try to prevent input and
+                            viewing of monitor at physical display.
+
+ Note: the Ultravnc extensions only apply to servers that support
+       them.  x11vnc/libvncserver supports some of them.
+
+ Send Clipboard not Primary  ~ -sendclipboard
+ Send Selection Every time   ~ -sendalways
+
 .SH ENCODINGS
 The server supplies information in whatever format is desired by the
 client, in order to make the client as easy as possible to implement. 
@@ -238,6 +673,15 @@
 \-quality and \-nojpeg options above). Tight encoding is usually the
 best choice for low\-bandwidth network environments (e.g. slow modem
 connections).
+.TP
+.B ZRLE
+The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding
+to the unix tightvnc viewer.
+.TP
+.B ZYWRLE
+The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE
+encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ 
+to the unix tightvnc viewer.
 .SH RESOURCES
 X resources that \fBvncviewer\fR knows about, aside from the
 normal Xt resources, are as follows:
@@ -364,12 +808,13 @@
 .B %R
 remote TCP port number.
 .SH SEE ALSO
-\fBvncserver\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1),
-\fBvncconnect\fR(1), \fBssh\fR(1)
+\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1),
+\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html
 .SH AUTHORS
 Original VNC was developed in AT&T Laboratories Cambridge. TightVNC
 additions was implemented by Constantin Kaplinsky. Many other people
-participated in development, testing and support.
+participated in development, testing and support.  Karl J. Runge 
+added all of the SSVNC related features and improvements.
 
 \fBMan page authors:\fR
 .br
@@ -380,3 +825,5 @@
 Tim Waugh <twaugh@redhat.com>,
 .br
 Constantin Kaplinsky <const@ce.cctpu.edu.ru>
+.br
+Karl J. Runge <runge@karlrunge.com>
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/zrle.c
--- vnc_unixsrc.orig/vncviewer/zrle.c	2007-02-04 18:59:50.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrle.c	2010-02-25 23:24:28.000000000 -0500
@@ -0,0 +1,620 @@
+/*
+ *  Copyright (C) 2005 Johannes E. Schindelin.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * zrle.c - handle zrle encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles an zrle
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#ifndef REALBPP
+#define REALBPP BPP
+#endif
+
+#if !defined(UNCOMP) || UNCOMP==0
+#define HandleZRLE CONCAT2E(HandleZRLE,REALBPP)
+#define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP)
+#elif UNCOMP>0
+#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down)
+#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down)
+#else
+#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up)
+#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up)
+#endif
+#undef CARDBPP
+#undef CARDREALBPP
+#define CARDBPP CONCAT2E(CARD, BPP)
+#define CARDREALBPP CONCAT2E(CARD,REALBPP)
+
+#define FillRectangle(x, y, w, h, color)  \
+	{ \
+		XGCValues _gcv; \
+		_gcv.foreground = color; \
+		if (!appData.useXserverBackingStore) { \
+			FillScreen(x, y, w, h, _gcv.foreground); \
+		} else { \
+			XChangeGC(dpy, gc, GCForeground, &_gcv); \
+			XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \
+		} \
+	}
+
+#if defined(__sparc) || defined(__sparc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN)
+#define IS_BIG_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 0
+#endif
+
+#if DO_ZYWRLE
+
+#define ENDIAN_LITTLE 0
+#define ENDIAN_BIG 1
+#define ENDIAN_NO 2
+#if IS_BIG_ENDIAN
+#define ZYWRLE_ENDIAN ENDIAN_BIG
+#else
+#define ZYWRLE_ENDIAN ENDIAN_LITTLE
+#endif
+#undef END_FIX
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+#  define END_FIX LE
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define END_FIX BE
+#else
+#  define END_FIX NE
+#endif
+#define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c)
+#define __RFB_CONCAT2E(a,b) CONCAT2E(a,b)
+#undef CPIXEL
+#if REALBPP != BPP
+#if UNCOMP == 0
+#define CPIXEL REALBPP
+#elif UNCOMP>0
+#define CPIXEL CONCAT2E(REALBPP,Down)
+#else
+#define CPIXEL CONCAT2E(REALBPP,Up)
+#endif
+#endif
+#define PIXEL_T CARDBPP
+#if BPP!=8
+#define ZYWRLE_DECODE 1
+#include "zywrletemplate.c"
+#endif
+#undef CPIXEL
+
+#endif	/* DO_ZYWRLE */
+
+static int HandleZRLETile(
+	unsigned char* buffer,size_t buffer_length,
+	int x,int y,int w,int h);
+
+static Bool
+HandleZRLE (int rx, int ry, int rw, int rh)
+{
+	rfbZRLEHeader header;
+	int remaining;
+	int inflateResult;
+	int toRead;
+	int min_buffer_size = rw * rh * (REALBPP / 8) * 2;
+
+	/* First make sure we have a large enough raw buffer to hold the
+	 * decompressed data.  In practice, with a fixed REALBPP, fixed frame
+	 * buffer size and the first update containing the entire frame
+	 * buffer, this buffer allocation should only happen once, on the
+	 * first update.
+	 */
+	if ( raw_buffer_size < min_buffer_size) {
+
+		if ( raw_buffer != NULL ) {
+
+			free( raw_buffer );
+
+		}
+
+		raw_buffer_size = min_buffer_size;
+		raw_buffer = (char*) malloc( raw_buffer_size );
+
+	}
+
+	if (!ReadFromRFBServer((char *)&header, sz_rfbZRLEHeader))
+		return False;
+
+	remaining = Swap32IfLE(header.length);
+
+	/* Need to initialize the decompressor state. */
+	decompStream.next_in   = ( Bytef * )buffer;
+	decompStream.avail_in  = 0;
+	decompStream.next_out  = ( Bytef * )raw_buffer;
+	decompStream.avail_out = raw_buffer_size;
+	decompStream.data_type = Z_BINARY;
+
+	/* Initialize the decompression stream structures on the first invocation. */
+	if ( decompStreamInited == False ) {
+
+		inflateResult = inflateInit( &decompStream );
+
+		if ( inflateResult != Z_OK ) {
+			fprintf(stderr, 
+					"inflateInit returned error: %d, msg: %s\n",
+					inflateResult,
+					decompStream.msg);
+			return False;
+		}
+
+		decompStreamInited = True;
+
+	}
+
+	inflateResult = Z_OK;
+
+	/* Process buffer full of data until no more to process, or
+	 * some type of inflater error, or Z_STREAM_END.
+	 */
+	while (( remaining > 0 ) &&
+			( inflateResult == Z_OK )) {
+
+		if ( remaining > BUFFER_SIZE ) {
+			toRead = BUFFER_SIZE;
+		}
+		else {
+			toRead = remaining;
+		}
+
+		/* Fill the buffer, obtaining data from the server. */
+		if (!ReadFromRFBServer(buffer,toRead))
+			return False;
+
+		decompStream.next_in  = ( Bytef * )buffer;
+		decompStream.avail_in = toRead;
+
+		/* Need to uncompress buffer full. */
+		inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
+
+		/* We never supply a dictionary for compression. */
+		if ( inflateResult == Z_NEED_DICT ) {
+			fprintf(stderr, "zlib inflate needs a dictionary!\n");
+			return False;
+		}
+		if ( inflateResult < 0 ) {
+			fprintf(stderr, 
+					"zlib inflate returned error: %d, msg: %s\n",
+					inflateResult,
+					decompStream.msg);
+			return False;
+		}
+
+		/* Result buffer allocated to be at least large enough.  We should
+		 * never run out of space!
+		 */
+		if (( decompStream.avail_in > 0 ) &&
+				( decompStream.avail_out <= 0 )) {
+			fprintf(stderr, "zlib inflate ran out of space!\n");
+			return False;
+		}
+
+		remaining -= toRead;
+
+	} /* while ( remaining > 0 ) */
+
+	if ( inflateResult == Z_OK ) {
+		void* buf=raw_buffer;
+		int i,j;
+
+		remaining = raw_buffer_size-decompStream.avail_out;
+
+		for(j=0; j<rh; j+=rfbZRLETileHeight)
+			for(i=0; i<rw; i+=rfbZRLETileWidth) {
+				int subWidth=(i+rfbZRLETileWidth>rw)?rw-i:rfbZRLETileWidth;
+				int subHeight=(j+rfbZRLETileHeight>rh)?rh-j:rfbZRLETileHeight;
+				int result=HandleZRLETile(buf,remaining,rx+i,ry+j,subWidth,subHeight);
+
+				if(result<0) {
+					fprintf(stderr, "ZRLE decoding failed (%d)\n",result);
+return True;
+					return False;
+				}
+
+				buf+=result;
+				remaining-=result;
+			}
+	}
+	else {
+
+		fprintf(stderr, 
+				"zlib inflate returned error: %d, msg: %s\n",
+				inflateResult,
+				decompStream.msg);
+		return False;
+
+	}
+
+	return True;
+}
+
+#if REALBPP!=BPP && defined(UNCOMP) && UNCOMP!=0
+# if BPP == 32 && IS_BIG_ENDIAN
+#  define UncompressCPixel(p) ( (*p << myFormat.redShift) | (*(p+1) << myFormat.greenShift) | (*(p+2) << myFormat.blueShift) )
+# else
+#  if UNCOMP>0
+#   define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)>>UNCOMP)
+#  else
+#   define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)<<(-(UNCOMP)))
+#  endif
+# endif
+#else
+# define UncompressCPixel(pointer) (*(CARDBPP*)pointer)
+#endif
+
+extern XImage *image;
+extern XImage *image_scale;
+extern int skip_maybe_sync;
+
+static int HandleZRLETile(
+		unsigned char* buffer,size_t buffer_length,
+		int x,int y,int w,int h) {
+	unsigned char* buffer_copy = buffer;
+	unsigned char* buffer_end = buffer+buffer_length;
+	unsigned char type;
+
+	if(buffer_length<1)
+		return -2;
+
+	if (frameBufferLen < w * h * BPP/8) {
+		if(frameBuffer) {
+			free(frameBuffer);
+		}
+		frameBufferLen = w * h * BPP/8 * 2;
+		frameBuffer = (unsigned char *) malloc(frameBufferLen);
+	}
+
+zywrle_top:
+	type = *buffer;
+	buffer++;
+	switch(type) {
+		case 0: /* raw */
+		{
+#if DO_ZYWRLE && BPP != 8
+		    if (zywrle_level > 0 && !(zywrle_level & 0x80) ) {
+			zywrle_level |= 0x80;
+			goto zywrle_top;
+		    } else
+#endif
+		    {
+#if REALBPP!=BPP
+			int m0 = 0, i,j;
+
+
+			if(1+w*h*REALBPP/8>buffer_length) {
+				fprintf(stderr, "expected %d bytes, got only %d (%dx%d)\n",1+w*h*REALBPP/8,buffer_length,w,h);
+				return -3;
+			}
+
+			for(j=y*si.framebufferWidth; j<(y+h)*si.framebufferWidth; j+=si.framebufferWidth) {
+				for(i=x; i<x+w; i++,buffer+=REALBPP/8) {
+#  if 0
+					((CARDBPP*)frameBuffer)[j+i] = UncompressCPixel(buffer);
+					/* alt */
+					CARDBPP color = UncompressCPixel(buffer);
+					CopyDataToScreen((char *)&color, i, j/si.framebufferWidth, 1, 1);
+#  else
+					((CARDBPP*)frameBuffer)[m0++] = UncompressCPixel(buffer);
+#  endif
+				}
+			}
+			CopyDataToScreen((char *)frameBuffer, x, y, w, h);
+if (0) fprintf(stderr, "cha1: %dx%d+%d+%d\n", w, h, x, y);
+
+#else
+#  if 0
+			CopyRectangle(buffer, x, y, w, h);
+#  else
+			CopyDataToScreen((char *)buffer, x, y, w, h);
+#  endif
+			buffer+=w*h*REALBPP/8;
+#endif
+		    }
+			break;
+		}
+		case 1: /* solid */
+		{
+			CARDBPP color = UncompressCPixel(buffer);
+
+			if(1+REALBPP/8>buffer_length)
+				return -4;
+				
+			if ((BPP == 8 && appData.useBGR233) || (BPP == 16 && appData.useBGR565)) {
+				int m0;
+				for (m0=0; m0 < w*h; m0++) {
+					((CARDBPP*)frameBuffer)[m0] = color;
+				}
+				CopyDataToScreen((char *)frameBuffer, x, y, w, h);
+			} else {
+				FillRectangle(x, y, w, h, color);
+			}
+if (0) fprintf(stderr, "cha2: %dx%d+%d+%d\n", w, h, x, y);
+
+			buffer+=REALBPP/8;
+
+			break;
+		}
+		case 2 ... 127: /* packed Palette */
+		{
+			CARDBPP palette[16];
+			int m0, i,j,shift,
+				bpp=(type>4?(type>16?8:4):(type>2?2:1)),
+				mask=(1<<bpp)-1,
+				divider=(8/bpp);
+
+			if(1+type*REALBPP/8+((w+divider-1)/divider)*h>buffer_length)
+				return -5;
+
+			/* read palette */
+			for(i=0; i<type; i++,buffer+=REALBPP/8)
+				palette[i] = UncompressCPixel(buffer);
+
+			m0 = 0;
+			/* read palettized pixels */
+			for(j=y*si.framebufferWidth; j<(y+h)*si.framebufferWidth; j+=si.framebufferWidth) {
+				for(i=x,shift=8-bpp; i<x+w; i++) {
+#  if 0
+					((CARDBPP*)frameBuffer)[j+i] = palette[((*buffer)>>shift)&mask];
+					/* alt */
+					CARDBPP color = palette[((*buffer)>>shift)&mask];
+					CopyDataToScreen((char *)&color, i, j/si.framebufferWidth, 1, 1);
+#  else
+					((CARDBPP*)frameBuffer)[m0++] = palette[((*buffer)>>shift)&mask];
+#  endif
+					shift-=bpp;
+					if(shift<0) {
+						shift=8-bpp;
+						buffer++;
+					}
+				}
+				if(shift<8-bpp)
+					buffer++;
+			}
+			CopyDataToScreen((char *)frameBuffer, x, y, w, h);
+if (0) fprintf(stderr, "cha3: %dx%d+%d+%d\n", w, h, x, y);
+
+			break;
+		}
+		/* case 17 ... 127: not used, but valid */
+		case 128: /* plain RLE */
+		{
+			int m0=0, i=0,j=0;
+			while(j<h) {
+				int color,length;
+				/* read color */
+				if(buffer+REALBPP/8+1>buffer_end)
+					return -7;
+				color = UncompressCPixel(buffer);
+				buffer+=REALBPP/8;
+				/* read run length */
+				length=1;
+				while(*buffer==0xff) {
+					if(buffer+1>=buffer_end)
+						return -8;
+					length+=*buffer;
+					buffer++;
+				}
+				length+=*buffer;
+				buffer++;
+				while(j<h && length>0) {
+#  if 0
+					((CARDBPP*)frameBuffer)[(y+j)*si.framebufferWidth+x+i] = color;
+					/* alt */
+					CopyDataToScreen((char *)&color, x+i, y+j, 1, 1);
+#  else
+					((CARDBPP*)frameBuffer)[m0++] = color;
+#  endif
+					length--;
+					i++;
+					if(i>=w) {
+						i=0;
+						j++;
+					}
+				}
+				if(length>0)
+					fprintf(stderr, "Warning: possible ZRLE corruption\n");
+			}
+			CopyDataToScreen((char *)frameBuffer, x, y, w, h);
+if (0) fprintf(stderr, "cha4: %dx%d+%d+%d\n", w, h, x, y);
+
+			break;
+		}
+		case 129: /* unused */
+		{
+			return -8;
+		}
+		case 130 ... 255: /* palette RLE */
+		{
+			CARDBPP palette[128];
+			int m0 = 0, i,j;
+
+			if(2+(type-128)*REALBPP/8>buffer_length)
+				return -9;
+
+			/* read palette */
+			for(i=0; i<type-128; i++,buffer+=REALBPP/8)
+				palette[i] = UncompressCPixel(buffer);
+			/* read palettized pixels */
+			i=j=0;
+			while(j<h) {
+				int color,length;
+				/* read color */
+				if(buffer>=buffer_end)
+					return -10;
+				color = palette[(*buffer)&0x7f];
+				length=1;
+				if(*buffer&0x80) {
+					if(buffer+1>=buffer_end)
+						return -11;
+					buffer++;
+					/* read run length */
+					while(*buffer==0xff) {
+						if(buffer+1>=buffer_end)
+							return -8;
+						length+=*buffer;
+						buffer++;
+					}
+					length+=*buffer;
+				}
+				buffer++;
+				while(j<h && length>0) {
+#  if 0
+					((CARDBPP*)frameBuffer)[(y+j)*si.framebufferWidth+x+i] = color;
+					/* alt */
+					CopyDataToScreen((char *)&color, x+i, y+j, 1, 1);
+#  else
+					((CARDBPP*)frameBuffer)[m0++] = color;
+#  endif
+					length--;
+					i++;
+					if(i>=w) {
+						i=0;
+						j++;
+					}
+				}
+				if(length>0)
+					fprintf(stderr, "Warning: possible ZRLE corruption\n");
+			}
+			CopyDataToScreen((char *)frameBuffer, x, y, w, h);
+if (0) fprintf(stderr, "cha5: %dx%d+%d+%d\n", w, h, x, y);
+
+			break;
+		}
+	}
+
+#if DO_ZYWRLE && BPP != 8
+	if (zywrle_level & 0x80) {
+		int th, tx;
+		int widthInBytes = w * BPP / 8;
+		int scrWidthInBytes;
+		char *scr, *buf;
+		static CARDBPP *ptmp = NULL;
+		static int ptmp_len = 0;
+		XImage *im = image_scale ? image_scale : image; 
+
+		if (w * h > ptmp_len) {
+			ptmp_len = w * h;
+			if (ptmp_len < rfbZRLETileWidth*rfbZRLETileHeight) {
+				ptmp_len = rfbZRLETileWidth*rfbZRLETileHeight;
+			}
+			if (ptmp) {
+				free(ptmp);
+			}
+			ptmp = (CARDBPP *) malloc(ptmp_len * sizeof(CARDBPP));
+		}
+
+		zywrle_level &= 0x7F;
+		/* Reverse copy: screen to buf/ptmp: */
+		/* make this CopyDataFromScreen() or something. */
+		if (!appData.useBGR565) {
+			scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8;
+			if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line;
+			scr = im->data + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8;
+			buf = (char *) ptmp;
+
+			for (th = 0; th < h; th++) {
+				memcpy(buf, scr, widthInBytes);
+				buf += widthInBytes;
+				scr += scrWidthInBytes;
+			}
+		} else {
+			scrWidthInBytes = si.framebufferWidth * 4;
+			if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line;
+			scr = im->data + y * scrWidthInBytes + x * 4;
+			buf = (char *) ptmp;
+
+			for (th = 0; th < h; th++) {
+				for (tx = 0; tx < w; tx++) {
+					unsigned long pix = *((unsigned int *)scr + tx);
+					unsigned int r1 = (pix & 0xff0000) >> 16; 
+					unsigned int g1 = (pix & 0x00ff00) >> 8; 
+					unsigned int b1 = (pix & 0x0000ff) >> 0; 
+					int r2, g2, b2, idx;
+					int rok = 0, gok = 0, bok = 0, is0, sh = 10;
+					r2 = (31 * r1)/255;
+					g2 = (63 * g1)/255;
+					b2 = (31 * b1)/255;
+					for (is0 = 0; is0 < sh; is0++) {
+						int is, i, t;
+						for (i = 0; i < 2; i++) {
+							if (i == 0) {
+								is = -is0;
+							} else {
+								is = +is0;
+							}
+							if (!rok) {
+								t = r2 + is;
+								if (r1 == (255 * t)/31) {
+									r2 = t; rok = 1;
+								}
+							}
+							if (!gok) {
+								t = g2 + is;
+								if (g1 == (255 * t)/63) {
+									g2 = t; gok = 1;
+								}
+							}
+							if (!bok) {
+								t = b2 + is;
+								if (b1 == (255 * t)/31) {
+									b2 = t; bok = 1;
+								}
+							}
+						}
+						if (rok && gok && bok) {
+							break;
+						}
+					}
+					idx = (r2 << 11) | (g2 << 5) | (b2 << 0);
+					*((CARDBPP *)buf + tx) = (CARDBPP) idx;
+				}
+				buf += widthInBytes;
+				scr += scrWidthInBytes;
+			}
+		}
+		ZYWRLE_SYNTHESIZE((PIXEL_T *)ptmp, (PIXEL_T *)ptmp, w, h, w, zywrle_level, zywrleBuf );
+		skip_maybe_sync = 1;
+
+		if (appData.yCrop > 0) {
+			skip_maybe_sync = 0;
+		}
+		CopyDataToScreen((char *)ptmp, x, y, w, h);
+
+	}
+#endif
+
+	return buffer-buffer_copy;	
+}
+
+#undef CARDBPP
+#undef CARDREALBPP
+#undef HandleZRLE
+#undef HandleZRLETile
+#undef UncompressCPixel
+#undef REALBPP
+
+#undef UNCOMP
+
+#undef FillRectangle
+#undef IS_BIG_ENDIAN
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c vnc_unixsrc/vncviewer/zrleencodetemplate.c
--- vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrleencodetemplate.c	2007-02-04 23:18:09.000000000 -0500
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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.
+ */
+
+/*
+ * Before including this file, you must define a number of CPP macros.
+ *
+ * BPP should be 8, 16 or 32 depending on the bits per pixel.
+ * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
+ * into the given buffer.  EXTRA_ARGS can be defined to pass any other
+ * arguments needed by GET_IMAGE_INTO_BUF.
+ *
+ * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
+ * bigger than the largest tile of pixel data, since the ZRLE encoding
+ * algorithm writes to the position one past the end of the pixel data.
+ */
+
+#include "zrleoutstream.h"
+#include "zrlepalettehelper.h"
+#include <assert.h>
+
+/* __RFB_CONCAT2 concatenates its two arguments.  __RFB_CONCAT2E does the same
+   but also expands its arguments if they are macros */
+
+#ifndef __RFB_CONCAT2E
+#define __RFB_CONCAT2(a,b) a##b
+#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
+#endif
+
+#ifndef __RFB_CONCAT3E
+#define __RFB_CONCAT3(a,b,c) a##b##c
+#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
+#endif
+
+#undef END_FIX
+#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
+#  define END_FIX LE
+#elif ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define END_FIX BE
+#else
+#  define END_FIX NE
+#endif
+
+#ifdef CPIXEL
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
+#define BPPOUT 24
+#elif BPP==15
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT 16
+#else
+#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
+#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
+#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
+#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
+#define BPPOUT BPP
+#endif
+
+#ifndef ZRLE_ONCE
+#define ZRLE_ONCE
+
+static const int bitsPerPackedPixel[] = {
+  0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+int zywrle_level;
+int zywrleBuf[rfbZRLETileWidth*rfbZRLETileHeight];
+
+static zrlePaletteHelper paletteHelper;
+
+#endif /* ZRLE_ONCE */
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os);
+
+#if BPP!=8
+#define ZYWRLE_ENCODE
+#include "zywrletemplate.c"
+#endif
+
+static void ZRLE_ENCODE (int x, int y, int w, int h,
+		  zrleOutStream* os, void* buf
+                  EXTRA_ARGS
+                  )
+{
+  int ty;
+  for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
+    int tx, th = rfbZRLETileHeight;
+    if (th > y+h-ty) th = y+h-ty;
+    for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
+      int tw = rfbZRLETileWidth;
+      if (tw > x+w-tx) tw = x+w-tx;
+
+      GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
+
+      ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os);
+    }
+  }
+  zrleOutStreamFlush(os);
+}
+
+
+void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os)
+{
+  /* First find the palette and the number of runs */
+
+  zrlePaletteHelper *ph;
+
+  int runs = 0;
+  int singlePixels = 0;
+
+  rfbBool useRle;
+  rfbBool usePalette;
+
+  int estimatedBytes;
+  int plainRleBytes;
+  int i;
+
+  PIXEL_T* ptr = data;
+  PIXEL_T* end = ptr + h * w;
+  *end = ~*(end-1); /* one past the end is different so the while loop ends */
+
+  ph = &paletteHelper;
+  zrlePaletteHelperInit(ph);
+
+  while (ptr < end) {
+    PIXEL_T pix = *ptr;
+    if (*++ptr != pix) {
+      singlePixels++;
+    } else {
+      while (*++ptr == pix) ;
+      runs++;
+    }
+    zrlePaletteHelperInsert(ph, pix);
+  }
+
+  /* Solid tile is a special case */
+
+  if (ph->size == 1) {
+    zrleOutStreamWriteU8(os, 1);
+    zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
+    return;
+  }
+
+  /* Try to work out whether to use RLE and/or a palette.  We do this by
+     estimating the number of bytes which will be generated and picking the
+     method which results in the fewest bytes.  Of course this may not result
+     in the fewest bytes after compression... */
+
+  useRle = FALSE;
+  usePalette = FALSE;
+
+  estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
+
+#if BPP!=8
+  if( (zywrle_level>0)&& !(zywrle_level & 0x80) ){
+	  estimatedBytes >>= zywrle_level;
+  }
+#endif
+
+  plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
+
+  if (plainRleBytes < estimatedBytes) {
+    useRle = TRUE;
+    estimatedBytes = plainRleBytes;
+  }
+
+  if (ph->size < 128) {
+    int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
+
+    if (paletteRleBytes < estimatedBytes) {
+      useRle = TRUE;
+      usePalette = TRUE;
+      estimatedBytes = paletteRleBytes;
+    }
+
+    if (ph->size < 17) {
+      int packedBytes = ((BPPOUT/8) * ph->size +
+                         w * h * bitsPerPackedPixel[ph->size-1] / 8);
+
+      if (packedBytes < estimatedBytes) {
+        useRle = FALSE;
+        usePalette = TRUE;
+        estimatedBytes = packedBytes;
+      }
+    }
+  }
+
+  if (!usePalette) ph->size = 0;
+
+  zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
+
+  for (i = 0; i < ph->size; i++) {
+    zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
+  }
+
+  if (useRle) {
+
+    PIXEL_T* ptr = data;
+    PIXEL_T* end = ptr + w * h;
+    PIXEL_T* runStart;
+    PIXEL_T pix;
+    while (ptr < end) {
+      int len;
+      runStart = ptr;
+      pix = *ptr++;
+      while (*ptr == pix && ptr < end)
+        ptr++;
+      len = ptr - runStart;
+      if (len <= 2 && usePalette) {
+        int index = zrlePaletteHelperLookup(ph, pix);
+        if (len == 2)
+          zrleOutStreamWriteU8(os, index);
+        zrleOutStreamWriteU8(os, index);
+        continue;
+      }
+      if (usePalette) {
+        int index = zrlePaletteHelperLookup(ph, pix);
+        zrleOutStreamWriteU8(os, index | 128);
+      } else {
+        zrleOutStreamWRITE_PIXEL(os, pix);
+      }
+      len -= 1;
+      while (len >= 255) {
+        zrleOutStreamWriteU8(os, 255);
+        len -= 255;
+      }
+      zrleOutStreamWriteU8(os, len);
+    }
+
+  } else {
+
+    /* no RLE */
+
+    if (usePalette) {
+      int bppp;
+      PIXEL_T* ptr = data;
+
+      /* packed pixels */
+
+      assert (ph->size < 17);
+
+      bppp = bitsPerPackedPixel[ph->size-1];
+
+      for (i = 0; i < h; i++) {
+        zrle_U8 nbits = 0;
+        zrle_U8 byte = 0;
+
+        PIXEL_T* eol = ptr + w;
+
+        while (ptr < eol) {
+          PIXEL_T pix = *ptr++;
+          zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
+          byte = (byte << bppp) | index;
+          nbits += bppp;
+          if (nbits >= 8) {
+            zrleOutStreamWriteU8(os, byte);
+            nbits = 0;
+          }
+        }
+        if (nbits > 0) {
+          byte <<= 8 - nbits;
+          zrleOutStreamWriteU8(os, byte);
+        }
+      }
+    } else {
+
+      /* raw */
+
+#if BPP!=8
+      if( (zywrle_level>0)&& !(zywrle_level & 0x80) ){
+		  ZYWRLE_ANALYZE( data, data, w, h, w, zywrle_level, zywrleBuf );
+		  zywrle_level |= 0x80;
+		  ZRLE_ENCODE_TILE( data, w, h, os );
+		  zywrle_level &= 0x7F;
+	  }else
+#endif
+	{
+#ifdef CPIXEL
+      PIXEL_T *ptr;
+      for (ptr = data; ptr < data+w*h; ptr++) {
+        zrleOutStreamWRITE_PIXEL(os, *ptr);
+      }
+#else
+        zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
+#endif
+	  }
+    }
+  }
+}
+
+#undef PIXEL_T
+#undef zrleOutStreamWRITE_PIXEL
+#undef ZRLE_ENCODE
+#undef ZRLE_ENCODE_TILE
+#undef ZYWRLE_ENCODE_TILE
+#undef BPPOUT
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleoutstream.c vnc_unixsrc/vncviewer/zrleoutstream.c
--- vnc_unixsrc.orig/vncviewer/zrleoutstream.c	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrleoutstream.c	2005-05-15 10:57:54.000000000 -0400
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include "zrleoutstream.h"
+#include <stdlib.h>
+
+#define ZRLE_IN_BUFFER_SIZE  16384
+#define ZRLE_OUT_BUFFER_SIZE 1024
+#undef  ZRLE_DEBUG
+
+static rfbBool zrleBufferAlloc(zrleBuffer *buffer, int size)
+{
+  buffer->ptr = buffer->start = malloc(size);
+  if (buffer->start == NULL) {
+    buffer->end = NULL;
+    return FALSE;
+  }
+
+  buffer->end = buffer->start + size;
+
+  return TRUE;
+}
+
+static void zrleBufferFree(zrleBuffer *buffer)
+{
+  if (buffer->start)
+    free(buffer->start);
+  buffer->start = buffer->ptr = buffer->end = NULL;
+}
+
+static rfbBool zrleBufferGrow(zrleBuffer *buffer, int size)
+{
+  int offset;
+
+  size  += buffer->end - buffer->start;
+  offset = ZRLE_BUFFER_LENGTH (buffer);
+
+  buffer->start = realloc(buffer->start, size);
+  if (!buffer->start) {
+    return FALSE;
+  }
+
+  buffer->end = buffer->start + size;
+  buffer->ptr = buffer->start + offset;
+
+  return TRUE;
+}
+
+zrleOutStream *zrleOutStreamNew(void)
+{
+  zrleOutStream *os;
+
+  os = malloc(sizeof(zrleOutStream));
+  if (os == NULL)
+    return NULL;
+
+  if (!zrleBufferAlloc(&os->in, ZRLE_IN_BUFFER_SIZE)) {
+    free(os);
+    return NULL;
+  }
+
+  if (!zrleBufferAlloc(&os->out, ZRLE_OUT_BUFFER_SIZE)) {
+    zrleBufferFree(&os->in);
+    free(os);
+    return NULL;
+  }
+
+  os->zs.zalloc = Z_NULL;
+  os->zs.zfree  = Z_NULL;
+  os->zs.opaque = Z_NULL;
+  if (deflateInit(&os->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
+    zrleBufferFree(&os->in);
+    free(os);
+    return NULL;
+  }
+
+  return os;
+}
+
+void zrleOutStreamFree (zrleOutStream *os)
+{
+  deflateEnd(&os->zs);
+  zrleBufferFree(&os->in);
+  zrleBufferFree(&os->out);
+  free(os);
+}
+
+rfbBool zrleOutStreamFlush(zrleOutStream *os)
+{
+  os->zs.next_in = os->in.start;
+  os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
+  
+#ifdef ZRLE_DEBUG
+  rfbLog("zrleOutStreamFlush: avail_in %d\n", os->zs.avail_in);
+#endif
+
+  while (os->zs.avail_in != 0) {
+    do {
+      int ret;
+
+      if (os->out.ptr >= os->out.end &&
+	  !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
+	rfbLog("zrleOutStreamFlush: failed to grow output buffer\n");
+	return FALSE;
+      }
+
+      os->zs.next_out = os->out.ptr;
+      os->zs.avail_out = os->out.end - os->out.ptr;
+
+#ifdef ZRLE_DEBUG
+      rfbLog("zrleOutStreamFlush: calling deflate, avail_in %d, avail_out %d\n",
+	     os->zs.avail_in, os->zs.avail_out);
+#endif 
+
+      if ((ret = deflate(&os->zs, Z_SYNC_FLUSH)) != Z_OK) {
+	rfbLog("zrleOutStreamFlush: deflate failed with error code %d\n", ret);
+	return FALSE;
+      }
+
+#ifdef ZRLE_DEBUG
+      rfbLog("zrleOutStreamFlush: after deflate: %d bytes\n",
+	     os->zs.next_out - os->out.ptr);
+#endif
+
+      os->out.ptr = os->zs.next_out;
+    } while (os->zs.avail_out == 0);
+  }
+
+  os->in.ptr = os->in.start;
+ 
+  return TRUE;
+}
+
+static int zrleOutStreamOverrun(zrleOutStream *os,
+				int            size)
+{
+#ifdef ZRLE_DEBUG
+  rfbLog("zrleOutStreamOverrun\n");
+#endif
+
+  while (os->in.end - os->in.ptr < size && os->in.ptr > os->in.start) {
+    os->zs.next_in = os->in.start;
+    os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in);
+
+    do {
+      int ret;
+
+      if (os->out.ptr >= os->out.end &&
+	  !zrleBufferGrow(&os->out, os->out.end - os->out.start)) {
+	rfbLog("zrleOutStreamOverrun: failed to grow output buffer\n");
+	return FALSE;
+      }
+
+      os->zs.next_out = os->out.ptr;
+      os->zs.avail_out = os->out.end - os->out.ptr;
+
+#ifdef ZRLE_DEBUG
+      rfbLog("zrleOutStreamOverrun: calling deflate, avail_in %d, avail_out %d\n",
+	     os->zs.avail_in, os->zs.avail_out);
+#endif
+
+      if ((ret = deflate(&os->zs, 0)) != Z_OK) {
+	rfbLog("zrleOutStreamOverrun: deflate failed with error code %d\n", ret);
+	return 0;
+      }
+
+#ifdef ZRLE_DEBUG
+      rfbLog("zrleOutStreamOverrun: after deflate: %d bytes\n",
+	     os->zs.next_out - os->out.ptr);
+#endif
+
+      os->out.ptr = os->zs.next_out;
+    } while (os->zs.avail_out == 0);
+
+    /* output buffer not full */
+
+    if (os->zs.avail_in == 0) {
+      os->in.ptr = os->in.start;
+    } else {
+      /* but didn't consume all the data?  try shifting what's left to the
+       * start of the buffer.
+       */
+      rfbLog("zrleOutStreamOverrun: out buf not full, but in data not consumed\n");
+      memmove(os->in.start, os->zs.next_in, os->in.ptr - os->zs.next_in);
+      os->in.ptr -= os->zs.next_in - os->in.start;
+    }
+  }
+
+  if (size > os->in.end - os->in.ptr)
+    size = os->in.end - os->in.ptr;
+
+  return size;
+}
+
+static int zrleOutStreamCheck(zrleOutStream *os, int size)
+{
+  if (os->in.ptr + size > os->in.end) {
+    return zrleOutStreamOverrun(os, size);
+  }
+  return size;
+}
+
+void zrleOutStreamWriteBytes(zrleOutStream *os,
+			     const zrle_U8 *data,
+			     int            length)
+{
+  const zrle_U8* dataEnd = data + length;
+  while (data < dataEnd) {
+    int n = zrleOutStreamCheck(os, dataEnd - data);
+    memcpy(os->in.ptr, data, n);
+    os->in.ptr += n;
+    data += n;
+  }
+}
+
+void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u)
+{
+  zrleOutStreamCheck(os, 1);
+  *os->in.ptr++ = u;
+}
+
+void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u)
+{
+  zrleOutStreamCheck(os, 1);
+  *os->in.ptr++ = u;
+}
+
+void zrleOutStreamWriteOpaque16 (zrleOutStream *os, zrle_U16 u)
+{
+  zrleOutStreamCheck(os, 2);
+  *os->in.ptr++ = ((zrle_U8*)&u)[0];
+  *os->in.ptr++ = ((zrle_U8*)&u)[1];
+}
+
+void zrleOutStreamWriteOpaque32 (zrleOutStream *os, zrle_U32 u)
+{
+  zrleOutStreamCheck(os, 4);
+  *os->in.ptr++ = ((zrle_U8*)&u)[0];
+  *os->in.ptr++ = ((zrle_U8*)&u)[1];
+  *os->in.ptr++ = ((zrle_U8*)&u)[2];
+  *os->in.ptr++ = ((zrle_U8*)&u)[3];
+}
+
+void zrleOutStreamWriteOpaque24A(zrleOutStream *os, zrle_U32 u)
+{
+  zrleOutStreamCheck(os, 3);
+  *os->in.ptr++ = ((zrle_U8*)&u)[0];
+  *os->in.ptr++ = ((zrle_U8*)&u)[1];
+  *os->in.ptr++ = ((zrle_U8*)&u)[2];
+}
+
+void zrleOutStreamWriteOpaque24B(zrleOutStream *os, zrle_U32 u)
+{
+  zrleOutStreamCheck(os, 3);
+  *os->in.ptr++ = ((zrle_U8*)&u)[1];
+  *os->in.ptr++ = ((zrle_U8*)&u)[2];
+  *os->in.ptr++ = ((zrle_U8*)&u)[3];
+}
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleoutstream.h vnc_unixsrc/vncviewer/zrleoutstream.h
--- vnc_unixsrc.orig/vncviewer/zrleoutstream.h	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrleoutstream.h	2004-05-25 06:05:15.000000000 -0400
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 __ZRLE_OUT_STREAM_H__
+#define __ZRLE_OUT_STREAM_H__
+
+#include <zlib.h>
+#include "zrletypes.h"
+#include "rfb/rfb.h"
+
+typedef struct {
+  zrle_U8 *start;
+  zrle_U8 *ptr;
+  zrle_U8 *end;
+} zrleBuffer;
+
+typedef struct {
+  zrleBuffer in;
+  zrleBuffer out;
+
+  z_stream   zs;
+} zrleOutStream;
+
+#define ZRLE_BUFFER_LENGTH(b) ((b)->ptr - (b)->start)
+
+zrleOutStream *zrleOutStreamNew           (void);
+void           zrleOutStreamFree          (zrleOutStream *os);
+rfbBool        zrleOutStreamFlush         (zrleOutStream *os);
+void           zrleOutStreamWriteBytes    (zrleOutStream *os,
+					   const zrle_U8 *data,
+					   int            length);
+void           zrleOutStreamWriteU8       (zrleOutStream *os,
+					   zrle_U8        u);
+void           zrleOutStreamWriteOpaque8  (zrleOutStream *os,
+					   zrle_U8        u);
+void           zrleOutStreamWriteOpaque16 (zrleOutStream *os,
+					   zrle_U16       u);
+void           zrleOutStreamWriteOpaque32 (zrleOutStream *os,
+					   zrle_U32       u);
+void           zrleOutStreamWriteOpaque24A(zrleOutStream *os,
+					   zrle_U32       u);
+void           zrleOutStreamWriteOpaque24B(zrleOutStream *os,
+					   zrle_U32       u);
+
+#endif /* __ZRLE_OUT_STREAM_H__ */
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrlepalettehelper.c vnc_unixsrc/vncviewer/zrlepalettehelper.c
--- vnc_unixsrc.orig/vncviewer/zrlepalettehelper.c	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrlepalettehelper.c	2004-05-25 06:05:15.000000000 -0400
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include "zrlepalettehelper.h"
+#include <assert.h>
+#include <string.h>
+
+#define ZRLE_HASH(pix) (((pix) ^ ((pix) >> 17)) & 4095)
+
+void zrlePaletteHelperInit(zrlePaletteHelper *helper)
+{
+  memset(helper->palette, 0, sizeof(helper->palette));
+  memset(helper->index, 255, sizeof(helper->index));
+  memset(helper->key, 0, sizeof(helper->key));
+  helper->size = 0;
+}
+
+void zrlePaletteHelperInsert(zrlePaletteHelper *helper, zrle_U32 pix)
+{
+  if (helper->size < ZRLE_PALETTE_MAX_SIZE) {
+    int i = ZRLE_HASH(pix);
+
+    while (helper->index[i] != 255 && helper->key[i] != pix)
+      i++;
+    if (helper->index[i] != 255) return;
+
+    helper->index[i] = helper->size;
+    helper->key[i] = pix;
+    helper->palette[helper->size] = pix;
+  }
+  helper->size++;
+}
+
+int zrlePaletteHelperLookup(zrlePaletteHelper *helper, zrle_U32 pix)
+{
+  int i = ZRLE_HASH(pix);
+
+  assert(helper->size <= ZRLE_PALETTE_MAX_SIZE);
+  
+  while (helper->index[i] != 255 && helper->key[i] != pix)
+    i++;
+  if (helper->index[i] != 255) return helper->index[i];
+
+  return -1;
+}
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrlepalettehelper.h vnc_unixsrc/vncviewer/zrlepalettehelper.h
--- vnc_unixsrc.orig/vncviewer/zrlepalettehelper.h	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrlepalettehelper.h	2004-05-25 06:05:15.000000000 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+/*
+ * The PaletteHelper class helps us build up the palette from pixel data by
+ * storing a reverse index using a simple hash-table
+ */
+
+#ifndef __ZRLE_PALETTE_HELPER_H__
+#define __ZRLE_PALETTE_HELPER_H__
+
+#include "zrletypes.h"
+
+#define ZRLE_PALETTE_MAX_SIZE 127
+
+typedef struct {
+  zrle_U32  palette[ZRLE_PALETTE_MAX_SIZE];
+  zrle_U8   index[ZRLE_PALETTE_MAX_SIZE + 4096];
+  zrle_U32  key[ZRLE_PALETTE_MAX_SIZE + 4096];
+  int       size;
+} zrlePaletteHelper;
+
+void zrlePaletteHelperInit  (zrlePaletteHelper *helper);
+void zrlePaletteHelperInsert(zrlePaletteHelper *helper,
+			     zrle_U32           pix);
+int  zrlePaletteHelperLookup(zrlePaletteHelper *helper,
+			     zrle_U32           pix);
+
+#endif /* __ZRLE_PALETTE_HELPER_H__ */
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrletypes.h vnc_unixsrc/vncviewer/zrletypes.h
--- vnc_unixsrc.orig/vncviewer/zrletypes.h	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zrletypes.h	2004-05-25 06:05:15.000000000 -0400
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#ifndef __ZRLE_TYPES_H__
+#define __ZRLE_TYPES_H__
+
+typedef unsigned char  zrle_U8;
+typedef unsigned short zrle_U16;
+typedef unsigned int   zrle_U32;
+typedef signed char    zrle_S8;
+typedef signed short   zrle_S16;
+typedef signed int     zrle_S32;
+
+#endif /* __ZRLE_TYPES_H__ */
diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zywrletemplate.c vnc_unixsrc/vncviewer/zywrletemplate.c
--- vnc_unixsrc.orig/vncviewer/zywrletemplate.c	1969-12-31 19:00:00.000000000 -0500
+++ vnc_unixsrc/vncviewer/zywrletemplate.c	2008-02-15 23:33:13.000000000 -0500
@@ -0,0 +1,824 @@
+
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *                                                                 *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************/
+
+/* Change Log:
+     V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
+	                     (Thanks Johannes Schindelin, author of LibVNC
+						  Server/Client)
+     V0.01 : 2007/02/06 : Initial release
+*/
+
+/* #define ZYWRLE_ENCODE */
+/* #define ZYWRLE_DECODE */
+#define ZYWRLE_QUANTIZE
+
+/*
+[References]
+ PLHarr:
+   Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy, "An Improved N-Bit to N-Bit Reversible Haar-Like Transform," Pacific Graphics 2004, October 2004, pp. 371-380.
+ EZW:
+   Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients, IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
+*/
+
+
+/* Template Macro stuffs. */
+#undef ZYWRLE_ANALYZE
+#undef ZYWRLE_SYNTHESIZE
+#define ZYWRLE_ANALYZE __RFB_CONCAT3E(zywrleAnalyze,BPP,END_FIX)
+#define ZYWRLE_SYNTHESIZE __RFB_CONCAT3E(zywrleSynthesize,BPP,END_FIX)
+
+#define ZYWRLE_RGBYUV __RFB_CONCAT3E(zywrleRGBYUV,BPP,END_FIX)
+#define ZYWRLE_YUVRGB __RFB_CONCAT3E(zywrleYUVRGB,BPP,END_FIX)
+#define ZYWRLE_YMASK __RFB_CONCAT2E(ZYWRLE_YMASK,BPP)
+#define ZYWRLE_UVMASK __RFB_CONCAT2E(ZYWRLE_UVMASK,BPP)
+#define ZYWRLE_LOAD_PIXEL __RFB_CONCAT2E(ZYWRLE_LOAD_PIXEL,BPP)
+#define ZYWRLE_SAVE_PIXEL __RFB_CONCAT2E(ZYWRLE_SAVE_PIXEL,BPP)
+
+/* Packing/Unpacking pixel stuffs.
+   Endian conversion stuffs. */
+#undef S_0
+#undef S_1
+#undef L_0
+#undef L_1
+#undef L_2
+#if ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define S_0	1
+#  define S_1	0
+#  define L_0	3
+#  define L_1	2
+#  define L_2	1
+#else
+#  define S_0	0
+#  define S_1	1
+#  define L_0	0
+#  define L_1	1
+#  define L_2	2
+#endif
+
+/*   Load/Save pixel stuffs. */
+#define ZYWRLE_YMASK15  0xFFFFFFF8
+#define ZYWRLE_UVMASK15 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL15(pSrc,R,G,B) { \
+	R =  (((unsigned char*)pSrc)[S_1]<< 1)& 0xF8;	\
+	G = ((((unsigned char*)pSrc)[S_1]<< 6)|(((unsigned char*)pSrc)[S_0]>> 2))& 0xF8;	\
+	B =  (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8;	\
+}
+#define ZYWRLE_SAVE_PIXEL15(pDst,R,G,B) { \
+	R &= 0xF8;	\
+	G &= 0xF8;	\
+	B &= 0xF8;	\
+	((unsigned char*)pDst)[S_1] = (unsigned char)( (R>>1)|(G>>6)       );	\
+	((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<2))& 0xFF);	\
+}
+#define ZYWRLE_YMASK16  0xFFFFFFFC
+#define ZYWRLE_UVMASK16 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL16(pSrc,R,G,B) { \
+	R =   ((unsigned char*)pSrc)[S_1]     & 0xF8;	\
+	G = ((((unsigned char*)pSrc)[S_1]<< 5)|(((unsigned char*)pSrc)[S_0]>> 3))& 0xFC;	\
+	B =  (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8;	\
+}
+#define ZYWRLE_SAVE_PIXEL16(pDst,R,G,B) { \
+	R &= 0xF8;	\
+	G &= 0xFC;	\
+	B &= 0xF8;	\
+	((unsigned char*)pDst)[S_1] = (unsigned char)(  R    |(G>>5)       );	\
+	((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<3))& 0xFF);	\
+}
+#define ZYWRLE_YMASK32  0xFFFFFFFF
+#define ZYWRLE_UVMASK32 0xFFFFFFFF
+#define ZYWRLE_LOAD_PIXEL32(pSrc,R,G,B) { \
+	R = ((unsigned char*)pSrc)[L_2];	\
+	G = ((unsigned char*)pSrc)[L_1];	\
+	B = ((unsigned char*)pSrc)[L_0];	\
+}
+#define ZYWRLE_SAVE_PIXEL32(pDst,R,G,B) { \
+	((unsigned char*)pDst)[L_2] = (unsigned char)R;	\
+	((unsigned char*)pDst)[L_1] = (unsigned char)G;	\
+	((unsigned char*)pDst)[L_0] = (unsigned char)B;	\
+}
+
+#ifndef ZYWRLE_ONCE
+#define ZYWRLE_ONCE
+
+#ifdef WIN32
+#define InlineX __inline
+#else
+#define InlineX inline
+#endif
+
+#ifdef ZYWRLE_ENCODE
+/* Tables for Coefficients filtering. */
+#  ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+const static unsigned int zywrleParam[3][3]={
+	{0x0000F000,0x00000000,0x00000000},
+	{0x0000C000,0x00F0F0F0,0x00000000},
+	{0x0000C000,0x00C0C0C0,0x00F0F0F0},
+/*	{0x0000FF00,0x00000000,0x00000000},
+	{0x0000FF00,0x00FFFFFF,0x00000000},
+	{0x0000FF00,0x00FFFFFF,0x00FFFFFF}, */
+};
+#  else
+/* Type B:Non liner quantization filter. */
+static const signed char zywrleConv[4][256]={
+{	/* bi=5, bo=5 r=0.0:PSNR=24.849 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=5 r=2.0:PSNR=74.031 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 32,
+	32, 32, 32, 32, 32, 32, 32, 32,
+	32, 32, 32, 32, 32, 32, 32, 32,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 56, 56, 56, 56, 56,
+	56, 56, 56, 56, 64, 64, 64, 64,
+	64, 64, 64, 64, 72, 72, 72, 72,
+	72, 72, 72, 72, 80, 80, 80, 80,
+	80, 80, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 96, 96,
+	96, 96, 96, 104, 104, 104, 104, 104,
+	104, 104, 104, 104, 104, 112, 112, 112,
+	112, 112, 112, 112, 112, 112, 120, 120,
+	120, 120, 120, 120, 120, 120, 120, 120,
+	0, -120, -120, -120, -120, -120, -120, -120,
+	-120, -120, -120, -112, -112, -112, -112, -112,
+	-112, -112, -112, -112, -104, -104, -104, -104,
+	-104, -104, -104, -104, -104, -104, -96, -96,
+	-96, -96, -96, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -80,
+	-80, -80, -80, -80, -80, -72, -72, -72,
+	-72, -72, -72, -72, -72, -64, -64, -64,
+	-64, -64, -64, -64, -64, -56, -56, -56,
+	-56, -56, -56, -56, -56, -56, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, -32, -32, -32, -32, -32, -32, -32,
+	-32, -32, -32, -32, -32, -32, -32, -32,
+	-32, -32, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=4 r=2.0:PSNR=64.441 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	48, 48, 48, 48, 48, 48, 48, 48,
+	64, 64, 64, 64, 64, 64, 64, 64,
+	64, 64, 64, 64, 64, 64, 64, 64,
+	80, 80, 80, 80, 80, 80, 80, 80,
+	80, 80, 80, 80, 80, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	104, 104, 104, 104, 104, 104, 104, 104,
+	104, 104, 104, 112, 112, 112, 112, 112,
+	112, 112, 112, 112, 120, 120, 120, 120,
+	120, 120, 120, 120, 120, 120, 120, 120,
+	0, -120, -120, -120, -120, -120, -120, -120,
+	-120, -120, -120, -120, -120, -112, -112, -112,
+	-112, -112, -112, -112, -112, -112, -104, -104,
+	-104, -104, -104, -104, -104, -104, -104, -104,
+	-104, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -80, -80, -80, -80,
+	-80, -80, -80, -80, -80, -80, -80, -80,
+	-80, -64, -64, -64, -64, -64, -64, -64,
+	-64, -64, -64, -64, -64, -64, -64, -64,
+	-64, -48, -48, -48, -48, -48, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, -48, -48, -48, -48, -48, -48, -48,
+	-48, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+},
+{	/* bi=5, bo=2 r=2.0:PSNR=43.175 */
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	88, 88, 88, 88, 88, 88, 88, 88,
+	0, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, -88, -88, -88, -88, -88, -88, -88,
+	-88, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+}
+};
+const static signed char* zywrleParam[3][3][3]={
+	{{zywrleConv[0],zywrleConv[2],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
+	{{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
+	{{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[2],zywrleConv[2],zywrleConv[2]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]}},
+};
+#  endif
+#endif
+
+static InlineX void Harr(signed char* pX0, signed char* pX1)
+{
+	/* Piecewise-Linear Harr(PLHarr) */
+	int X0 = (int)*pX0, X1 = (int)*pX1;
+	int orgX0 = X0, orgX1 = X1;
+	if ((X0 ^ X1) & 0x80) {
+		/* differ sign */
+		X1 += X0;
+		if (((X1^orgX1)&0x80)==0) {
+			/* |X1| > |X0| */
+			X0 -= X1;	/* H = -B */
+		}
+	} else {
+		/* same sign */
+		X0 -= X1;
+		if (((X0 ^ orgX0) & 0x80) == 0) {
+			/* |X0| > |X1| */
+			X1 += X0;	/* L = A */
+		}
+	}
+	*pX0 = (signed char)X1;
+	*pX1 = (signed char)X0;
+}
+/*
+ 1D-Wavelet transform.
+
+ In coefficients array, the famous 'pyramid' decomposition is well used.
+
+ 1D Model:
+   |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
+   |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
+
+ But this method needs line buffer because H/L is different position from X0/X1.
+ So, I used 'interleave' decomposition instead of it.
+
+ 1D Model:
+   |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
+   |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
+
+ In this method, H/L and X0/X1 is always same position.
+ This lead us to more speed and less memory.
+ Of cause, the result of both method is quite same
+ because it's only difference that coefficient position.
+*/
+static InlineX void WaveletLevel(int* data, int size, int l, int SkipPixel)
+{
+	int s, ofs;
+	signed char* pX0;
+	signed char* end;
+
+	pX0 = (signed char*)data;
+	s = (8<<l)*SkipPixel;
+	end = pX0+(size>>(l+1))*s;
+	s -= 2;
+	ofs = (4<<l)*SkipPixel;
+	while (pX0 < end) {
+		Harr(pX0, pX0+ofs);
+		pX0++;
+		Harr(pX0, pX0+ofs);
+		pX0++;
+		Harr(pX0, pX0+ofs);
+		pX0 += s;
+	}
+}
+#define InvWaveletLevel(d,s,l,pix) WaveletLevel(d,s,l,pix)
+
+#ifdef ZYWRLE_ENCODE
+#  ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
+{
+	int r, s;
+	int x, y;
+	int* pH;
+	const unsigned int* pM;
+
+	pM = &(zywrleParam[level-1][l]);
+	s = 2<<l;
+	for (r = 1; r < 4; r++) {
+		pH   = pBuf;
+		if (r & 0x01)
+			pH +=  s>>1;
+		if (r & 0x02)
+			pH += (s>>1)*width;
+		for (y = 0; y < height / s; y++) {
+			for (x = 0; x < width / s; x++) {
+				/*
+				 these are same following code.
+				     pH[x] = pH[x] / (~pM[x]+1) * (~pM[x]+1);
+				     ( round pH[x] with pM[x] bit )
+				 '&' operator isn't 'round' but is 'floor'.
+				 So, we must offset when pH[x] is negative.
+				*/
+				if (((signed char*)pH)[0] & 0x80)
+					((signed char*)pH)[0] += ~((signed char*)pM)[0];
+				if (((signed char*)pH)[1] & 0x80)
+					((signed char*)pH)[1] += ~((signed char*)pM)[1];
+				if (((signed char*)pH)[2] & 0x80)
+					((signed char*)pH)[2] += ~((signed char*)pM)[2];
+				*pH &= *pM;
+				pH += s;
+			}
+			pH += (s-1)*width;
+		}
+	}
+}
+#  else
+/*
+ Type B:Non liner quantization filter.
+
+ Coefficients have Gaussian curve and smaller value which is
+ large part of coefficients isn't more important than larger value.
+ So, I use filter of Non liner quantize/dequantize table.
+ In general, Non liner quantize formula is explained as following.
+
+    y=f(x)   = sign(x)*round( ((abs(x)/(2^7))^ r   )* 2^(bo-1) )*2^(8-bo)
+    x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
+ ( r:power coefficient  bi:effective MSB in input  bo:effective MSB in output )
+
+   r < 1.0 : Smaller value is more important than larger value.
+   r > 1.0 : Larger value is more important than smaller value.
+   r = 1.0 : Liner quantization which is same with EZW style.
+
+ r = 0.75 is famous non liner quantization used in MP3 audio codec.
+ In contrast to audio data, larger value is important in wavelet coefficients.
+ So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
+
+ As compared with EZW style liner quantization, this filter tended to be
+ more sharp edge and be more compression rate but be more blocking noise and be less quality.
+ Especially, the surface of graphic objects has distinguishable noise in middle quality mode.
+
+ We need only quantized-dequantized(filtered) value rather than quantized value itself
+ because all values are packed or palette-lized in later ZRLE section.
+ This lead us not to need to modify client decoder when we change
+ the filtering procedure in future.
+ Client only decodes coefficients given by encoder.
+*/
+static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
+{
+	int r, s;
+	int x, y;
+	int* pH;
+	const signed char** pM;
+
+	pM = zywrleParam[level-1][l];
+	s = 2<<l;
+	for (r = 1; r < 4; r++) {
+		pH   = pBuf;
+		if (r & 0x01)
+			pH +=  s>>1;
+		if (r & 0x02)
+			pH += (s>>1)*width;
+		for (y = 0; y < height / s; y++) {
+			for (x = 0; x < width / s; x++) {
+				((signed char*)pH)[0] = pM[0][((unsigned char*)pH)[0]];
+				((signed char*)pH)[1] = pM[1][((unsigned char*)pH)[1]];
+				((signed char*)pH)[2] = pM[2][((unsigned char*)pH)[2]];
+				pH += s;
+			}
+			pH += (s-1)*width;
+		}
+	}
+}
+#  endif
+
+static InlineX void Wavelet(int* pBuf, int width, int height, int level)
+{
+	int l, s;
+	int* pTop;
+	int* pEnd;
+
+	for (l = 0; l < level; l++) {
+		pTop = pBuf;
+		pEnd = pBuf+height*width;
+		s = width<<l;
+		while (pTop < pEnd) {
+			WaveletLevel(pTop, width, l, 1);
+			pTop += s;
+		}
+		pTop = pBuf;
+		pEnd = pBuf+width;
+		s = 1<<l;
+		while (pTop < pEnd) {
+			WaveletLevel(pTop, height,l, width);
+			pTop += s;
+		}
+		FilterWaveletSquare(pBuf, width, height, level, l);
+	}
+}
+#endif
+#ifdef ZYWRLE_DECODE
+static InlineX void InvWavelet(int* pBuf, int width, int height, int level)
+{
+	int l, s;
+	int* pTop;
+	int* pEnd;
+
+	for (l = level - 1; l >= 0; l--) {
+		pTop = pBuf;
+		pEnd = pBuf+width;
+		s = 1<<l;
+		while (pTop < pEnd) {
+			InvWaveletLevel(pTop, height,l, width);
+			pTop += s;
+		}
+		pTop = pBuf;
+		pEnd = pBuf+height*width;
+		s = width<<l;
+		while (pTop < pEnd) {
+			InvWaveletLevel(pTop, width, l, 1);
+			pTop += s;
+		}
+	}
+}
+#endif
+
+/* Load/Save coefficients stuffs.
+ Coefficients manages as 24 bits little-endian pixel. */
+#define ZYWRLE_LOAD_COEFF(pSrc,R,G,B) { \
+	R = ((signed char*)pSrc)[2];	\
+	G = ((signed char*)pSrc)[1];	\
+	B = ((signed char*)pSrc)[0];	\
+}
+#define ZYWRLE_SAVE_COEFF(pDst,R,G,B) { \
+	((signed char*)pDst)[2] = (signed char)R;	\
+	((signed char*)pDst)[1] = (signed char)G;	\
+	((signed char*)pDst)[0] = (signed char)B;	\
+}
+
+/*
+ RGB <=> YUV conversion stuffs.
+ YUV coversion is explained as following formula in strict meaning:
+   Y =  0.299R + 0.587G + 0.114B (   0<=Y<=255)
+   U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
+   V =  0.500R - 0.419G - 0.081B (-128<=V<=127)
+
+ I use simple conversion RCT(reversible color transform) which is described
+ in JPEG-2000 specification.
+   Y = (R + 2G + B)/4 (   0<=Y<=255)
+   U = B-G (-256<=U<=255)
+   V = R-G (-256<=V<=255)
+*/
+#define ROUND(x) (((x)<0)?0:(((x)>255)?255:(x)))
+	/* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
+	 For make Same N-bit, UV is lossy.
+	 More exact PLHarr, we reduce to odd range(-127<=x<=127). */
+#define ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ymask,uvmask) { \
+	Y = (R+(G<<1)+B)>>2;	\
+	U =  B-G;	\
+	V =  R-G;	\
+	Y -= 128;	\
+	U >>= 1;	\
+	V >>= 1;	\
+	Y &= ymask;	\
+	U &= uvmask;	\
+	V &= uvmask;	\
+	if (Y == -128)	\
+		Y += (0xFFFFFFFF-ymask+1);	\
+	if (U == -128)	\
+		U += (0xFFFFFFFF-uvmask+1);	\
+	if (V == -128)	\
+		V += (0xFFFFFFFF-uvmask+1);	\
+}
+#define ZYWRLE_YUVRGB1(R,G,B,Y,U,V) { \
+	Y += 128;	\
+	U <<= 1;	\
+	V <<= 1;	\
+	G = Y-((U+V)>>2);	\
+	B = U+G;	\
+	R = V+G;	\
+	G = ROUND(G);	\
+	B = ROUND(B);	\
+	R = ROUND(R);	\
+}
+
+/*
+ coefficient packing/unpacking stuffs.
+ Wavelet transform makes 4 sub coefficient image from 1 original image.
+
+ model with pyramid decomposition:
+   +------+------+
+   |      |      |
+   |  L   |  Hx  |
+   |      |      |
+   +------+------+
+   |      |      |
+   |  H   |  Hxy |
+   |      |      |
+   +------+------+
+
+ So, we must transfer each sub images individually in strict meaning.
+ But at least ZRLE meaning, following one decompositon image is same as
+ avobe individual sub image. I use this format.
+ (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
+  for simplified procedure for any wavelet level.)
+
+   +------+------+
+   |      L      |
+   +------+------+
+   |      Hx     |
+   +------+------+
+   |      Hy     |
+   +------+------+
+   |      Hxy    |
+   +------+------+
+*/
+#define INC_PTR(data) \
+	data++;	\
+	if( data-pData >= (w+uw) ){	\
+		data += scanline-(w+uw);	\
+		pData = data;	\
+	}
+
+#define ZYWRLE_TRANSFER_COEFF(pBuf,data,r,w,h,scanline,level,TRANS)	\
+	pH = pBuf;	\
+	s = 2<<level;	\
+	if (r & 0x01)	\
+		pH +=  s>>1;	\
+	if (r & 0x02)	\
+		pH += (s>>1)*w;	\
+	pEnd = pH+h*w;	\
+	while (pH < pEnd) {	\
+		pLine = pH+w;	\
+		while (pH < pLine) {	\
+			TRANS	\
+			INC_PTR(data)	\
+			pH += s;	\
+		}	\
+		pH += (s-1)*w;	\
+	}
+
+#define ZYWRLE_PACK_COEFF(pBuf,data,r,width,height,scanline,level)	\
+	ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_COEFF(pH,R,G,B);ZYWRLE_SAVE_PIXEL(data,R,G,B);)
+
+#define ZYWRLE_UNPACK_COEFF(pBuf,data,r,width,height,scanline,level)	\
+	ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_PIXEL(data,R,G,B);ZYWRLE_SAVE_COEFF(pH,R,G,B);)
+
+#define ZYWRLE_SAVE_UNALIGN(data,TRANS)	\
+	pTop = pBuf+w*h;	\
+	pEnd = pBuf + (w+uw)*(h+uh);	\
+	while (pTop < pEnd) {	\
+		TRANS	\
+		INC_PTR(data)	\
+		pTop++;	\
+	}
+
+#define ZYWRLE_LOAD_UNALIGN(data,TRANS)	\
+	pTop = pBuf+w*h;	\
+	if (uw) {	\
+		pData=         data + w;	\
+		pEnd = (int*)(pData+ h*scanline);	\
+		while (pData < (PIXEL_T*)pEnd) {	\
+			pLine = (int*)(pData + uw);	\
+			while (pData < (PIXEL_T*)pLine) {	\
+				TRANS	\
+				pData++;	\
+				pTop++;	\
+			}	\
+			pData += scanline-uw;	\
+		}	\
+	}	\
+	if (uh) {	\
+		pData=         data +  h*scanline;	\
+		pEnd = (int*)(pData+ uh*scanline);	\
+		while (pData < (PIXEL_T*)pEnd) {	\
+			pLine = (int*)(pData + w);	\
+			while (pData < (PIXEL_T*)pLine) {	\
+				TRANS	\
+				pData++;	\
+				pTop++;	\
+			}	\
+			pData += scanline-w;	\
+		}	\
+	}	\
+	if (uw && uh) {	\
+		pData=         data + w+ h*scanline;	\
+		pEnd = (int*)(pData+   uh*scanline);	\
+		while (pData < (PIXEL_T*)pEnd) {	\
+			pLine = (int*)(pData + uw);	\
+			while (pData < (PIXEL_T*)pLine) {	\
+				TRANS	\
+				pData++;	\
+				pTop++;	\
+			}	\
+			pData += scanline-uw;	\
+		}	\
+	}
+
+static InlineX void zywrleCalcSize(int* pW, int* pH, int level)
+{
+	*pW &= ~((1<<level)-1);
+	*pH &= ~((1<<level)-1);
+}
+
+#endif /* ZYWRLE_ONCE */
+
+#ifndef CPIXEL
+#ifdef ZYWRLE_ENCODE
+static InlineX void ZYWRLE_RGBYUV(int* pBuf, PIXEL_T* data, int width, int height, int scanline)
+{
+	int R, G, B;
+	int Y, U, V;
+	int* pLine;
+	int* pEnd;
+	pEnd = pBuf+height*width;
+	while (pBuf < pEnd) {
+		pLine = pBuf+width;
+		while (pBuf < pLine) {
+			ZYWRLE_LOAD_PIXEL(data,R,G,B);
+			ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ZYWRLE_YMASK,ZYWRLE_UVMASK);
+			ZYWRLE_SAVE_COEFF(pBuf,V,Y,U);
+			pBuf++;
+			data++;
+		}
+		data += scanline-width;
+	}
+}
+#endif
+#ifdef ZYWRLE_DECODE
+static InlineX void ZYWRLE_YUVRGB(int* pBuf, PIXEL_T* data, int width, int height, int scanline) {
+	int R, G, B;
+	int Y, U, V;
+	int* pLine;
+	int* pEnd;
+	pEnd = pBuf+height*width;
+	while (pBuf < pEnd) {
+		pLine = pBuf+width;
+		while (pBuf < pLine) {
+			ZYWRLE_LOAD_COEFF(pBuf,V,Y,U);
+			ZYWRLE_YUVRGB1(R,G,B,Y,U,V);
+			ZYWRLE_SAVE_PIXEL(data,R,G,B);
+			pBuf++;
+			data++;
+		}
+		data += scanline-width;
+	}
+}
+#endif
+
+#ifdef ZYWRLE_ENCODE
+PIXEL_T* ZYWRLE_ANALYZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf) {
+	int l;
+	int uw = w;
+	int uh = h;
+	int* pTop;
+	int* pEnd;
+	int* pLine;
+	PIXEL_T* pData;
+	int R, G, B;
+	int s;
+	int* pH;
+
+	zywrleCalcSize(&w, &h, level);
+	if (w == 0 || h == 0)
+		return NULL;
+	uw -= w;
+	uh -= h;
+
+	pData = dst;
+	ZYWRLE_LOAD_UNALIGN(src,*(PIXEL_T*)pTop=*pData;)
+	ZYWRLE_RGBYUV(pBuf, src, w, h, scanline);
+	Wavelet(pBuf, w, h, level);
+	for (l = 0; l < level; l++) {
+		ZYWRLE_PACK_COEFF(pBuf, dst, 3, w, h, scanline, l);
+		ZYWRLE_PACK_COEFF(pBuf, dst, 2, w, h, scanline, l);
+		ZYWRLE_PACK_COEFF(pBuf, dst, 1, w, h, scanline, l);
+		if (l == level - 1) {
+			ZYWRLE_PACK_COEFF(pBuf, dst, 0, w, h, scanline, l);
+		}
+	}
+	ZYWRLE_SAVE_UNALIGN(dst,*dst=*(PIXEL_T*)pTop;)
+	return dst;
+}
+#endif
+#ifdef ZYWRLE_DECODE
+PIXEL_T* ZYWRLE_SYNTHESIZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf)
+{
+	int l;
+	int uw = w;
+	int uh = h;
+	int* pTop;
+	int* pEnd;
+	int* pLine;
+	PIXEL_T* pData;
+	int R, G, B;
+	int s;
+	int* pH;
+
+	zywrleCalcSize(&w, &h, level);
+	if (w == 0 || h == 0)
+		return NULL;
+	uw -= w;
+	uh -= h;
+
+	pData = src;
+	for (l = 0; l < level; l++) {
+		ZYWRLE_UNPACK_COEFF(pBuf, src, 3, w, h, scanline, l);
+		ZYWRLE_UNPACK_COEFF(pBuf, src, 2, w, h, scanline, l);
+		ZYWRLE_UNPACK_COEFF(pBuf, src, 1, w, h, scanline, l);
+		if (l == level - 1) {
+			ZYWRLE_UNPACK_COEFF(pBuf, src, 0, w, h, scanline, l);
+		}
+	}
+	ZYWRLE_SAVE_UNALIGN(src,*(PIXEL_T*)pTop=*src;)
+	InvWavelet(pBuf, w, h, level);
+	ZYWRLE_YUVRGB(pBuf, dst, w, h, scanline);
+	ZYWRLE_LOAD_UNALIGN(dst,*pData=*(PIXEL_T*)pTop;)
+	return src;
+}
+#endif
+#endif  /* CPIXEL */
+
+#undef ZYWRLE_RGBYUV
+#undef ZYWRLE_YUVRGB
+#undef ZYWRLE_LOAD_PIXEL
+#undef ZYWRLE_SAVE_PIXEL
diff -Naur -X ./exclude vnc_unixsrc.orig/include/rfbproto.h vnc_unixsrc/include/rfbproto.h
--- vnc_unixsrc.orig/include/rfbproto.h	2004-05-27 03:02:02.000000000 -0400
+++ vnc_unixsrc/include/rfbproto.h	2010-02-25 21:54:58.000000000 -0500
@@ -205,7 +205,22 @@
 #define rfbSecTypeInvalid 0
 #define rfbSecTypeNone 1
 #define rfbSecTypeVncAuth 2
+#define rfbSecTypeRA2 5
+#define rfbSecTypeRA2ne 6
 #define rfbSecTypeTight 16
+#define rfbSecTypeUltra 17
+
+/* try to support VeNCrypt and TLS */
+#define rfbSecTypeAnonTls  18
+#define rfbSecTypeVencrypt 19
+
+#define rfbVencryptPlain        256
+#define rfbVencryptTlsNone      257
+#define rfbVencryptTlsVnc       258
+#define rfbVencryptTlsPlain     259
+#define rfbVencryptX509None     260
+#define rfbVencryptX509Vnc      261
+#define rfbVencryptX509Plain    262
 
 
 /*-----------------------------------------------------------------------------
@@ -381,6 +396,11 @@
 #define rfbBell 2
 #define rfbServerCutText 3
 
+#define rfbResizeFrameBuffer 4 /* Modif sf@2002 */
+
+/* http://sourceforge.net/projects/vncsessmgr */
+#define rfbRestartConnection 82
+
 #define rfbFileListData 130
 #define rfbFileDownloadData 131
 #define rfbFileUploadCancel 132
@@ -403,6 +423,18 @@
 #define rfbPointerEvent 5
 #define rfbClientCutText 6
 
+/* ultra */
+
+#define rfbFileTransfer 7
+#define rfbSetScale 8
+#define rfbSetServerInput 9
+#define rfbSetSW 10
+#define rfbTextChat 11
+#define rfbKeyFrameRequest 12
+#define rfbPalmVNCSetScaleFactor 0xF
+
+
+
 #define rfbFileListRequest 130
 #define rfbFileDownloadRequest 131
 #define rfbFileUploadRequest 132
@@ -435,6 +467,13 @@
 #define rfbEncodingTight     7
 #define rfbEncodingZlibHex   8
 
+#define rfbEncodingZRLE 16
+/*
+nyama/2006/08/02:new YUV-Wavlet lossy codec based on ZRLE (ZYWRLE)
+ */
+#define rfbEncodingZYWRLE 17
+
+
 /* signatures for basic encoding types */
 #define sig_rfbEncodingRaw       "RAW_____"
 #define sig_rfbEncodingCopyRect  "COPYRECT"
@@ -955,6 +994,51 @@
 #define sz_rfbFileDownloadFailedMsg 4
 
 /*-----------------------------------------------------------------------------
+ * RestartConnection - the server has restarted the client connection.
+ */
+
+typedef struct _rfbRestartConnectionMsg {
+    CARD8 type;			/* always rfbRestartConnection */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbRestartConnectionMsg;
+
+#define sz_rfbRestartConnectionMsg 8
+
+
+typedef struct _rfbTextChatMsg {
+    CARD8 type;                 /* always rfbTextChat */
+    CARD8 pad1;         /* Could be used later as an additionnal param */
+    CARD16 pad2;                /* Could be used later as text offset, for instance */
+    CARD32 length;      /* Specific values for Open, close, finished (-1, -2, -3) */
+    /* followed by char text[length] */
+} rfbTextChatMsg;
+
+#define sz_rfbTextChatMsg 8
+
+#define rfbTextMaxSize          4096
+#define rfbTextChatOpen         0xFFFFFFFF 
+#define rfbTextChatClose        0xFFFFFFFE  
+#define rfbTextChatFinished 0xFFFFFFFD  
+
+/*-----------------------------------------------------------------------------
+ * Modif sf@2002
+ * ResizeFrameBuffer - The Client must change the size of its framebuffer  
+ */
+
+typedef struct _rfbResizeFrameBufferMsg {
+    CARD8 type;                 /* always rfbResizeFrameBuffer */
+        CARD8 pad1;
+        CARD16 framebufferWidth;        /* FrameBuffer width */
+        CARD16 framebufferHeight;       /* FrameBuffer height */
+} rfbResizeFrameBufferMsg;
+
+#define sz_rfbResizeFrameBufferMsg 6
+
+
+/*-----------------------------------------------------------------------------
  * Union of all server->client messages.
  */
 
@@ -968,6 +1052,8 @@
     rfbFileDownloadDataMsg fdd;
     rfbFileUploadCancelMsg fuc;
     rfbFileDownloadFailedMsg fdf;
+    rfbRestartConnectionMsg rc;
+	rfbTextChatMsg tc;
 } rfbServerToClientMsg;
 
 
@@ -1221,6 +1307,41 @@
 
 #define sz_rfbFileCreateDirRequestMsg 4
 
+/* ultra */
+typedef struct _rfbSetScaleMsg {
+    CARD8 type;                 /* always rfbSetScale */
+    CARD8 scale;                /* Scale value 1<sv<n */
+    CARD16 pad;
+} rfbSetScaleMsg;
+
+#define sz_rfbSetScaleMsg 4
+
+typedef struct {
+    CARD8 type;                 /* always rfbSetScaleFactor */
+
+    CARD8 scale;                /* Scale factor (positive non-zero integer) */
+    CARD16 pad2;
+} rfbPalmVNCSetScaleFactorMsg;
+
+#define sz_rfbPalmVNCSetScaleFactorMsg (4)
+
+typedef struct _rfbSetServerInputMsg {
+    CARD8 type;                 /* always rfbSetServerInputMsg */
+    CARD8 status;               /* on or off */
+    CARD16 pad;
+} rfbSetServerInputMsg;
+
+#define sz_rfbSetServerInputMsg 4
+
+typedef struct _rfbSetSWMsg {
+    CARD8 type;                 /* always rfbSetSW */
+    CARD8 status;
+    CARD16 x;
+    CARD16 y;
+} rfbSetSWMsg;
+
+#define sz_rfbSetSWMsg 6
+
 /*-----------------------------------------------------------------------------
  * Union of all client->server messages.
  */
@@ -1241,4 +1362,9 @@
     rfbFileDownloadCancelMsg fdc;
     rfbFileUploadFailedMsg fuf;
     rfbFileCreateDirRequestMsg fcdr;
+	rfbSetScaleMsg ssc;
+	rfbPalmVNCSetScaleFactorMsg pssf;
+	rfbSetServerInputMsg sim;
+	rfbSetSWMsg sw;
+	rfbTextChatMsg tc;
 } rfbClientToServerMsg;
diff -Naur -X ./exclude vnc_unixsrc.orig/include/vncauth.h vnc_unixsrc/include/vncauth.h
--- vnc_unixsrc.orig/include/vncauth.h	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/include/vncauth.h	2009-03-21 00:37:23.000000000 -0400
@@ -23,8 +23,11 @@
 
 #define MAXPWLEN 8
 #define CHALLENGESIZE 16
+#define CHALLENGESIZE_MSLOGON 64
 
 extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
 extern char *vncDecryptPasswdFromFile(char *fname);
 extern void vncRandomBytes(unsigned char *bytes);
 extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
+
+extern void vncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd);
diff -Naur -X ./exclude vnc_unixsrc.orig/libvncauth/d3des.c vnc_unixsrc/libvncauth/d3des.c
--- vnc_unixsrc.orig/libvncauth/d3des.c	2000-06-11 08:00:53.000000000 -0400
+++ vnc_unixsrc/libvncauth/d3des.c	2010-02-25 21:49:02.000000000 -0500
@@ -34,12 +34,15 @@
 static void cookey(unsigned long *);
 
 static unsigned long KnL[32] = { 0L };
+/* no londer used: */
+#if 0
 static unsigned long KnR[32] = { 0L };
 static unsigned long Kn3[32] = { 0L };
 static unsigned char Df_Key[24] = {
 	0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
 	0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
 	0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
+#endif
 
 static unsigned short bytebit[8]	= {
 	01, 02, 04, 010, 020, 040, 0100, 0200 };
diff -Naur -X ./exclude vnc_unixsrc.orig/libvncauth/vncauth.c vnc_unixsrc/libvncauth/vncauth.c
--- vnc_unixsrc.orig/libvncauth/vncauth.c	2003-03-01 11:48:06.000000000 -0500
+++ vnc_unixsrc/libvncauth/vncauth.c	2010-02-25 21:47:25.000000000 -0500
@@ -27,9 +27,11 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <time.h>
 #include <vncauth.h>
 #include <d3des.h>
 
+#include <fcntl.h>
 
 /*
  * Make sure we call srandom() only once.
@@ -45,6 +47,8 @@
 
 static unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7};
 
+int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname);
+int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly);
 
 /*
  * Encrypt a password and store it in a file.  Returns 0 if successful,
@@ -73,7 +77,7 @@
 vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname)
 {
     FILE *fp;
-    int i, bytesToWrite, bytesWrote;
+    int bytesToWrite, bytesWrote;
     unsigned char encryptedPasswd[16] = {
 	0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0
@@ -195,6 +199,44 @@
     return (i < 16) ? 1 : 2;
 }
 
+unsigned int urandom(void) {
+	unsigned int val = 0;
+	struct stat sb;
+	int fd = -1;
+	if (fd < 0 && stat("/dev/urandom", &sb) == 0) {
+		fd = open("/dev/urandom", O_RDONLY);
+	}
+	if (fd < 0 && stat("/dev/random", &sb) == 0) {
+		fd = open("/dev/random", O_RDONLY);
+	}
+	if (fd < 0 && stat("/proc/loadavg", &sb) == 0) {
+		fd = open("/proc/loadavg", O_RDONLY);
+	}
+	if (fd < 0 && stat("/bin/bash", &sb) == 0) {
+		fd = open("/bin/bash", O_RDONLY);
+		lseek(fd, (off_t) (unsigned int) getpid(), SEEK_SET);
+	}
+	if (fd >= 0) {
+		int i;
+		for (i=0; i < 3; i++) {
+			char buf[2];
+			if (read(fd, buf, 1) > 0) {
+				unsigned char uc = (unsigned char) buf[0];  
+				if (i==0) {
+					val += uc; 
+				} else if (i==1) {
+					val += uc * 256; 
+				} else if (i==2) {
+					val += uc * 256 * 256; 
+				}
+			}
+		}
+		close(fd);
+	} else {
+		val = (unsigned int) getpid();
+	}
+	return val;
+}
 
 /*
  * Generate CHALLENGESIZE random bytes for use in challenge-response
@@ -207,11 +249,13 @@
     int i;
     unsigned int seed;
 
-    if (!s_srandom_called) {
-      seed = (unsigned int)time(0) ^ (unsigned int)getpid();
-      srandom(seed);
-      s_srandom_called = 1;
-    }
+	if (!s_srandom_called) {
+		seed = (unsigned int)time(0) ^ (unsigned int)getpid();
+		seed += urandom();
+
+		srandom(seed);
+		s_srandom_called = 1;
+	}
 
     for (i = 0; i < CHALLENGESIZE; i++) {
 	bytes[i] = (unsigned char)(random() & 255);    
@@ -245,3 +289,48 @@
 	des(bytes+i, bytes+i);
     }
 }
+
+void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd) {
+	unsigned int i;
+	for (i=0; i < 32; i++) {
+		if (i < strlen(passwd)) {
+			encryptedPasswd[i] = passwd[i];
+		} else {
+			encryptedPasswd[i] = '\0';
+		}
+	}
+	deskey(s_fixedkey, EN0);
+	des(encryptedPasswd, encryptedPasswd);
+}
+
+void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key) {
+	int i, j;
+	deskey(key, EN0);
+	for (i=0; i < 8; i++) {
+		where[i] ^= key[i];
+	}
+	des(where, where);
+	for (i=8; i < length; i += 8) {
+		for (j=0; j < 8; j++) {
+			where[i+j] ^= where[i+j-8];
+		}
+		des(where+i, where+i);
+	}
+}
+
+void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key) {
+	int i, j;
+	deskey(key, DE1);
+	for (i = length - 8; i > 0; i -= 8) {
+		des(where + i, where + i);
+		for (j=0; j < 8; j++) {
+			where[i+j] ^= where[i+j-8];
+		}
+	}
+	/* i=0 */
+	des(where, where);
+	for (i=0; i < 8; i++) {
+		where[i] ^= key[i];
+	}
+}
+
