From 9903dac004a98b47d9ede275e10cb3820c8983af Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 6 Jul 2007 17:46:50 -0400 Subject: [PATCH 1/2] Initial prototype switching code over to using GTK VNC --- README | 1 + configure.ac | 1 - src/Makefile.am | 2 +- src/virtManager/console.py | 163 +++++---- src/vncViewer/Makefile.am | 5 - src/vncViewer/__init__.py | 18 - src/vncViewer/crippled_des.py | 481 ------------------------- src/vncViewer/rfb.py | 566 ----------------------------- src/vncViewer/vnc.py | 659 ---------------------------------- virt-manager.spec.in | 6 +- 10 files changed, 98 insertions(+), 1804 deletions(-) delete mode 100644 src/vncViewer/Makefile.am delete mode 100644 src/vncViewer/__init__.py delete mode 100644 src/vncViewer/crippled_des.py delete mode 100644 src/vncViewer/rfb.py delete mode 100755 src/vncViewer/vnc.py diff --git a/README b/README index a8f67da1..64989ee7 100644 --- a/README +++ b/README @@ -34,6 +34,7 @@ please report any success to the mailing lists gnome-python-desktop >= 2.15.4 libxml2-python >= 2.6.23 vte >= 0.12.2 + gtk-vnc >= 0.0.1 python-virtinst >= 0.103.0 The latter is available from diff --git a/configure.ac b/configure.ac index b9a47ab8..cd308a58 100644 --- a/configure.ac +++ b/configure.ac @@ -30,7 +30,6 @@ AC_OUTPUT(Makefile po/Makefile.in src/Makefile src/virtManager/Makefile - src/vncViewer/Makefile src/graphWidgets/Makefile virt-manager.spec help/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 50951b04..35a32e8f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = vncViewer graphWidgets virtManager +SUBDIRS = graphWidgets virtManager bin_SOURCES = virt-manager.in bin_SCRIPTS = virt-manager diff --git a/src/virtManager/console.py b/src/virtManager/console.py index 405715b8..990aafa9 100644 --- a/src/virtManager/console.py +++ b/src/virtManager/console.py @@ -25,9 +25,14 @@ import sys import logging import dbus import traceback +import gtkvnc from virtManager.error import vmmErrorDialog -from vncViewer.vnc import GRFBViewer + +PAGE_UNAVAILABLE = 0 +PAGE_SCREENSHOT = 1 +PAGE_AUTHENTICATE = 2 +PAGE_VNCVIEWER = 3 class vmmConsole(gobject.GObject): __gsignals__ = { @@ -55,15 +60,19 @@ class vmmConsole(gobject.GObject): self.window.get_widget("control-shutdown").set_icon_widget(gtk.Image()) self.window.get_widget("control-shutdown").get_icon_widget().set_from_file(config.get_icon_dir() + "/icon_shutdown.png") + self.vncViewer = gtkvnc.Display() if self.config.get_console_keygrab() == 2: - self.vncViewer = GRFBViewer(topwin, autograbkey=True) - else: - self.vncViewer = GRFBViewer(topwin, autograbkey=False) - self.vncViewer.connect("pointer-grabbed", self.notify_grabbed) - self.vncViewer.connect("pointer-ungrabbed", self.notify_ungrabbed) + self.vncViewer.set_keyboard_grab(True) + + self.vncViewer.set_pointer_grab(True) + self.vncViewer.set_sticky_modifiers(True) + + self.vncViewer.connect("vnc-pointer-grab", self.notify_grabbed) + self.vncViewer.connect("vnc-pointer-ungrab", self.notify_ungrabbed) self.window.get_widget("console-vnc-align").add(self.vncViewer) self.vncViewer.connect("size-request", self.autosize) + self.vncViewer.realize() self.vncViewer.show() self.vncViewerFailures = 0 self.vncViewerRetryDelay = 125 @@ -106,13 +115,15 @@ class vmmConsole(gobject.GObject): "on_menu_vm_close_activate": self.close, - "on_console_auth_login_clicked": self.try_login, + "on_console_auth_login_clicked": self.set_password, "on_console_help_activate": self.show_help, }) self.vm.connect("status-changed", self.update_widget_states) - self.vncViewer.connect("disconnected", self._vnc_disconnected) + self.vncViewer.connect("vnc-auth-credential", self._vnc_auth_credential) + self.vncViewer.connect("vnc-initialized", self._vnc_initialized) + self.vncViewer.connect("vnc-disconnected", self._vnc_disconnected) # Auto-increase the window size to fit the console - within reason # though, cos we don't want a min window size greater than the screen @@ -169,18 +180,18 @@ class vmmConsole(gobject.GObject): def keygrab_changed(self, src, ignore1=None,ignore2=None,ignore3=None): if self.config.get_console_keygrab() == 2: - self.vncViewer.set_autograb_keyboard(True) + self.vncViewer.set_keyboard_grab(True) else: - self.vncViewer.set_autograb_keyboard(False) + self.vncViewer.set_keyboard_grab(False) def toggle_fullscreen(self, src): if src.get_active(): self.window.get_widget("vmm-console").fullscreen() - if self.config.get_console_keygrab() == 1: - self.vncViewer.grab_keyboard() + #if self.config.get_console_keygrab() == 1: + # self.vncViewer.grab_keyboard() else: - if self.config.get_console_keygrab() == 1: - self.vncViewer.ungrab_keyboard() + #if self.config.get_console_keygrab() == 1: + # self.vncViewer.ungrab_keyboard() self.window.get_widget("vmm-console").unfullscreen() def toggle_toolbar(self, src): @@ -193,7 +204,6 @@ class vmmConsole(gobject.GObject): dialog = self.window.get_widget("vmm-console") dialog.show_all() dialog.present() - self.try_login() self.update_widget_states(self.vm, self.vm.status()) def show_help(self, src): @@ -207,9 +217,9 @@ class vmmConsole(gobject.GObject): fs.set_active(False) self.window.get_widget("vmm-console").hide() - if self.vncViewer.is_connected(): + if self.vncViewer.flags() & gtk.VISIBLE: try: - self.vncViewer.disconnect_from_host() + self.vncViewer.close() except: logging.error("Failure when disconnecting from VNC server") return 1 @@ -220,21 +230,45 @@ class vmmConsole(gobject.GObject): return 0 def _vnc_disconnected(self, src): - if self.is_visible(): - self.try_login() + logging.debug("VNC disconnected") + self.vncViewerFailures = self.vncViewerFailures + 1 + self.activate_unavailable_page() + if not self.is_visible(): + return + + if self.vncViewerFailures < 10: + self.schedule_retry() + else: + logging.error("Too many connection failures, not retrying again") + + def _vnc_initialized(self, src): + logging.debug("VNC initialized") + self.activate_viewer_page() + + # Had a succesfull connect, so reset counters now + self.vncViewerFailures = 0 + self.vncViewerRetryDelay = 125 + + def schedule_retry(self): + logging.warn("Retrying connection in %d ms", self.vncViewerRetryDelay) + gobject.timeout_add(self.vncViewerRetryDelay, self.retry_login) + if self.vncViewerRetryDelay < 2000: + self.vncViewerRetryDelay = self.vncViewerRetryDelay * 2 def retry_login(self): gtk.gdk.threads_enter() try: + logging.debug("Got timed retry") self.try_login() return False finally: gtk.gdk.threads_leave() def try_login(self, src=None): - if self.vm.get_id() == 0: + if self.vm.get_id() <= 0: return + logging.debug("Trying console login") password = self.window.get_widget("console-auth-password").get_text() protocol, host, port = self.vm.get_graphics_console() @@ -245,56 +279,47 @@ class vmmConsole(gobject.GObject): uri = str(protocol) + "://" + str(host) + ":" + str(port) logging.debug("Graphics console configured at " + uri) + if int(port) == -1: + self.schedule_retry() + return + if protocol != "vnc": + logging.debug("Not a VNC console, disabling") self.activate_unavailable_page() return - if not(self.vncViewer.is_connected()): - try: - self.vncViewer.connect_to_host(host, port) - except: - self.vncViewerFailures = self.vncViewerFailures + 1 - logging.warn("Unable to activate console " + uri + ": " + str((sys.exc_info())[0]) + " " + str((sys.exc_info())[1])) - self.activate_unavailable_page() - if self.vncViewerFailures < 10: - logging.warn("Retrying connection in %d ms", self.vncViewerRetryDelay) - gobject.timeout_add(self.vncViewerRetryDelay, self.retry_login) - if self.vncViewerRetryDelay < 2000: - self.vncViewerRetryDelay = self.vncViewerRetryDelay * 2 - else: - logging.error("Too many connection failures, not retrying again") - return + logging.debug("Starting connect process for %s %s" % (host, str(port))) + try: + self.vncViewer.open_name(host, str(port)) + except: + (type, value, stacktrace) = sys.exc_info () + details = \ + "Unable to start virtual machine '%s'" % \ + (str(type) + " " + str(value) + "\n" + \ + traceback.format_exc (stacktrace)) + logging.error(details) - # Had a succesfull connect, so reset counters now - self.vncViewerFailures = 0 - self.vncViewerRetryDelay = 125 + def set_password(self, src=None): + logging.debug("Setting a password to " . str(src.get_text())) - if self.vncViewer.is_authenticated(): - self.activate_viewer_page() - elif password or not(self.vncViewer.needs_password()): - if self.vncViewer.authenticate(password) == 1: - if self.window.get_widget("console-auth-remember").get_active(): - self.config.set_console_password(self.vm, password) - else: - self.config.clear_console_password(self.vm) - self.activate_viewer_page() - self.vncViewer.activate() - else: - # Our VNC console doesn't like it when password is - # wrong and gets out of sync in its state machine - # So we force disconnect - self.vncViewer.disconnect_from_host() - self.activate_auth_page() - else: - self.activate_auth_page() + self.vncViewer.set_credential(gtkvnc.CREDENTIAL_PASSWORD, src.get_text()) + def _vnc_auth_credential(self, src, type): + logging.debug("Got credential request %d", type) + if type != gtkvnc.CREDENTIAL_PASSWORD: + # Force it to stop re-trying + self.vncViewerFailures = 10 + self.vncViewer.close() + return + + self.activate_auth_page() def activate_unavailable_page(self): - self.window.get_widget("console-pages").set_current_page(0) + self.window.get_widget("console-pages").set_current_page(PAGE_UNAVAILABLE) self.window.get_widget("menu-vm-screenshot").set_sensitive(False) def activate_screenshot_page(self): - self.window.get_widget("console-pages").set_current_page(1) + self.window.get_widget("console-pages").set_current_page(PAGE_SCREENSHOT) self.window.get_widget("menu-vm-screenshot").set_sensitive(True) def activate_auth_page(self): @@ -310,10 +335,10 @@ class vmmConsole(gobject.GObject): self.window.get_widget("console-auth-remember").set_active(False) else: self.window.get_widget("console-auth-remember").set_sensitive(False) - self.window.get_widget("console-pages").set_current_page(2) + self.window.get_widget("console-pages").set_current_page(PAGE_AUTHENTICATE) def activate_viewer_page(self): - self.window.get_widget("console-pages").set_current_page(3) + self.window.get_widget("console-pages").set_current_page(PAGE_VNCVIEWER) self.window.get_widget("menu-vm-screenshot").set_sensitive(True) self.vncViewer.grab_focus() @@ -468,13 +493,14 @@ class vmmConsole(gobject.GObject): self.window.get_widget("menu-vm-pause").set_active(False) if status in [ libvirt.VIR_DOMAIN_SHUTOFF ,libvirt.VIR_DOMAIN_CRASHED ] or vm.is_management_domain(): - self.window.get_widget("console-pages").set_current_page(0) + if self.window.get_widget("console-pages").get_current_page() != PAGE_UNAVAILABLE: + self.vncViewer.close() + self.window.get_widget("console-pages").set_current_page(PAGE_UNAVAILABLE) else: if status == libvirt.VIR_DOMAIN_PAUSED: screenshot = None - if self.vncViewer.is_authenticated(): + if self.window.get_widget("console-pages").get_current_page() == PAGE_VNCVIEWER: screenshot = self.vncViewer.take_screenshot() - if screenshot != None: cr = screenshot.cairo_create() width, height = screenshot.get_size() @@ -496,15 +522,14 @@ class vmmConsole(gobject.GObject): self.window.get_widget("console-screenshot").set_from_pixmap(screenshot, None) self.activate_screenshot_page() else: + if self.window.get_widget("console-pages").get_current_page() != PAGE_UNAVAILABLE: + self.vncViewer.close() self.activate_unavailable_page() else: - # State changed, so better let it try connecting again - self.vncViewerFailures = 0 - self.vncViewerRetryDelay = 125 - try: + if self.window.get_widget("console-pages").get_current_page() == PAGE_UNAVAILABLE: + self.vncViewerFailures = 0 + self.vncViewerRetryDelay = 125 self.try_login() - except: - logging.error("Couldn't open console " + str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1])) self.ignorePause = False self.ignorePause = False diff --git a/src/vncViewer/Makefile.am b/src/vncViewer/Makefile.am deleted file mode 100644 index 708f6e9a..00000000 --- a/src/vncViewer/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ - -pythondir = $(pkgdatadir)/vncViewer -python_DATA = $(wildcard $(srcdir)/*.py) - -EXTRA_DIST = $(python_DATA) diff --git a/src/vncViewer/__init__.py b/src/vncViewer/__init__.py deleted file mode 100644 index 2347c085..00000000 --- a/src/vncViewer/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (C) 2006 Red Hat, Inc. -# Copyright (C) 2006 Daniel P. Berrange -# -# This program 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 program 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 program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# diff --git a/src/vncViewer/crippled_des.py b/src/vncViewer/crippled_des.py deleted file mode 100644 index e605c83e..00000000 --- a/src/vncViewer/crippled_des.py +++ /dev/null @@ -1,481 +0,0 @@ -## -## pyvnc2swf - crippled_des.py -## -## $Id: crippled_des.py,v 1.3 2005/08/25 20:01:59 euske Exp $ -## -## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu) -## All Rights Reserved. -## -## This is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This software is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this software; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -## USA. -## - -## The following part of this file is taken from -## pyvncviewer by Chris Liechti. -## URL: http://homepage.hispeed.ch/py430/python/ - -# Modified DES encryption for VNC password authentication. -# Ported from realvnc's java viewer by -# I chose this package name because it is not compatible with the -# original DES algorithm, e.g. found pycrypto. -# Original notice following: - -# This DES class has been extracted from package Acme.Crypto for use in VNC. -# The bytebit[] array has been reversed so that the most significant bit -# in each byte of the key is ignored, not the least significant. Also the -# unnecessary odd parity code has been removed. -# -# These changes are: -# Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. -# -# This software is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# - -# DesCipher - the DES encryption method -# -# The meat of this code is by Dave Zimmerman , and is: -# -# Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. -# -# Permission to use, copy, modify, and distribute this software -# and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and -# without fee is hereby granted, provided that this copyright notice is kept -# intact. -# -# WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY -# OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -# TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -# PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE -# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR -# DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. -# -# THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE -# CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE -# PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT -# NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE -# SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE -# SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE -# PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP -# SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR -# HIGH RISK ACTIVITIES. -# -# -# The rest is: -# -# Copyright (C) 1996 by Jef Poskanzer . All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. 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. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. -# -# Visit the ACME Labs Java page for up-to-date versions of this and other -# fine Java utilities: http://www.acme.com/java/ - - -#/ The DES encryption method. -#

