close cleanly connection

This commit is contained in:
speyrefitte
2014-07-29 18:01:34 +02:00
parent 3319b86d66
commit be1eb94920
7 changed files with 445 additions and 88 deletions

View File

@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from twisted.mail.pop3client import ERR
"""
RDP proxy recorder and spy function
@@ -34,16 +35,56 @@ from twisted.internet import reactor
from PyQt4 import QtCore, QtGui
class IProxyClient(object):
"""
Interface use by Proxy server to interact with client
"""
def close(self):
"""
Close proxy client
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getColorDepth", "IProxyClient"))
def getColorDepth(self):
pass
"""
Color depth client, Use to re-negociate color depth with server
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getColorDepth", "IProxyClient"))
def sendKeyEventScancode(self, code, isPressed):
pass
"""
Key event as scan code
@param code: scan code of key
@param isPressed: True if key is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEventScancode", "IProxyClient"))
def sendKeyEventUnicode(self, code, isPressed):
pass
"""
Key event as unicode
@param code: unicode of key
@param isPressed: True if key is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEventUnicode", "IProxyClient"))
def sendPointerEvent(self, x, y, button, isPressed):
pass
"""
Mouse event
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendPointerEvent", "IProxyClient"))
def sendRefreshOrder(self, left, top, right, bottom):
pass
"""
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendRefreshOrder", "IProxyClient"))
class ProxyServer(rdp.RDPServerObserver):
"""
@@ -92,6 +133,13 @@ class ProxyServer(rdp.RDPServerObserver):
#refresh client
width, height = self._controller.getScreen()
self._client.sendRefreshOrder(0, 0, width, height)
def onClose(self):
"""
Call when client close connection
"""
if not self._client is None:
self._client.close()
def onKeyEventScancode(self, code, isPressed):
"""
@@ -111,7 +159,7 @@ class ProxyServer(rdp.RDPServerObserver):
@param code: unicode of key
@param isPressed: True if key is down
"""
#no client connectedomaind
#no client connected domain
if self._client is None:
return
@@ -135,7 +183,8 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
"""
Client side of proxy
"""
def __init__(self, controller, server):
_CONNECTED_ = {}
def __init__(self, controller, server, name):
"""
@param controller: RDPClientObserver
@param server: ProxyServer
@@ -143,6 +192,7 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
"""
rdp.RDPClientObserver.__init__(self, controller)
self._server = server
self._name = name
def onReady(self):
"""
@@ -150,8 +200,23 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
Inform proxy server that i'm connected
implement RDPClientObserver
"""
ProxyClient._CONNECTED_[self._name] = self
self._server.clientConnected(self)
def onClose(self):
"""
Stack is closes
"""
if ProxyClient._CONNECTED_.has_key(self._name):
del ProxyClient._CONNECTED_[self._name]
self._server._controller.close()
def close(self):
"""
Close proxy client
"""
self._controller.close()
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Event use to inform bitmap update
@@ -169,18 +234,44 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
def getColorDepth(self):
"""
Color depth client, Use to re-negociate color depth with server
"""
return self._controller.getColorDepth()
def sendKeyEventScancode(self, code, isPressed):
"""
Key event as scan code
@param code: scan code of key
@param isPressed: True if key is down
"""
self._controller.sendKeyEventScancode(code, isPressed)
def sendKeyEventUnicode(self, code, isPressed):
"""
Key event as uni code
@param code: uni code of key
@param isPressed: True if key is down
"""
self._controller.sendKeyEventUnicode(code, isPressed)
def sendPointerEvent(self, x, y, button, isPressed):
"""
Mouse event
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
self._controller.sendPointerEvent(x, y, button, isPressed)
def sendRefreshOrder(self, left, top, right, bottom):
"""
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
self._controller.sendRefreshOrder(left, top, right, bottom)
class ProxyServerFactory(rdp.ServerFactory):
@@ -192,7 +283,7 @@ class ProxyServerFactory(rdp.ServerFactory):
@param config: rdp-proxy configuration
@param credentialProvider: CredentialProvider
"""
rdp.ServerFactory.__init__(self, "/home/sylvain/dev/certificate/rdpy.key", "/home/sylvain/dev/certificate/rdpy.crt", 16)
rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt", 16)
self._credentialProvider = credentialProvider
def buildObserver(self, controller):
@@ -201,21 +292,11 @@ class ProxyServerFactory(rdp.ServerFactory):
@param controller: rdp.RDPServerController
"""
return ProxyServer(controller, self._credentialProvider)
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
pass
def clientConnectionFailed(self, connector, reason):
pass
class ProxyClientFactory(rdp.ClientFactory):
"""
Factory for proxy client
"""
_CLIENT_PROXY_ = {}
def __init__(self, server, width, height, domain, username, password, name):
"""
@param server: ProxyServer
@@ -224,6 +305,7 @@ class ProxyClientFactory(rdp.ClientFactory):
@param domain: domain session
@param username: username session
@param password: password session
@param name: name of session
"""
self._server = server
self._width = width
@@ -245,21 +327,128 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setDomain(self._domain)
controller.setUsername(self._username)
controller.setPassword(self._password)
proxy = ProxyClient(controller, self._server)
ProxyClientFactory._CLIENT_PROXY_[self._name] = proxy
proxy = ProxyClient(controller, self._server, self._name)
return proxy
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name):
del ProxyClientFactory._CLIENT_PROXY_[self._name]
pass
def clientConnectionFailed(self, connector, reason):
if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name):
del ProxyClientFactory._CLIENT_PROXY_[self._name]
pass
class ProxyAdmin(IProxyClient):
"""
Use to manage client side of admin session
Add GUI to select which session to see
And manage see session
Just escape key is authorized during see session
"""
class State(object):
"""
GUI state -> list of active session
SPY state -> watch active session
"""
GUI = 0
SPY = 1
def __init__(self, server):
"""
@param server: rdp.RDPServerController
"""
self._server = server
self._spyProxy = None
self.initView()
self._state = ProxyAdmin.State.GUI
def initView(self):
"""
Init GUI view
"""
width, height = self._server._controller.getScreen()
self._window = view.WindowView(width, height, QtGui.QColor(24, 93, 123))
self._window.addView(view.AnchorView(width / 2 - 250, height / 2 - 250, view.ListView(ProxyClient._CONNECTED_.keys(), 500, 500, self.onSelect, QtGui.QColor(24, 93, 123))))
self._render = view.RDPRenderer(self._server._controller)
def close(self):
"""
Close proxy client
"""
pass
def getColorDepth(self):
"""
Use same Color depth as server init
@return color depth of GUI
"""
if self._state == ProxyAdmin.State.GUI:
return self._server._controller.getColorDepth()
elif self._state == ProxyAdmin.State.SPY:
return self._spyProxy.getColorDepth()
def sendKeyEventScancode(self, code, isPressed):
"""
IProxyClient implement is unauthorized during admin session
Only for GUI
@param code: scan code of key
@param isPressed: True if key is down
"""
if self._state == ProxyAdmin.State.GUI:
if not isPressed:
return
self._window.keyEvent(code)
self._window.update(self._render)
elif code == 1:
#escape button refresh GUI
self._spyProxy._controller.removeClientObserver(self._spyProxy)
self._state = ProxyAdmin.State.GUI
self._server.clientConnected(self)
def sendKeyEventUnicode(self, code, isPressed):
"""
Key event as uni code is unauthorized during admin session
@param code: uni code of key
@param isPressed: True if key is down
"""
pass
def sendPointerEvent(self, x, y, button, isPressed):
"""
Mouse event is unauthorized during admin session
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
pass
def sendRefreshOrder(self, left, top, right, bottom):
"""
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
if self._state == ProxyAdmin.State.GUI:
self._window.update(self._render)
elif self._state == ProxyAdmin.State.SPY:
self._spyProxy.sendRefreshOrder(left, top, right, bottom)
def onSelect(self, name):
"""
Call back of list view
@param name: name selected by user
"""
if not ProxyClient._CONNECTED_.has_key(name):
return
self._spyProxy = ProxyClient(ProxyClient._CONNECTED_[name]._controller, self._server, "Admin")
self._state = ProxyAdmin.State.SPY
#reconnect me
self._server.clientConnected(self)
class CredentialProvider(object):
"""
Credential provider for proxy
@@ -293,33 +482,7 @@ class CredentialProvider(object):
"""
account = self.getAccount(domain, username)
return account.has_key("admin") and account["admin"] and account.has_key("password") and str(account["password"]) == password
class ProxyAdmin(IProxyClient):
"""
Use to manage client side of admin session
Add GUI to select wich session to see
"""
def __init__(self, server):
self._server = server
self._list = view.ListView(ProxyClientFactory._CLIENT_PROXY_.keys(), 300, 300, self.onSelect)
self._render = view.RDPRenderer(self._server._controller)
self._list.update(self._render)
def getColorDepth(self):
return 16
def sendKeyEventScancode(self, code, isPressed):
if isPressed:
self._list.keyEvent(code)
self._list.update(self._render)
def sendKeyEventUnicode(self, code, isPressed):
pass
def sendPointerEvent(self, x, y, button, isPressed):
pass
def sendRefreshOrder(self, left, top, right, bottom):
self._list.update(self._render)
def onSelect(self, name):
if ProxyClientFactory._CLIENT_PROXY_.has_key(name):
self._server.clientConnected(ProxyClient(ProxyClientFactory._CLIENT_PROXY_[name]._controller, self._server))
def help():
"""
Print help in console

View File

@@ -108,9 +108,63 @@ class LayerAutomata(Layer, IStreamListener):
#twisted layer concept
from twisted.internet import protocol
from twisted.internet.abstract import FileDescriptor
#first that handle stream
from type import Stream
class RawLayerClientFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer client factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
rawLayer.setFactory(self)
return rawLayer
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
def connectionLost(self, rawlayer):
"""
Overirde this method to handle connection lost
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayerServerFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer server factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
rawLayer.setFactory(self)
return rawLayer
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
def connectionLost(self, rawlayer):
"""
Overirde this method to handle connection lost
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
"""
Inherit from protocol twisted class
@@ -127,6 +181,14 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
self._buffer = ""
#len of next packet pass to next state function
self._expectedLen = 0
self._factory = None
def setFactory(self, factory):
"""
Call by RawLayer Factory
@param param: RawLayerClientFactory or RawLayerFactory
"""
self._factory = factory
def dataReceived(self, data):
"""
@@ -152,11 +214,14 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
#join two scheme
self.connect()
def connectionLost(self, reason):
self._factory.connectionLost(self)
def close(self):
"""
Close raw layer
"""
self.transport.loseConnection()
FileDescriptor.loseConnection(self.transport)
def expect(self, expectedLen, callback = None):
"""

