Merge heads

This commit is contained in:
Daniel P. Berrange 2007-08-15 17:29:01 -04:00
commit ce3292dcc1
10 changed files with 98 additions and 1804 deletions

1
README
View File

@ -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

View File

@ -30,7 +30,6 @@ AC_OUTPUT(Makefile
po/Makefile.in
src/Makefile
src/virtManager/Makefile
src/vncViewer/Makefile
src/graphWidgets/Makefile
man/Makefile
virt-manager.spec

View File

@ -1,5 +1,5 @@
SUBDIRS = vncViewer graphWidgets virtManager
SUBDIRS = graphWidgets virtManager
bin_SOURCES = virt-manager.in
bin_SCRIPTS = virt-manager

View File

@ -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
@ -105,13 +114,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
@ -168,18 +179,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):
@ -192,7 +203,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):
@ -206,9 +216,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
@ -219,21 +229,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()
@ -244,56 +278,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_host(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):
@ -309,10 +334,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()
@ -467,13 +492,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()
@ -495,15 +521,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

View File

@ -1,5 +0,0 @@
pythondir = $(pkgdatadir)/vncViewer
python_DATA = $(wildcard $(srcdir)/*.py)
EXTRA_DIST = $(python_DATA)

View File

@ -1,18 +0,0 @@
#
# Copyright (C) 2006 Red Hat, Inc.
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
# 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.
#

View File

@ -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 <cliechti@gmx.net>
# 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 <dzimm@widget.com>, 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 <jef@acme.com>. 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.
# <P>
# 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.
# <P>
# Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
# Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
# <P>
# <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
# <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
# <P>
# @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"))

View File

@ -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

View File

@ -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()

View File

@ -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