-# This is surprisingly fast, for pure Java. On a SPARC 20, wrapped -# in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream, -# it does around 7000 bytes/second. -#

-# Most of this code is by Dave Zimmerman , and is -# Copyright (c) 1996 Widget Workshop, Inc. See the source file for details. -#

-# Fetch the software.
-# Fetch the entire Acme package. -#

-# @see Des3Cipher -# @see EncryptedOutputStream -# @see EncryptedInputStream - -import struct - -class DesCipher: - # Constructor, byte-array key. - def __init__(self, key): - self.setKey(key) - - #/ Set the key. - def setKey(self, key): - self.encryptKeys = self.deskey([ord(x) for x in key], 1) - self.decryptKeys = self.deskey([ord(x) for x in key], 0) - - # Turn an 8-byte key into internal keys. - def deskey(self, keyBlock, encrypting): - #~ int i, j, l, m, n; - pc1m = [0]*56 #new int[56]; - pcr = [0]*56 #new int[56]; - kn = [0]*32 #new int[32]; - - for j in range(56): - l = pc1[j] - m = l & 07 - pc1m[j] = ((keyBlock[l >> 3] & bytebit[m]) != 0) - - for i in range(16): - if encrypting: - m = i << 1 - else: - m = (15-i) << 1 - n = m + 1 - kn[m] = kn[n] = 0 - for j in range(28): - l = j + totrot[i] - if l < 28: - pcr[j] = pc1m[l] - else: - pcr[j] = pc1m[l - 28] - for j in range(28, 56): - l = j + totrot[i] - if l < 56: - pcr[j] = pc1m[l] - else: - pcr[j] = pc1m[l - 28] - for j in range(24): - if pcr[pc2[j]] != 0: - kn[m] |= bigbyte[j] - if pcr[pc2[j+24]] != 0: - kn[n] |= bigbyte[j] - return self.cookey(kn) - - def cookey(self, raw): - #~ int raw0, raw1; - #~ int rawi, KnLi; - #~ int i; - KnL = [0]*32 - - rawi = 0 - KnLi = 0 - for i in range(16): - raw0 = raw[rawi] - rawi += 1 - raw1 = raw[rawi] - rawi += 1 - KnL[KnLi] = (raw0 & 0x00fc0000L) << 6 - KnL[KnLi] |= (raw0 & 0x00000fc0L) << 10 - KnL[KnLi] |= (raw1 & 0x00fc0000L) >> 10 - KnL[KnLi] |= (raw1 & 0x00000fc0L) >> 6 - KnLi += 1 - KnL[KnLi] = (raw0 & 0x0003f000L) << 12 - KnL[KnLi] |= (raw0 & 0x0000003fL) << 16 - KnL[KnLi] |= (raw1 & 0x0003f000L) >> 4 - KnL[KnLi] |= (raw1 & 0x0000003fL) - KnLi += 1 - return KnL - - # Block encryption routines. - - #/ Encrypt a block of eight bytes. - def encrypt(self, clearText): - if len(clearText) != 8: - raise TypeError, "length must be eight bytes" - return struct.pack(">LL", - *self.des(struct.unpack(">LL", clearText), self.encryptKeys) - ) - - #/ Decrypt a block of eight bytes. - def decrypt(self, cipherText): - if len(cipherText) != 8: - raise TypeError, "length must be eight bytes" - return struct.pack(">LL", - *self.des(struct.unpack(">LL", cipherText), self.decryptKeys) - ) - - # The DES function. - def des(self, (leftt, right), keys): - #~ int fval, work, right, leftt; - #~ int round - keysi = 0 - - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL - right ^= work - leftt ^= (work << 4) & 0xffffffffL - - work = ((leftt >> 16) ^ right) & 0x0000ffffL - right ^= work - leftt ^= (work << 16) & 0xffffffffL - - work = ((right >> 2) ^ leftt) & 0x33333333L - leftt ^= work - right ^= (work << 2) & 0xffffffffL - - work = ((right >> 8) ^ leftt) & 0x00ff00ffL - leftt ^= work - right ^= (work << 8) & 0xffffffffL - right = ((right << 1) | ((right >> 31) & 1)) & 0xffffffffL - - work = (leftt ^ right) & 0xaaaaaaaaL - leftt ^= work - right ^= work - leftt = ((leftt << 1) | ((leftt >> 31) & 1)) & 0xffffffffL - - for round in range(8): - work = ((right << 28) | (right >> 4)) & 0xffffffffL - work ^= keys[keysi] - keysi += 1 - fval = SP7[ work & 0x0000003fL ] - fval |= SP5[(work >> 8) & 0x0000003fL ] - fval |= SP3[(work >> 16) & 0x0000003fL ] - fval |= SP1[(work >> 24) & 0x0000003fL ] - work = right ^ keys[keysi] - keysi += 1 - fval |= SP8[ work & 0x0000003fL ] - fval |= SP6[(work >> 8) & 0x0000003fL ] - fval |= SP4[(work >> 16) & 0x0000003fL ] - fval |= SP2[(work >> 24) & 0x0000003fL ] - leftt ^= fval - work = ((leftt << 28) | (leftt >> 4)) & 0xffffffffL - work ^= keys[keysi] - keysi += 1 - fval = SP7[ work & 0x0000003fL ] - fval |= SP5[(work >> 8) & 0x0000003fL ] - fval |= SP3[(work >> 16) & 0x0000003fL ] - fval |= SP1[(work >> 24) & 0x0000003fL ] - work = leftt ^ keys[keysi] - keysi += 1 - fval |= SP8[ work & 0x0000003fL ] - fval |= SP6[(work >> 8) & 0x0000003fL ] - fval |= SP4[(work >> 16) & 0x0000003fL ] - fval |= SP2[(work >> 24) & 0x0000003fL ] - right ^= fval - - right = ((right << 31) | (right >> 1)) & 0xffffffffL - work = (leftt ^ right) & 0xaaaaaaaaL - leftt ^= work - right ^= work - leftt = ((leftt << 31) | (leftt >> 1)) & 0xffffffffL - work = ((leftt >> 8) ^ right) & 0x00ff00ffL - right ^= work - leftt ^= (work << 8) & 0xffffffffL - work = ((leftt >> 2) ^ right) & 0x33333333L - right ^= work - leftt ^= (work << 2) & 0xffffffffL - work = ((right >> 16) ^ leftt) & 0x0000ffffL - leftt ^= work - right ^= (work << 16) & 0xffffffffL - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL - leftt ^= work - right ^= (work << 4) & 0xffffffffL - return right, leftt - -# Tables, permutations, S-boxes, etc. - -bytebit = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80] - -bigbyte = [ - 0x800000, 0x400000, 0x200000, 0x100000, - 0x080000, 0x040000, 0x020000, 0x010000, - 0x008000, 0x004000, 0x002000, 0x001000, - 0x000800, 0x000400, 0x000200, 0x000100, - 0x000080, 0x000040, 0x000020, 0x000010, - 0x000008, 0x000004, 0x000002, 0x000001 -] - -pc1 = [ - 56, 48, 40, 32, 24, 16, 8, - 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, - 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, - 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, - 20, 12, 4, 27, 19, 11, 3 -] - -totrot = [ - 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 -] - -pc2 = [ - 13, 16, 10, 23, 0, 4, - 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3 , 25, 7, - 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, - 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, - 45, 41, 49, 35, 28, 31, -] - -SP1 = [ - 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, - 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, - 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, - 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, - 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, - 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, - 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, - 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, - 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, - 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, - 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, - 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, - 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, - 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L -] -SP2 = [ - 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, - 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, - 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, - 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, - 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, - 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, - 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, - 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, - 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, - 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, - 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, - 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, - 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, - 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, - 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, - 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L -] -SP3 = [ - 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, - 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, - 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, - 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, - 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, - 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, - 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, - 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, - 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, - 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, - 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, - 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, - 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, - 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, - 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, - 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L -] -SP4 = [ - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, - 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, - 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, - 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, - 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, - 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, - 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, - 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, - 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L -] -SP5 = [ - 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, - 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, - 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, - 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, - 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, - 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, - 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, - 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, - 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, - 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, - 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, - 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, - 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, - 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, - 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, - 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L -] -SP6 = [ - 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, - 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, - 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, - 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, - 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, - 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, - 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, - 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, - 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, - 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, - 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, - 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, - 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, - 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L -] -SP7 = [ - 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, - 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, - 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, - 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, - 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, - 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, - 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, - 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, - 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, - 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, - 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, - 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, - 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, - 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, - 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, - 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L -] -SP8 = [ - 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, - 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, - 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, - 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, - 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, - 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, - 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, - 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, - 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, - 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, - 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, - 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, - 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, - 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, - 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, - 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L -] - -#test only: -if __name__ == '__main__': - des = DesCipher('test1234') - print repr(des.encrypt("hello321")) - print des.decrypt(des.encrypt("hello321")) - print des.encrypt(des.decrypt("hello321")) diff --git a/src/vncViewer/rfb.py b/src/vncViewer/rfb.py deleted file mode 100644 index d962acf5..00000000 --- a/src/vncViewer/rfb.py +++ /dev/null @@ -1,566 +0,0 @@ -## -## pyvnc2swf - rfb.py -## -## $Id: rfb.py,v 1.25 2005/11/27 00:04:18 euske Exp $ -## -## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu) -## All Rights Reserved. -## -## Adapted for use as a VNC widget in virtmanager: -## -## Copyright (C) 2006 Red Hat 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. -## - - -import sys, time, socket -from struct import pack, unpack -from crippled_des import DesCipher -stderr = sys.stderr -lowerbound = max - - -def byte2bit(s): - return ''.join([ chr((ord(s[i>>3]) >> (7 - i&7)) & 1) for i in xrange(len(s)*8) ]) - - -# Exceptions -class RFBError(Exception): pass -class RFBAuthError(RFBError): pass -class RFBProtocolError(RFBError): pass - -ENCODING_RAW = 0 -ENCODING_COPY_RECT = 1 -ENCODING_RRE = 2 -ENCODING_CORRE = 4 -ENCODING_HEXTILE = 5 -ENCODING_ZRLE = 16 -ENCODING_DESKTOP_RESIZE = -223 -ENCODING_CURSOR_POS = -232 -ENCODING_RICH_CURSOR = -239 -ENCODING_XCURSOR = -240 - -AUTH_INVALID = 0 -AUTH_NONE = 1 -AUTH_VNCAUTH = 2 -AUTH_RA2 = 5 -AUTH_RA2NE = 6 -AUTH_TIGHT = 16 -AUTH_ULTRA = 17 -AUTH_TLS = 18 - -AUTH_VALID = [ AUTH_NONE, AUTH_VNCAUTH, AUTH_RA2, AUTH_RA2NE, AUTH_TIGHT, AUTH_ULTRA, AUTH_TLS ] -AUTH_SUPPORTED = [ AUTH_NONE, AUTH_VNCAUTH ] - -## RFBFrameBuffer -## -class RFBFrameBuffer: - - def init_screen(self, width, height, name): - #print >>stderr, 'init_screen: %dx%d, name=%r' % (width, height, name) - raise NotImplementedError - - def resize_screen(self, width, height): - raise NotImplementedError - - def set_converter(self, convert_pixels, convert_color1): - self.convert_pixels = convert_pixels - self.convert_color1 = convert_color1 - return - - def process_pixels(self, x, y, width, height, data): - #print >>stderr, 'process_pixels: %dx%d at (%d,%d)' % (width,height,x,y) - raise NotImplementedError - - def process_solid(self, x, y, width, height, data): - #print >>stderr, 'process_solid: %dx%d at (%d,%d), color=%r' % (width,height,x,y, color) - raise NotImplementedError - - def update_screen(self, t): - #print >>stderr, 'update_screen' - raise NotImplementedError - - # data is given as ARGB - def change_cursor(self, width, height, x, y, data): - #print >>stderr, 'change_cursor' - raise NotImplementedError - - def move_cursor(self, x, y): - #print >>stderr, 'move_cursor' - raise NotImplementedError - - def close(self): - return - - -## RFBProxy -## -class RFBProxy: - "Abstract class of RFB clients." - - def __init__(self, fb=None, preferred_encoding=(ENCODING_RAW,ENCODING_HEXTILE), debug=0): - self.fb = fb - self.debug = debug - self.preferred_encoding = preferred_encoding - return - - FASTEST_FORMAT = (32, 8, 1, 1, 255, 255, 255, 24, 16, 8) - def preferred_format(self, bitsperpixel, depth, bigendian, truecolour, - red_max, green_max, blue_max, - red_shift, green_shift, blue_shift): - # should return 10-tuple (bitsperpixel, depth, bigendian, truecolour, - # red_max, green_max, blue_max, red_shift, green_shift, blue_shift) - if self.fb: - self.fb.set_converter(lambda data: data, - lambda data: unpack('BBBx', data)) - return self.FASTEST_FORMAT - - def send(self, s): - "Send data s to the server." - raise NotImplementedError - - def recv(self, n): - "Receive n-bytes data from the server." - raise NotImplementedError - - def recv_relay(self, n): - "Same as recv() except the received data is also passed to self.relay.recv_framedata." - return self.recv(n) - - def recv_byte_with_timeout(self): - return self.recv_relay(1) - - def write(self, n): - return - - def request_update(self): - "Send a request to the server." - raise NotImplementedError - def finish_update(self): - if self.fb: - self.fb.update_screen(time.time()) - return - - def init(self): - # recv: server protocol version - server_version = self.recv(12) - # send: client protocol version - self.protocol_version = 3 - if server_version.startswith('RFB 003.007'): - self.protocol_version = 7 - elif server_version.startswith('RFB 003.008'): - self.protocol_version = 8 - self.send('RFB 003.%03d\x0a' % self.protocol_version) - if self.debug: - print >>stderr, 'protocol_version: 3.%d' % self.protocol_version - - self.auth_types = [] - - if self.protocol_version == 3: - # protocol 3.3 (or 3.6) - # recv: server security - (server_security,) = unpack('>L', self.recv(4)) - if self.debug: - print >>stderr, 'server_security: %r' % server_security - # server_security might be 0, 1 or 2. - if int(server_security) == 0: - (reason_length,) = unpack('>L', self.recv(4)) - reason = self.recv(reason_length) - raise RFBAuthError('Auth Error: %s' % reason) - elif int(server_security) in AUTH_VALID: - self.auth_types = [ server_security ] - else: - raise "illegal auth type %d" % server_security - elif self.protocol_version >= 7: - (nsecurities,) = unpack('>B', self.recv(1)) - server_securities = self.recv(nsecurities) - if self.debug: - print >>stderr, 'server_securities: %r' % server_securities - for type in server_securities: - if ord(type) in AUTH_SUPPORTED: - self.auth_types.append(ord(type)) - - if len(self.auth_types) == 0: - raise "no valid auth types in " + str(server_securities) - - return self.auth_types - - def getpass(self): - raise NotImplementedError - - - def auth(self): - - # vnc challange & response auth - def crauth(): - p = self.getpass() - if not p: - raise RFBError('Auth cancelled') - # from pyvncviewer - des = DesCipher((p+'\x00'*8)[:8]) - challange = self.recv(16) - if self.debug: - print >>stderr, 'challange: %r' % challange - response = des.encrypt(challange[:8]) + des.encrypt(challange[8:]) - if self.debug: - print >>stderr, 'response: %r' % response - self.send(response) - # recv: security result - (result,) = unpack('>L', self.recv(4)) - return result - - server_result = 0 - if self.protocol_version == 3: - if AUTH_NONE in self.auth_types: - server_result = 0 - elif AUTH_VNCAUTH in self.auth_types: - server_result = crauth() - elif self.protocol_version >= 7: - if AUTH_NONE in self.auth_types: - self.send('\x01') - if self.protocol_version == 8: - # Protocol 3.8: must recv security result - (server_result,) = unpack('>L', self.recv(4)) - else: - server_result = 0 - elif AUTH_VNCAUTH in self.auth_types: - self.send('\x02') - server_result = crauth() - else: - raise "no supported auth types" - # result returned. - if self.debug: - print >>stderr, 'server_result: %r' % server_result - if server_result != 0: - # auth failed. - if self.protocol_version != 3: - (reason_length,) = unpack('>L', self.recv(4)) - reason = self.recv(reason_length) - else: - reason = server_result - raise RFBAuthError('Auth Error: %s' % reason) - - def start(self, shared=True): - if shared: - self.send('\x01') - else: - self.send('\x00') - - # server info. - server_init = self.recv(24) - (width, height, pixelformat, namelen) = unpack('>HH16sL', server_init) - self.name = self.recv(namelen) - (bitsperpixel, depth, bigendian, truecolour, - red_max, green_max, blue_max, - red_shift, green_shift, blue_shift) = unpack('>BBBBHHHBBBxxx', pixelformat) - if self.debug: - print >>stderr, 'Server Encoding:' - print >>stderr, ' width=%d, height=%d, name=%r' % (width, height, self.name) - print >>stderr, ' pixelformat=', (bitsperpixel, depth, bigendian, truecolour) - print >>stderr, ' rgbmax=', (red_max, green_max, blue_max) - print >>stderr, ' rgbshift=', (red_shift, green_shift, blue_shift) - # setformat - self.send('\x00\x00\x00\x00') - # 32bit, 8bit-depth, big-endian(RGBX), truecolour, 255max - (bitsperpixel, depth, bigendian, truecolour, - red_max, green_max, blue_max, - red_shift, green_shift, blue_shift) = self.preferred_format(bitsperpixel, depth, bigendian, truecolour, - red_max, green_max, blue_max, - red_shift, green_shift, blue_shift) - self.bytesperpixel = bitsperpixel/8 - pixelformat = pack('>BBBBHHHBBBxxx', bitsperpixel, depth, bigendian, truecolour, - red_max, green_max, blue_max, - red_shift, green_shift, blue_shift) - self.send(pixelformat) - self.write(pack('>HH16sL', width, height, pixelformat, namelen)) - self.write(self.name) - if self.fb: - self.clipping = self.fb.init_screen(width, height, self.name) - else: - self.clipping = (0,0, width, height) - self.send('\x02\x00' + pack('>H', len(self.preferred_encoding))) - for e in self.preferred_encoding: - self.send(pack('>l', e)) - return self - - def loop1(self): - self.request_update() - c = self.recv_byte_with_timeout() - if c == '': - return False - elif c == None: - # timeout - pass - elif c == '\x00': - (nrects,) = unpack('>xH', self.recv_relay(3)) - if self.debug: - print >>stderr, 'FrameBufferUpdate: nrects=%d' % nrects - for rectindex in xrange(nrects): - (x0, y0, width, height, t) = unpack('>HHHHl', self.recv_relay(12)) - if self.debug: - print >>stderr, ' %d: %d x %d at (%d,%d), type=%d' % (rectindex, width, height, x0, y0, t) - - if t == ENCODING_RAW: - l = width*height*self.bytesperpixel - data = self.recv_relay(l) - if self.debug: - print >>stderr, ' RawEncoding: len=%d, received=%d' % (l, len(data)) - if self.fb: - self.fb.process_pixels(x0, y0, width, height, data) - - elif t == ENCODING_COPY_RECT: - raise RFBProtocolError('unsupported: CopyRectEncoding') - - elif t == ENCODING_RRE: - (nsubrects,) = unpack('>L', self.recv_relay(4)) - bgcolor = self.recv_relay(self.bytesperpixel) - if self.debug: - print >>stderr, ' RREEncoding: subrects=%d, bgcolor=%r' % (nsubrects, bgcolor) - if self.fb: - self.fb.process_solid(x0, y0, width, height, bgcolor) - for i in xrange(nsubrects): - fgcolor = self.recv_relay(self.bytesperpixel) - (x,y,w,h) = unpack('>HHHH', self.recv_relay(8)) - if self.fb: - self.fb.process_solid(x0+x, y0+y, w, h, fgcolor) - if 2 <= self.debug: - print >>stderr, ' RREEncoding: ', (x,y,w,h,fgcolor) - - elif t == ENCODING_CORRE: - (nsubrects,) = unpack('>L', self.recv_relay(4)) - bgcolor = self.recv_relay(self.bytesperpixel) - if self.debug: - print >>stderr, ' CoRREEncoding: subrects=%d, bgcolor=%r' % (nsubrects, bgcolor) - if self.fb: - self.fb.process_solid(x0, y0, width, height, bgcolor) - for i in xrange(nsubrects): - fgcolor = self.recv_relay(self.bytesperpixel) - (x,y,w,h) = unpack('>BBBB', self.recv_relay(4)) - if self.fb: - self.fb.process_solid(x0+x, y0+y, w, h, fgcolor) - if 2 <= self.debug: - print >>stderr, ' CoRREEncoding: ', (x,y,w,h,fgcolor) - - elif t == ENCODING_HEXTILE: - if self.debug: - print >>stderr, ' HextileEncoding' - (fgcolor, bgcolor) = (None, None) - for y in xrange(0, height, 16): - for x in xrange(0, width, 16): - w = min(width-x, 16) - h = min(height-y, 16) - c = ord(self.recv_relay(1)) - assert c < 32 - # Raw - if c & 1: - l = w*h*self.bytesperpixel - data = self.recv_relay(l) - if self.fb: - self.fb.process_pixels(x0+x, y0+y, w, h, data) - if 2 <= self.debug: - print >>stderr, ' Raw:', l - continue - if c & 2: - bgcolor = self.recv_relay(self.bytesperpixel) - if c & 4: - fgcolor = self.recv_relay(self.bytesperpixel) - if self.fb: - self.fb.process_solid(x0+x, y0+y, w, h, bgcolor) - # Solid - if not c & 8: - if 2 <= self.debug: - print >>stderr, ' Solid:', repr(bgcolor) - continue - nsubrects = ord(self.recv_relay(1)) - # SubrectsColoured - if c & 16: - if 2 <= self.debug: - print >>stderr, ' SubrectsColoured:', nsubrects, repr(bgcolor) - for i in xrange(nsubrects): - color = self.recv_relay(self.bytesperpixel) - (xy,wh) = unpack('>BB', self.recv_relay(2)) - if self.fb: - self.fb.process_solid(x0+x+(xy>>4), y0+y+(xy&15), (wh>>4)+1, (wh&15)+1, color) - if 3 <= self.debug: - print >>stderr, ' ', repr(color), (xy,wh) - # NoSubrectsColoured - else: - if 2 <= self.debug: - print >>stderr, ' NoSubrectsColoured:', nsubrects, repr(bgcolor) - for i in xrange(nsubrects): - (xy,wh) = unpack('>BB', self.recv_relay(2)) - if self.fb: - self.fb.process_solid(x0+x+(xy>>4), y0+y+(xy&15), (wh>>4)+1, (wh&15)+1, fgcolor) - if 3 <= self.debug: - print >>stderr, ' ', (xy,wh) - - elif t == ENCODING_ZRLE: - raise RFBProtocolError('unsupported: ZRLEEncoding') - - elif t == ENCODING_DESKTOP_RESIZE: - self.clipping = self.fb.resize_screen(width, height) - - elif t == ENCODING_RICH_CURSOR: - if width and height: - rowbytes = (width + 7) / 8; - # Cursor image RGB - data = self.recv_relay(width * height * self.bytesperpixel) - # Cursor mask -> 1 bit/pixel (1 -> image; 0 -> transparent) - mask = self.recv_relay(rowbytes * height) - # Set the alpha channel with maskData where bit=1 -> alpha = 255, bit=0 -> alpha=255 - if self.debug: - print >>stderr, 'RichCursor: %dx%d at %d,%d' % (width,height,x0,y0) - if self.fb: - data = self.fb.convert_pixels(data) - mask = ''.join([ byte2bit(mask[p:p+rowbytes]) for p in xrange(0, height*rowbytes, rowbytes) ]) - def conv1(i): - if mask[i/4] == '\x01': - return '\xff'+data[i]+data[i+1]+data[i+2] - else: - return '\x00\x00\x00\x00' - data = ''.join([ conv1(i) for i in xrange(0, len(data), 4) ]) - self.fb.change_cursor(width, height, x0, y0, data) - - elif t == ENCODING_XCURSOR: - if width and height: - rowbytes = (width + 7) / 8; - # Foreground RGB - fgcolor = self.recv_relay(3) - # Background RGB - bgcolor = self.recv_relay(3) - # Cursor Data -> 1 bit/pixel - data = self.recv_relay(rowbytes * height) - # Cursor Mask -> 1 bit/pixel - mask = self.recv_relay(rowbytes * height) - # Create the image from cursordata and maskdata. - print >>stderr, 'XCursor: %dx%d at %d,%d' % (width,height,x0,y0) - if self.fb: - data = byte2bit(data) - mask = byte2bit(mask) - def conv1(i): - if mask[i] == '\x01': - if data[i] == '\x01': - return '\xff'+fgcolor - else: - return '\xff'+bgcolor - else: - return '\x00\x00\x00\x00' - data = ''.join([ conv1(i) for i in xrange(len(data)) ]) - self.fb.change_cursor(width, height, x0, y0, data) - - elif t == ENCODING_CURSOR_POS: - if self.debug: - print >>stderr, 'CursorPos: %d,%d' % (x0,y0) - if self.fb: - self.fb.move_cursor(x0, y0) - else: - raise RFBProtocolError('Illegal encoding: 0x%02x' % t) - self.finish_update() - elif c == '\x01': - (first, ncolours) = unpack('>xHH', self.recv_relay(11)) - if self.debug: - print >>stderr, 'SetColourMapEntries: first=%d, ncolours=%d' % (first, ncolours) - for i in ncolours: - self.recv_relay(6) - - elif c == '\x02': - if self.debug: - print >>stderr, 'Bell' - - elif c == '\x03': - (length, ) = unpack('>3xL', self.recv_relay(7)) - data = self.recv_relay(length) - if self.debug: - print >>stderr, 'ServerCutText: %r' % data - - else: - raise RFBProtocolError('Unsupported msg: %d' % ord(c)) - - return True - - def loop(self): - while self.loop1(): - pass - self.finish_update() - return self - - def close(self): - if self.fb: - self.fb.close() - return - - -## RFBNetworkClient -## -class RFBNetworkClient(RFBProxy): - - def __init__(self, host, port, fb=None, pwdfile=None, - preferred_encoding=(ENCODING_RAW,ENCODING_HEXTILE), debug=0): - RFBProxy.__init__(self, fb=fb, preferred_encoding=preferred_encoding, debug=debug) - self.host = host - self.port = port - self.pwdfile = pwdfile - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - return - - def init(self): - self.sock.connect((self.host, self.port)) - return RFBProxy.init(self) - - def recv(self, n): - # MS-Windows doesn't have MSG_WAITALL, so we emulate it. - buf = '' - while n: - x = self.sock.recv(n) - if not x: break - buf += x - n -= len(x) - return buf - - def recv_byte_with_timeout(self): - self.sock.settimeout(0.05) - try: - c = self.recv_relay(1) - except socket.timeout: - c = None - self.sock.settimeout(None) - return c - - def send(self, s): - return self.sock.send(s) - - def getpass(self): - import getpass - if self.pwdfile: - fp = file(self.pwdfile) - s = fp.read().rstrip() - fp.close() - return s - return getpass.getpass('Password for %s:%d: ' % (self.host, self.port)) - - def request_update(self): - if self.debug: - print >>stderr, 'FrameBufferUpdateRequest' - self.send('\x03\x01' + pack('>HHHH', *self.clipping)) - return - - def close(self): - RFBProxy.close(self) - self.sock.close() - return - - diff --git a/src/vncViewer/vnc.py b/src/vncViewer/vnc.py deleted file mode 100755 index 180161a8..00000000 --- a/src/vncViewer/vnc.py +++ /dev/null @@ -1,659 +0,0 @@ -# -# Copyright (C) 2006 Daniel Berrange -# Copyright (C) 2006 Red Hat -# -## 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. - - -import gobject -import rfb -import sys -from struct import pack, unpack -import pygtk -import gtk -import logging - -stderr = sys.stderr - -from time import time - -class GRFBFrameBuffer(rfb.RFBFrameBuffer, gobject.GObject): - __gsignals__= { - "resize": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [int,int]), - "invalidate": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [int,int,int,int]) - } - - def __init__(self, canvas): - self.__gobject_init__() - self.canvas = canvas - self.pixmap = None - self.name = "VNC" - self.dirtyregion = None - - def get_name(self): - return self.name - - def get_pixmap(self): - return self.pixmap - - def clone_pixmap(self): - if self.pixmap == None: - return None - width, height = self.pixmap.get_size() - clone = gtk.gdk.Pixmap(self.canvas.window, width, height) - gc = clone.new_gc() - clone.draw_drawable(gc, self.pixmap, 0, 0, 0, 0, -1, -1) - return clone - - def init_screen(self, width, height, name): - self.name = name - return self.resize_screen(width, height) - - def resize_screen(self, width, height): - self.pixmap = gtk.gdk.Pixmap(self.canvas.window, width, height) - self.gc = self.pixmap.new_gc() - self.emit("resize", width, height) - return (0, 0, width, height) - - def process_pixels(self, x, y, width, height, data): - if self.pixmap == None: - return - - self.pixmap.draw_rgb_32_image(self.gc, x, y, width, height, gtk.gdk.RGB_DITHER_NONE, data) - self.dirty(x,y,width,height) - - def dirty(self, x, y, width, height): - if self.dirtyregion == None: - self.dirtyregion = { "x1": x, "y1": y, "x2": x+width, "y2": y+height } - else: - if x < self.dirtyregion["x1"]: - self.dirtyregion["x1"] = x - if (x + width) > self.dirtyregion["x2"]: - self.dirtyregion["x2"] = (x + width) - if y < self.dirtyregion["y1"]: - self.dirtyregion["y1"] = y - if (y + height) > self.dirtyregion["y2"]: - self.dirtyregion["y2"] = (y + height) - - def process_solid(self, x, y, width, height, color): - # XXX very very evil assumes pure 32-bit RGBA format - (r,g,b,a) = unpack('BBBB', color) - self.gc.set_rgb_fg_color(gtk.gdk.Color(red=r*255,green=g*255,blue=b*255)) - if width == 1 and height == 1: - self.pixmap.draw_point(self.gc, x, y) - else: - self.pixmap.draw_rectangle(self.gc, True, x, y, width, height) - self.dirty(x,y,width,height) - - def update_screen(self, t): - if self.dirtyregion != None: - x1 = self.dirtyregion["x1"] - x2 = self.dirtyregion["x2"] - y1 = self.dirtyregion["y1"] - y2 = self.dirtyregion["y2"] - self.emit("invalidate", x1, y1, x2-x1, y2-y1) - self.dirtyregion = None - - def change_cursor(self, width, height, x, y, data): - logging.error("Unsupported change_cursor operation requested") - - def move_cursor(self, x, y): - logging.error("Unsupported move_cursor operation requested") - -gobject.type_register(GRFBFrameBuffer) - - -class GRFBNetworkClient(rfb.RFBNetworkClient, gobject.GObject): - __gsignals__= { - "disconnected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []) - } - - def __init__(self, host, port, converter, debug=0, preferred_encoding=(rfb.ENCODING_RAW)): - rfb.RFBNetworkClient.__init__(self, host, port, converter, debug=debug,preferred_encoding=preferred_encoding) - self.__gobject_init__() - - self.watch = None - self.password = None - - def init(self): - return rfb.RFBNetworkClient.init(self) - - def start(self): - rfb.RFBNetworkClient.start(self) - self.watch = gobject.io_add_watch(self.sock.fileno(), gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, self.handle_io) - - def handle_io(self, src, condition): - gtk.gdk.threads_enter() - try: - return self._handle_io(src, condition) - finally: - gtk.gdk.threads_leave() - - def _handle_io(self, src, condition): - if self.watch == None: - return 0 - - try: - self.loop1() - except Exception, e: - logging.warn("Failure while handling VNC I/O, closing socket: " + str(e)) - self.close() - self.emit("disconnected") - return 0 - return 1 - - def close(self): - rfb.RFBNetworkClient.close(self) - - if self.watch != None: - gobject.source_remove(self.watch) - self.watch = None - - def setpass(self, password): - self.password = password - - def getpass(self): - return self.password - - def update_key(self, down, key): - self.send(pack('>BBHI', 4, down, 0, key)) - - def update_pointer(self, mask, x, y): - if x < 0: - x = 0 - if y < 0: - y = 0 - self.send(pack('>BBHH', 5, mask, x, y)) -gobject.type_register(GRFBNetworkClient) - - -class GRFBViewer(gtk.DrawingArea): - __gsignals__= { - "connected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str, int]), - "authenticated": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "activated": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "disconnected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "pointer-grabbed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "pointer-ungrabbed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "keyboard-grabbed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - "keyboard-ungrabbed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []), - } - - def __init__(self, topwin, autograbkey=False): - gtk.DrawingArea.__init__(self) - - self.fb = GRFBFrameBuffer(self) - self.client = None - self.authenticated = False - self.needpw = True - self.autograbkey = autograbkey - self.autograbptr = True - self.topwin = topwin - self.accel_groups = gtk.accel_groups_from_object(topwin) - self.preferred_encoding = (rfb.ENCODING_RAW, rfb.ENCODING_DESKTOP_RESIZE) - # Current impl of draw_solid is *far* too slow to be practical - # for Hextile which likes lots of 1x1 pixels solid rectangles - #self.preferred_encoding = (rfb.ENCODING_HEXTILE, rfb.ENCODING_RAW, rfb.ENCODING_DESKTOP_RESIZE) - - self.fb.connect("resize", self.resize_display) - self.fb.connect("invalidate", self.repaint_region) - - self.connect("expose-event", self.expose_region) - - self.connect("motion-notify-event", self.pointer_move) - self.connect("button-press-event", self.pointer_press) - self.connect("button-release-event", self.pointer_release) - self.connect("scroll-event", self.pointer_scroll) - self.connect("key-press-event", self.key_press) - self.connect("key-release-event", self.key_release) - self.connect("enter-notify-event", self.enter_notify) - self.connect("leave-notify-event", self.leave_notify) - self.connect("focus-in-event", self.focus_in) - self.connect("focus-out-event", self.focus_out) - - # We keep a big list of likely modifier keys, so when we get - # a focus-out event while one of these is presed, we then - # send a fake KeyUp event to VNC. This avoid trouble with - # the guest having 'stuck' modifier keys. - self.modifiers = (gtk.gdk.keyval_from_name("Shift_L"), \ - gtk.gdk.keyval_from_name("Shift_R"), \ - gtk.gdk.keyval_from_name("Control_L"), \ - gtk.gdk.keyval_from_name("Control_R"), \ - gtk.gdk.keyval_from_name("Caps_Lock"), \ - gtk.gdk.keyval_from_name("Shift_Lock"), \ - gtk.gdk.keyval_from_name("Meta_L"), \ - gtk.gdk.keyval_from_name("Meta_R"), \ - gtk.gdk.keyval_from_name("Alt_L"), \ - gtk.gdk.keyval_from_name("Alt_R"), \ - gtk.gdk.keyval_from_name("Super_L"), \ - gtk.gdk.keyval_from_name("Super_R"), \ - gtk.gdk.keyval_from_name("Hyper_L"), \ - gtk.gdk.keyval_from_name("Hyper_R"), \ - gtk.gdk.keyval_from_name("ISO_Lock"), \ - gtk.gdk.keyval_from_name("ISO_Level2_Latch"), \ - gtk.gdk.keyval_from_name("ISO_Level2_Shift"), \ - gtk.gdk.keyval_from_name("ISO_Level3_Latch"), \ - gtk.gdk.keyval_from_name("ISO_Level3_Lock"), \ - gtk.gdk.keyval_from_name("ISO_Group_Shift"), \ - gtk.gdk.keyval_from_name("ISO_Group_Latch"), \ - gtk.gdk.keyval_from_name("ISO_Group_Lock"), \ - gtk.gdk.keyval_from_name("ISO_Next_Group"), \ - gtk.gdk.keyval_from_name("ISO_Next_Group_Lock"), \ - gtk.gdk.keyval_from_name("ISO_Prev_Group"), \ - gtk.gdk.keyval_from_name("ISO_Prev_Group_Lock"), \ - gtk.gdk.keyval_from_name("ISO_First_Group"), \ - gtk.gdk.keyval_from_name("ISO_First_Group_Lock"), \ - gtk.gdk.keyval_from_name("ISO_Last_Group"), \ - gtk.gdk.keyval_from_name("ISO_Last_Group_Lock"), \ - gtk.gdk.keyval_from_name("Mode_switch"), \ - gtk.gdk.keyval_from_name("Num_Lock"), \ - ) - self.modifiersOn = {} - - # If we press one of these keys 3 times in a row - # its become sticky until a key outside this set - # is pressed. This lets you do Ctrl-Alt-F1, eg - # by "Ctrl Ctrl Ctrl Alt-F1" - self.stickyMods = (gtk.gdk.keyval_from_name("Alt_L"), \ - gtk.gdk.keyval_from_name("Alt_R"), \ - gtk.gdk.keyval_from_name("Shift_L"), \ - gtk.gdk.keyval_from_name("Shift_R"), \ - gtk.gdk.keyval_from_name("Super_L"), \ - gtk.gdk.keyval_from_name("Super_R"), \ - gtk.gdk.keyval_from_name("Hyper_L"), \ - gtk.gdk.keyval_from_name("Hyper_R"), \ - gtk.gdk.keyval_from_name("Meta_L"), \ - gtk.gdk.keyval_from_name("Meta_R"), \ - gtk.gdk.keyval_from_name("Control_L"), \ - gtk.gdk.keyval_from_name("Control_R")) - self.ctrlMods = (gtk.gdk.keyval_from_name("Control_L"), \ - gtk.gdk.keyval_from_name("Control_R")) - self.altMods = (gtk.gdk.keyval_from_name("Alt_L"), \ - gtk.gdk.keyval_from_name("Alt_R")) - self.lastKeyVal = None - self.lastKeyRepeat = 0 - - empty = gtk.gdk.Pixmap(None, 1, 1, 1) - clear = gtk.gdk.Color() - self.nullcursor = gtk.gdk.Cursor(empty, empty, clear, clear, 0, 0) - - self.set_events(gtk.gdk.EXPOSURE_MASK | - gtk.gdk.LEAVE_NOTIFY_MASK | - gtk.gdk.ENTER_NOTIFY_MASK | - gtk.gdk.KEY_RELEASE_MASK | - gtk.gdk.KEY_PRESS_MASK | - gtk.gdk.BUTTON_RELEASE_MASK | - gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.POINTER_MOTION_MASK | - gtk.gdk.POINTER_MOTION_HINT_MASK) - - self.set_property("can-focus", True) - - def get_framebuffer_name(self): - return self.fb.get_name() - - def connect_to_host(self, host, port, debug=0): - self.disconnect_from_host() - - client = GRFBNetworkClient(host, port, self.fb, debug=debug, preferred_encoding=self.preferred_encoding) - client.connect("disconnected", self._client_disconnected) - - auth_types = client.init() - - # NB we delibrately dont assign to self.client until - # we're successfully connected. - self.client = client - self.authenticated = False - self.emit("connected", host, port) - if rfb.AUTH_NONE in auth_types: - self.needpw = False - else: - self.needpw = True - return self.needpw - - def _client_disconnected(self, src): - self.client = None - self.emit("disconnected") - - def disconnect_from_host(self): - if self.client == None: - return - - # Reset server state in case we have modifiers pressed - for key in self.modifiersOn.keys(): - if not(self.client is None): - self.client.update_key(0, key) - self.modifiersOn = {} - - self.client.close() - self.client = None - self.emit("disconnected") - - def authenticate(self, password): - self.client.setpass(password) - try: - self.client.auth() - except Exception, e: - logging.warn("Failure while authenticating " + str(e)) - self.disconnect_from_host() - return 0 - self.authenticated = True - self.emit("authenticated") - return 1 - - def activate(self): - if self.client == None: - return - - self.client.start() - self.client.request_update() - self.emit("activated") - - def is_authenticated(self): - if not(self.is_connected()): - return False - return self.authenticated - - def needs_password(self): - return self.needpw - - def is_connected(self): - if self.client == None: - return False - return True - - def state_to_mask(self, state): - mask = 0 - if state & gtk.gdk.BUTTON1_MASK: - mask = mask + 1 - if state & gtk.gdk.BUTTON2_MASK: - mask = mask + 2 - if state & gtk.gdk.BUTTON3_MASK: - mask = mask + 4 - if state & gtk.gdk.BUTTON4_MASK: - mask = mask + 8 - if state & gtk.gdk.BUTTON5_MASK: - mask = mask + 16 - return mask - - def take_screenshot(self): - return self.fb.clone_pixmap() - - def pointer_move(self, win, event): - self.update_pointer(win, event) - - def pointer_press(self, win, event): - if not gtk.gdk.pointer_is_grabbed() and self.will_autograb_pointer(): - self.grab_pointer() - self.update_pointer(win, event) - - def pointer_release(self, win, event): - self.update_pointer(win, event) - - def pointer_scroll(self, win, event): - if self.client != None: - x, y, state = event.window.get_pointer() - newstate = state - if event.direction == gtk.gdk.SCROLL_UP: - newstate = newstate | gtk.gdk.BUTTON4_MASK - else: - newstate = newstate | gtk.gdk.BUTTON5_MASK - self.client.update_pointer(self.state_to_mask(newstate), x, y) - self.client.update_pointer(self.state_to_mask(state), x, y) - - def update_pointer(self, win, event): - if self.client != None: - x, y, state = event.window.get_pointer() - self.client.update_pointer(self.state_to_mask(state), x, y) - return True - - - def will_autograb_pointer(self): - return self.autograbptr - - def set_autograb_pointer(self, grab): - self.autograbptr = grab - if grab == False and gtk.gdk.pointer_is_grabbed(): - self.ungrab_pointer() - - def has_grabbed_keyboard(self): - return self.grabbedKeyboard - - def will_autograb_keyboard(self): - return self.autograbkey - - def set_autograb_keyboard(self, grab): - self.autograbkey = grab - if grab == False and self.grabbedKeyboard: - self.ungrab_keyboard() - - - def grab_pointer(self): - gtk.gdk.pointer_grab(self.window, False, - gtk.gdk.LEAVE_NOTIFY_MASK | - gtk.gdk.ENTER_NOTIFY_MASK | - gtk.gdk.BUTTON_RELEASE_MASK | - gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.POINTER_MOTION_MASK | - gtk.gdk.POINTER_MOTION_HINT_MASK, - self.window, self.nullcursor) - self.emit("pointer-grabbed") - - def ungrab_pointer(self): - gtk.gdk.pointer_ungrab() - self.emit("pointer-ungrabbed") - - def grab_keyboard(self): - gtk.gdk.keyboard_grab(self.window, False, long(0)) - for g in self.accel_groups: - self.topwin.remove_accel_group(g) - self.gtk_settings = gtk.settings_get_default() - self.gtk_settings_accel = self.gtk_settings.get_property('gtk-menu-bar-accel') - self.gtk_settings.set_property('gtk-menu-bar-accel', None) - self.grabbedKeyboard = True - self.emit("keyboard-grabbed") - - def ungrab_keyboard(self): - gtk.gdk.keyboard_ungrab() - for g in self.accel_groups: - self.topwin.add_accel_group(g) - self.gtk_settings.set_property('gtk-menu-bar-accel', self.gtk_settings_accel) - self.grabbedKeyboard = False - self.emit("keyboard-ungrabbed") - - def enter_notify(self, win, event): - if self.autograbkey: - self.grab_keyboard() - - def leave_notify(self, win, event): - if self.autograbkey: - self.ungrab_keyboard() - - def focus_in(self, win, event): - self.modifiersOn = {} - - def focus_out(self, win, event): - # Forceably release any modifiers still on - for key in self.modifiersOn.keys(): - if not(self.client is None): - self.client.update_key(0, key) - self.modifiersOn = {} - - - def key_press(self, win, event): - # Key handling in VNC is screwy. The event.keyval from GTK is - # interpreted relative to modifier state. This really messes - # up with VNC which has no concept of modifiers. If we interpret - # at client end you can end up with 'Alt' key press generating - # Alt_L, and key release generated ISO_Prev_Group. This really - # really confuses the VNC server - 'Alt' gets stuck on. - # - # So we have to redo GTK's keycode -> keyval translation - # using only the SHIFT modifier which explicitly has to be - # interpreted at client end. - map = gtk.gdk.keymap_get_default() - maskedstate = event.state & (gtk.gdk.SHIFT_MASK | gtk.gdk.LOCK_MASK) - (val,group,level,mod) = map.translate_keyboard_state(event.hardware_keycode, maskedstate, 0) - - stickyVal = None - - # Check modifiers for sticky keys, or pointer ungrab - if val in self.stickyMods: - # No previous mod pressed, start counting our presses - if self.lastKeyVal == None: - self.lastKeyVal = val - self.lastKeyRepeat = 1 - else: - # Check for Alt+Ctrl or Ctrl+Alt to release grab - if ((self.lastKeyVal in self.ctrlMods and val in self.altMods) or \ - (self.lastKeyVal in self.altMods and val in self.ctrlMods)) and \ - gtk.gdk.pointer_is_grabbed(): - self.ungrab_pointer() - - if self.lastKeyVal == val: - # Match last key pressed, so increase count - self.lastKeyRepeat = self.lastKeyRepeat + 1 - elif self.lastKeyRepeat < 3: - # Different modifier & last one was not yet - # sticky so reset it - self.lastKeyVal = None - else: - # If the prev modifier was pressed 3 times in row its sticky - if self.lastKeyVal != None and self.lastKeyRepeat >= 3: - stickyVal = self.lastKeyVal - - if self.client != None: - # Send fake sticky modifier key - if stickyVal != None: - self.client.update_key(1, stickyVal) - - self.client.update_key(1, val) - #self.client.update_key(1, event.keyval) - - if val in self.modifiers: - self.modifiersOn[val] = 1 - - return True - - def key_release(self, win, event): - # Key handling in VNC is screwy. See above - map = gtk.gdk.keymap_get_default() - maskedstate = event.state & (gtk.gdk.SHIFT_MASK | gtk.gdk.LOCK_MASK) - (val,group,level,mod) = map.translate_keyboard_state(event.hardware_keycode, maskedstate, 0) - - stickyVal = None - - if not(val in self.stickyMods): - # If a sticky modifier is active, we must release it - if self.lastKeyVal != None and self.lastKeyRepeat >= 3: - stickyVal = self.lastKeyVal - - # Release of any non-modifier clears stickyness - self.lastKeyVal = None - - if self.client != None: - if val in self.modifiers and self.modifiersOn.has_key(val): - del self.modifiersOn[val] - - self.client.update_key(0, val) - #self.client.update_key(0, event.keyval) - - # Release the sticky modifier - if stickyVal != None: - self.client.update_key(0, stickyVal) - - - return True - - def get_frame_buffer(self): - return self.fb - - def resize_display(self, fb, width, height): - self.set_size_request(width, height) - - def repaint_region(self,fb, x, y, width, height): - if self.fb.get_pixmap() == None: - return - gc = self.window.new_gc() - self.window.draw_drawable(gc, self.fb.get_pixmap(), x, y, x, y, width, height) - - def expose_region(self, win, event): - if self.fb.get_pixmap() == None: - return - gc = self.window.new_gc() - self.window.draw_drawable(gc, self.fb.get_pixmap(), event.area.x, event.area.y, event.area.x, event.area.y, event.area.width, event.area.height) - -gobject.type_register(GRFBViewer) - - -def main(): - host = sys.argv[1] - port = int(sys.argv[2]) - password = None - if len(sys.argv) == 4: - password = sys.argv[3] - - win = gtk.Window() - win.set_name("VNC") - win.connect("destroy", lambda w: gtk.main_quit()) - - pane = gtk.ScrolledWindow() - pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - win.add(pane) - - vp = gtk.Viewport() - pane.add(vp) - - vnc = GRFBViewer(win, autograbkey=True) - vp.add(vnc) - - win.show_all() - win.present() - - if vnc.connect_to_host(host, port, debug=0): - print "Need password" - if password == None: - return 1 - else: - print "No password needed" - vnc.authenticate(password) - vnc.activate() - - win.set_title(vnc.get_framebuffer_name()) - - def autosize(): - rootWidth = gtk.gdk.screen_width() - rootHeight = gtk.gdk.screen_height() - - vncWidth, vncHeight = vnc.get_size_request() - - if vncWidth > (rootWidth-200): - vncWidth = rootWidth - 200 - if vncHeight > (rootHeight-200): - vncHeight = rootHeight - 200 - - vp.set_size_request(vncWidth+3, vncHeight+3) - - def resize(src, size): - autosize() - - vnc.connect('size-request', resize) - - gtk.main() - vnc.disconnect_from_host() - -if __name__ == '__main__': - main() diff --git a/virt-manager.spec.in b/virt-manager.spec.in index a2445b55..ced8f59b 100644 --- a/virt-manager.spec.in +++ b/virt-manager.spec.in @@ -44,6 +44,8 @@ Requires: librsvg2 Requires: vte >= 0.12.2 # For online help Requires: scrollkeeper +# For console widget +Requires: gtk-vnc ExclusiveArch: %{ix86} x86_64 ia64 @@ -129,10 +131,6 @@ fi %{_datadir}/%{name}/virtManager/*.pyc %{_datadir}/%{name}/virtManager/*.pyo -%{_datadir}/%{name}/vncViewer/*.py -%{_datadir}/%{name}/vncViewer/*.pyc -%{_datadir}/%{name}/vncViewer/*.pyo - %{_datadir}/omf/%{name} %{_datadir}/gnome/help From a254e92d73f89ca7742a900bb44e857814e0363c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 20 Jul 2007 10:51:50 -0400 Subject: [PATCH 2/2] Updated for changes in GTK-VNC api --- src/virtManager/console.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/virtManager/console.py b/src/virtManager/console.py index 990aafa9..386fa618 100644 --- a/src/virtManager/console.py +++ b/src/virtManager/console.py @@ -65,7 +65,7 @@ class vmmConsole(gobject.GObject): self.vncViewer.set_keyboard_grab(True) self.vncViewer.set_pointer_grab(True) - self.vncViewer.set_sticky_modifiers(True) + #self.vncViewer.set_sticky_modifiers(True) self.vncViewer.connect("vnc-pointer-grab", self.notify_grabbed) self.vncViewer.connect("vnc-pointer-ungrab", self.notify_ungrabbed) @@ -290,7 +290,7 @@ class vmmConsole(gobject.GObject): logging.debug("Starting connect process for %s %s" % (host, str(port))) try: - self.vncViewer.open_name(host, str(port)) + self.vncViewer.open_host(host, str(port)) except: (type, value, stacktrace) = sys.exc_info () details = \