View File

@@ -25,7 +25,7 @@ In this layer are managed all mains bitmap update orders end user inputs
from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
import caps
import caps, order
class SecurityFlag(object):
"""
@@ -930,17 +930,7 @@ class OrderUpdateDataPDU(CompositeType):
self.pad2OctetsA = UInt16Le()
self.numberOrders = UInt16Le(lambda:len(self.orderData._array))
self.pad2OctetsB = UInt16Le()
self.orderData = ArrayType(DrawingOrder, readLen = self.numberOrders)
class DrawingOrder(CompositeType):
"""
GDI drawing orders
@see: http://msdn.microsoft.com/en-us/library/cc241574.aspx
@todo: not implemented yet but need it
"""
def __init__(self):
CompositeType.__init__(self)
self.controlFlags = UInt8()
self.orderData = ArrayType(order.DrawingOrder, readLen = self.numberOrders)
class BitmapCompressedDataHeader(CompositeType):
"""

View File

@@ -573,10 +573,11 @@ class Server(PDULayer, tpkt.IFastPathListener):
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT:
self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array)
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST:
log.debug("Receive Shutdown Request")
self._transport.close()
def recvFastPath(self, fastPathS):
"""r
"""
Implement IFastPathListener interface
Fast path is needed by RDP 8.0
@param fastPathS: Stream that contain fast path data

View File

@@ -0,0 +1,45 @@
#
# Copyright (c) 2014 Sylvain Peyrefitte
#
# This file is part of rdpy.
#
# rdpy 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 3 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, see <http://www.gnu.org/licenses/>.
#
"""
GDI order structure
"""
from rdpy.network.type import CompositeType, UInt8
class ControlFlag(object):
TS_STANDARD = 0x01
TS_SECONDARY = 0x02
class DrawingOrder(CompositeType):
"""
GDI drawing orders
@see: http://msdn.microsoft.com/en-us/library/cc241574.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.controlFlags = UInt8()
class PrimaryDrawingOrder(CompositeType):
"""
GDI Primary drawing order
@see: http://msdn.microsoft.com/en-us/library/cc241586.aspx
"""
def __init__(self):
CompositeType.__init__(self)

View File

@@ -21,7 +21,7 @@
Use to manage RDP stack in twisted
"""
from twisted.internet import protocol
from rdpy.network import layer
from rdpy.base.error import CallPureVirtualFuntion, InvalidValue
import pdu.layer
import pdu.data
@@ -46,7 +46,6 @@ class RDPClientController(pdu.layer.PDUClientListener):
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
#is pdu layer is ready to send
self._isReady = False
self._sendReady = False
def getProtocol(self):
"""
@@ -112,6 +111,16 @@ class RDPClientController(pdu.layer.PDUClientListener):
"""
self._clientObserver.append(observer)
def removeClientObserver(self, observer):
"""
Remove observer to RDP protocol stack
@param observer: observer to remove
"""
for i in range(0, len(self._clientObserver)):
if self._clientObserver[i] == observer:
del self._clientObserver[i]
return
def onUpdate(self, rectangles):
"""
Call when a bitmap data is received from update PDU
@@ -127,12 +136,17 @@ class RDPClientController(pdu.layer.PDUClientListener):
Call when PDU layer is connected
"""
self._isReady = True
if self._sendReady:
return
self._sendReady = False
#signal all listener
for observer in self._clientObserver:
observer.onReady()
def onClose(self):
"""
Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._clientObserver:
observer.onClose()
def sendPointerEvent(self, x, y, button, isPressed):
"""
@@ -260,6 +274,12 @@ class RDPServerController(pdu.layer.PDUServerListener):
#set color depth of session
self.setColorDepth(colorDepth)
def close(self):
"""
Close protocol stack
"""
self._pduLayer.close()
def getProtocol(self):
"""
@return: the twisted protocol layer
@@ -342,6 +362,14 @@ class RDPServerController(pdu.layer.PDUServerListener):
for observer in self._serverObserver:
observer.onReady()
def onClose(self):
"""
Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._serverObserver:
observer.onClose()
def onSlowPathInput(self, slowPathInputEvents):
"""
Event call when slow path input are available
@@ -388,27 +416,36 @@ class RDPServerController(pdu.layer.PDUServerListener):
self._pduLayer.sendBitmapUpdatePDU([bitmapData])
class ClientFactory(protocol.Factory):
class ClientFactory(layer.RawLayerClientFactory):
"""
Factory of Client RDP protocol
"""
def buildProtocol(self, addr):
def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
def buildRawLayer(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
controller = RDPClientController()
self.buildObserver(controller)
return controller.getProtocol();
controller.getProtocol()._factory = self
return controller.getProtocol()
def buildObserver(self, controller):
'''
build observer use for connection
'''
"""
Build observer use for connection
@param controller: RDPClientController
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
class ServerFactory(protocol.Factory):
class ServerFactory(layer.RawLayerServerFactory):
"""
Factory of Server RDP protocol
"""
@@ -421,14 +458,23 @@ class ServerFactory(protocol.Factory):
self._privateKeyFileName = privateKeyFileName
self._certificateFileName = certificateFileName
self._colorDepth = colorDepth
def buildProtocol(self, addr):
def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
def buildRawLayer(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
controller = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth)
self.buildObserver(controller)
controller.getProtocol()._factory = self
return controller.getProtocol()
def buildObserver(self, controller):
@@ -455,6 +501,12 @@ class RDPClientObserver(object):
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
def onClose(self):
"""
Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Notify bitmap update
@@ -488,6 +540,12 @@ class RDPServerObserver(object):
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPServerObserver"))
def onClose(self):
"""
Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onKeyEventScancode(self, code, isPressed):
"""
Event call when a keyboard event is catch in scan code format

View File

@@ -20,7 +20,7 @@
"""
Fake widget
"""
from rdpy.base.error import CallPureVirtualFuntion
from rdpy.base.error import CallPureVirtualFuntion, InvalidExpectedDataException
from PyQt4 import QtGui, QtCore
@@ -34,6 +34,8 @@ class IRender(object):
pass
def drawImage(self, image):
pass
def getImageFormat(self):
pass
class IView(object):
def keyEvent(self, code):
@@ -54,20 +56,19 @@ class AnchorView(IView):
self._view.pointerEvent(x - self._x, y - self._y)
def update(self, render):
render.translate(self._x, self._y)
self._view.update(self._view, render)
self._view.update(render)
render.translate(- self._x, - self._y)
class ListView(IView):
"""
List widget simulate by QT painter
"""
def __init__(self, labels, width, height, callback):
def __init__(self, labels, width, height, callback, backgroudColor = QtCore.Qt.black):
self._labels = labels
self._width = width
self._height = height
self._cellHeight = 25
self._backGroudColor = QtGui.QColor(24, 93, 123)
self._backgroudColor = backgroudColor
self._fontSize = 14
self._current = 0
self._callback = callback
@@ -91,9 +92,9 @@ class ListView(IView):
Draw GUI that list active session
"""
i = 0
drawArea = QtGui.QImage(self._width, self._height, QtGui.QImage.Format_RGB16)
drawArea = QtGui.QImage(self._width, self._height, render.getImageFormat())
#fill with background Color
drawArea.fill(self._backGroudColor)
drawArea.fill(self._backgroudColor)
with QtGui.QPainter(drawArea) as qp:
for label in self._labels:
rect = QtCore.QRect(0, i * self._cellHeight, self._width, self._cellHeight)
@@ -105,6 +106,29 @@ class ListView(IView):
qp.drawText(rect, QtCore.Qt.AlignCenter, label)
i += 1
render.drawImage(drawArea)
class WindowView(IView):
def __init__(self, width, height, backgroundColor = QtCore.Qt.black):
self._views = []
self._focusIndex = 0
self._width = width
self._height = height
self._backgroundColor = backgroundColor
def addView(self, view):
self._views.append(view)
def keyEvent(self, code):
if self._focusIndex < len(self._views):
self._views[self._focusIndex].keyEvent(code)
def pointerEvent(self, x, y, button):
if self._focusIndex < len(self._views):
self._views[self._focusIndex].pointerEvent(x, y, button)
def update(self, render):
drawArea = QtGui.QImage(self._width, self._height, render.getImageFormat())
#fill with background Color
drawArea.fill(self._backgroundColor)
render.drawImage(drawArea)
for view in self._views:
view.update(render)
class RDPRenderer(object):
def __init__(self, server):
@@ -112,10 +136,21 @@ class RDPRenderer(object):
@param server: RDPServerController
"""
self._server = server
self._colorDepth = self._server.getColorDepth()
self._dx = 0
self._dy = 0
self._renderSize = 64
def getImageFormat(self):
if self._colorDepth == 15:
return QtGui.QImage.Format_RGB15
elif self._colorDepth == 16:
return QtGui.QImage.Format_RGB16
elif self._colorDepth == 24:
return QtGui.QImage.Format_RGB24
elif self._colorDepth == 32:
return QtGui.QImage.Format_RGB32
def translate(self, dx, dy):
self._dx += dx
self._dy += dy
@@ -133,5 +168,5 @@ class RDPRenderer(object):
tmp = tmp.transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
ptr = tmp.bits()
ptr.setsize(tmp.byteCount())
self._server.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), 16, False, ptr.asstring())
self._server.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), self._colorDepth, False, ptr.asstring())