From 03e0425f7bf758702a84e1b906ce03cd9f9c6108 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Wed, 18 Jun 2014 18:14:36 +0200 Subject: [PATCH] customize start script --- rdpy/display/qt.py | 80 ++++++++++++++++++++++++++------ rdpy/examples/__init__.py | 0 rdpy/examples/client.py | 36 ++++++++++++++ rdpy/{ => examples}/rdpserver.py | 2 +- rdpy/protocol/rdp/pdu.py | 14 ++++-- rdpy/protocol/rdp/rdp.py | 65 ++++++++++++++++++++++++-- rdpy/protocol/rfb/rfb.py | 27 +++++++++-- rdpy/rdpclient.py | 17 ------- rdpy/{ => tests}/dotest.py | 2 +- rdpy/vncclient.py | 32 ------------- 10 files changed, 197 insertions(+), 78 deletions(-) create mode 100644 rdpy/examples/__init__.py create mode 100644 rdpy/examples/client.py rename rdpy/{ => examples}/rdpserver.py (84%) delete mode 100644 rdpy/rdpclient.py rename rdpy/{ => tests}/dotest.py (94%) delete mode 100644 rdpy/vncclient.py diff --git a/rdpy/display/qt.py b/rdpy/display/qt.py index 17cc70e..daa63c1 100644 --- a/rdpy/display/qt.py +++ b/rdpy/display/qt.py @@ -3,19 +3,21 @@ ''' from PyQt4 import QtGui, QtCore from rdpy.protocol.rfb.rfb import RfbObserver +from rdpy.protocol.rdp.rdp import RDPObserver class QAdaptor(object): ''' adaptor model with link beetween protocol and qt widget ''' - def __init__(self): + def __init__(self, qRemoteDesktop): ''' constructor must set qRemoteDesktop attribute ''' #qwidget use for render - self._qRemoteDesktop = None + self._qRemoteDesktop = qRemoteDesktop + self._qRemoteDesktop._adaptor = self def sendMouseEvent(self, e): ''' @@ -39,14 +41,21 @@ class RfbAdaptor(RfbObserver, QAdaptor): QAdaptor for specific RFB protocol stack is to an RFB observer ''' - def __init__(self, rfb): + def __init__(self, qRemoteDesktop): ''' ctor - @param rfb: RFB protocol stack + @param qRemoteDesktop: widget use for render + ''' + QAdaptor.__init__(self, qRemoteDesktop) + self._rfb = None + + def setProtocol(self, rfb): + ''' + inherit from RfbObserver + init protocol settings ''' - self._rfb = rfb #set RFB observer to - self._rfb.addObserver(self) + self._rfb = rfb def notifyFramebufferUpdate(self, width, height, x, y, pixelFormat, encoding, data): ''' @@ -92,23 +101,60 @@ class RfbAdaptor(RfbObserver, QAdaptor): @param e: qKeyEvent ''' self._rfb.sendKeyEvent(True, e.nativeVirtualKey()) - + +class RDPAdaptor(RDPObserver, QAdaptor): + ''' + Adaptor for RDP client + ''' + def __init__(self, qRemoteDesktop): + ''' + constructor + @param qRemoteDesktop: widget use for render + ''' + QAdaptor.__init__(self, qRemoteDesktop) + + def notifyBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): + ''' + notify bitmap update + @param destLeft: xmin position + @param destTop: ymin position + @param destRight: xmax position because RDP can send bitmap with padding + @param destBottom: ymax position because RDP can send bitmap with padding + @param width: width of bitmap + @param height: height of bitmap + @param bitsPerPixel: number of bit per pixel + @param isCompress: use RLE compression + @param data: bitmap data + ''' + #TODO + if isCompress: + return + + imageFormat = None + if bitsPerPixel == 16: + imageFormat = QtGui.QImage.Format_RGB16 + elif bitsPerPixel == 24: + imageFormat = QtGui.QImage.Format_RGB888 + elif bitsPerPixel == 32: + imageFormat = QtGui.QImage.Format_RGB32 + else: + print "Receive image in bad format" + return + + image = QtGui.QImage(data, width, height, imageFormat) + self._qRemoteDesktop.notifyImage(destLeft, destTop, image) class QRemoteDesktop(QtGui.QWidget): ''' qt display widget ''' - def __init__(self, adaptor): + def __init__(self): ''' constructor - @param adaptor: any object which inherit - from QAdaptor (RfbAdaptor | RdpAdaptor) ''' super(QRemoteDesktop, self).__init__() - #set adaptor - self._adaptor = adaptor - #set widget attribute of adaptor - self._adaptor._qRemoteDesktop = self + #set by adaptor + self._adaptor = None #refresh stack of image #because we can update image only in paint #event function. When protocol receive image @@ -153,6 +199,8 @@ class QRemoteDesktop(QtGui.QWidget): call when mouse move @param event: qMouseEvent ''' + if self._adaptor is None: + print "No adaptor to send mouse move event" self._adaptor.sendMouseEvent(event) def mousePressEvent(self, event): @@ -160,6 +208,8 @@ class QRemoteDesktop(QtGui.QWidget): call when button mouse is pressed @param event: qMouseEvent ''' + if self._adaptor is None: + print "No adaptor to send mouse press event" self._adaptor.sendMouseEvent(event) def keyPressEvent(self, event): @@ -167,4 +217,6 @@ class QRemoteDesktop(QtGui.QWidget): call when button key is pressed @param event: qKeyEvent ''' + if self._adaptor is None: + print "No adaptor to send key press event" self._adaptor.sendKeyEvent(event) \ No newline at end of file diff --git a/rdpy/examples/__init__.py b/rdpy/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rdpy/examples/client.py b/rdpy/examples/client.py new file mode 100644 index 0000000..c68f52f --- /dev/null +++ b/rdpy/examples/client.py @@ -0,0 +1,36 @@ +''' +@author: citronneur +''' +import sys +import os +# Change path so we find rdpy +sys.path.insert(1, os.path.join(sys.path[0], '../..')) + +from PyQt4 import QtGui +from rdpy.display.qt import RDPAdaptor, RfbAdaptor, QRemoteDesktop +from rdpy.protocol.rdp import rdp +from rdpy.protocol.rfb import rfb + +if __name__ == '__main__': + #create application + app = QtGui.QApplication(sys.argv) + + #add qt4 reactor + import qt4reactor + qt4reactor.install() + + #create widget + w = QRemoteDesktop() + w.resize(1024, 800) + w.setWindowTitle('rdpyclient') + w.show() + + if sys.argv[3] == 'rdp': + factory = rdp.Factory(RDPAdaptor(w)) + else: + factory = rfb.ClientFactory(RfbAdaptor(w)) + + from twisted.internet import reactor + reactor.connectTCP(sys.argv[1], int(sys.argv[2]), factory) + reactor.run() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/rdpy/rdpserver.py b/rdpy/examples/rdpserver.py similarity index 84% rename from rdpy/rdpserver.py rename to rdpy/examples/rdpserver.py index 9a2cd26..9125de5 100644 --- a/rdpy/rdpserver.py +++ b/rdpy/examples/rdpserver.py @@ -4,7 +4,7 @@ import sys, os # Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) +sys.path.insert(1, os.path.join(sys.path[0], '../..')) from rdpy.protocol.rdp import rdp from rdpy.network.layer import LayerMode diff --git a/rdpy/protocol/rdp/pdu.py b/rdpy/protocol/rdp/pdu.py index eb2e12b..b455b46 100644 --- a/rdpy/protocol/rdp/pdu.py +++ b/rdpy/protocol/rdp/pdu.py @@ -701,7 +701,7 @@ class PDU(LayerAutomata): Global channel for mcs that handle session identification user, licensing management, and capabilities exchange ''' - def __init__(self, mode): + def __init__(self, mode, dispatcher): ''' Constructor ''' @@ -742,6 +742,9 @@ class PDU(LayerAutomata): #share id between client and server self._shareId = UInt32Le() + #rdp observer + self._dispatcher = dispatcher + def connect(self): ''' connect event in client mode send logon info @@ -793,9 +796,9 @@ class PDU(LayerAutomata): if dataPDU.shareDataHeader.pduType2 != PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: return dataPDU - message = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value) - if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): - message = ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] + message = "Unknown code %s"%hex(dataPDU.pduData._value.errorInfo.value) + if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData._value.errorInfo): + message = ErrorInfo._MESSAGES_[dataPDU.pduData._value.errorInfo] raise ErrorReportedFromPeer("Receive PDU Error info : %s"%message) @@ -867,6 +870,9 @@ class PDU(LayerAutomata): @param data: Stream from transport layer ''' dataPDU = self.readDataPDU(data) + if dataPDU.shareDataHeader.pduType2 == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData._value.updateType == UpdateType.UPDATETYPE_BITMAP: + self._dispatcher.recvBitmapUpdateDataPDU(dataPDU.pduData._value.updateData._value) + def sendConfirmActivePDU(self): ''' diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 0e6f2ca..fb63951 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -3,15 +3,51 @@ ''' from twisted.internet import protocol import tpkt, tpdu, mcs, pdu +from rdpy.network.layer import LayerMode + +class RDP(object): + ''' + use to decode and dispatch to observer PDU message and orders + ''' + def __init__(self): + ''' + ctor + ''' + #list of observer + self._observers = [] + + def addObserver(self, observer): + ''' + add observer to rdp protocol + @param observer: new observer to add + ''' + self._observers.append(observer) + + def recvBitmapUpdateDataPDU(self, bitmapUpdateData): + ''' + call when a bitmap data is received from update pdu + @param bitmapData: pdu.BitmapData struct + ''' + for observer in self._observers: + #for each rectangle in update PDU + for rectangle in bitmapUpdateData.rectangles._array: + observer.notifyBitmapUpdate(rectangle.destLeft.value, rectangle.destTop.value, rectangle.destRight.value, rectangle.destBottom.value, rectangle.width.value, rectangle.height.value, rectangle.bitsPerPixel.value, rectangle.flags | pdu.BitmapFlag.BITMAP_COMPRESSION, rectangle.bitmapDataStream.value) + class Factory(protocol.Factory): ''' - Factory of RDP protocol + Factory of Client RDP protocol ''' - def __init__(self, mode): - self._mode = mode + def __init__(self, observer): + ''' + ctor + @param observer: observer use by rdp protocol to handle events + ''' + self._observer = observer def buildProtocol(self, addr): - return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pdu.PDU(self._mode)))); + rdp = RDP() + rdp.addObserver(self._observer) + return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pdu.PDU(LayerMode.CLIENT, rdp)))); def startedConnecting(self, connector): print 'Started to connect.' @@ -20,4 +56,23 @@ class Factory(protocol.Factory): print 'Lost connection. Reason:', reason def clientConnectionFailed(self, connector, reason): - print 'Connection failed. Reason:', reason \ No newline at end of file + print 'Connection failed. Reason:', reason + +class RDPObserver(object): + ''' + class use to inform all rdp event handle by RDPY + ''' + def notifyBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): + ''' + notify bitmap update + @param destLeft: xmin position + @param destTop: ymin position + @param destRight: xmax position because RDP can send bitmap with padding + @param destBottom: ymax position because RDP can send bitmap with padding + @param width: width of bitmap + @param height: height of bitmap + @param bitsPerPixel: number of bit per pixel + @param isCompress: use RLE compression + @param data: bitmap data + ''' + pass \ No newline at end of file diff --git a/rdpy/protocol/rfb/rfb.py b/rdpy/protocol/rfb/rfb.py index f7e1acf..6842953 100644 --- a/rdpy/protocol/rfb/rfb.py +++ b/rdpy/protocol/rfb/rfb.py @@ -357,6 +357,7 @@ class Rfb(RawLayer): ''' for observer in self._observer: observer.notifyFramebufferUpdate(self._currentRect.width.value, self._currentRect.height.value, self._currentRect.x.value, self._currentRect.y.value, self._pixelFormat, self._currentRect.encoding, data.getvalue()) + self._nbRect = self._nbRect - 1 #if there is another rect to read if self._nbRect == 0: @@ -410,15 +411,26 @@ class Rfb(RawLayer): ''' self.send((ClientToServerMessages.CUT_TEXT, ClientCutText(text))) -class Factory(protocol.Factory): +class ClientFactory(protocol.Factory): ''' Factory of RFB protocol ''' - def __init__(self, mode): - self._protocol = Rfb(mode) + def __init__(self, observer): + ''' + save mode and adapter + @param adapter: graphic client adapter + ''' + self._observer = observer def buildProtocol(self, addr): - return self._protocol; + ''' + function call by twisted on connection + @param addr: adresse where client try to connect + ''' + protocol = Rfb(LayerMode.CLIENT) + protocol.addObserver(self._observer) + self._observer.setProtocol(protocol) + return protocol def startedConnecting(self, connector): print 'Started to connect.' @@ -444,4 +456,11 @@ class RfbObserver(object): @param encoding : encoding struct from rfb.types @param data : in respect of dataFormat and pixelFormat ''' + pass + + def setProtocol(self, rfbLayer): + ''' + call when observer is added to an rfb layer + @param: rfbLayer layer inform the observer + ''' pass \ No newline at end of file diff --git a/rdpy/rdpclient.py b/rdpy/rdpclient.py deleted file mode 100644 index e520543..0000000 --- a/rdpy/rdpclient.py +++ /dev/null @@ -1,17 +0,0 @@ -''' -Created on 4 sept. 2013 - -@author: sylvain -''' - -import sys, os -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - -from rdpy.protocol.rdp import rdp -from rdpy.network.layer import LayerMode - -if __name__ == '__main__': - from twisted.internet import reactor - reactor.connectTCP("192.168.135.59", 3389, rdp.Factory(LayerMode.CLIENT)) - reactor.run() \ No newline at end of file diff --git a/rdpy/dotest.py b/rdpy/tests/dotest.py similarity index 94% rename from rdpy/dotest.py rename to rdpy/tests/dotest.py index 0645d14..12ea828 100644 --- a/rdpy/dotest.py +++ b/rdpy/tests/dotest.py @@ -3,7 +3,7 @@ ''' import sys, os # Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) +sys.path.insert(1, os.path.join(sys.path[0], '../..')) import unittest, rdpy.tests.network.type, rdpy.tests.network.const, rdpy.tests.network.layer def headerTest(name): diff --git a/rdpy/vncclient.py b/rdpy/vncclient.py deleted file mode 100644 index 6a86d11..0000000 --- a/rdpy/vncclient.py +++ /dev/null @@ -1,32 +0,0 @@ -''' -@author: sylvain -''' - -import sys -import os -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - -from PyQt4 import QtGui -from rdpy.display.qt import RfbAdaptor, QRemoteDesktop -from rdpy.protocol.rfb import rfb -from rdpy.network.layer import LayerMode - -if __name__ == '__main__': - #create application - app = QtGui.QApplication(sys.argv) - - #add qt4 reactor - import qt4reactor - qt4reactor.install() - - #create rfb protocol - factory = rfb.Factory(LayerMode.CLIENT) - w = QRemoteDesktop(RfbAdaptor(factory._protocol)) - w.resize(1000, 700) - w.setWindowTitle('vncclient') - w.show() - from twisted.internet import reactor - reactor.connectTCP("127.0.0.1", 5903, factory) - reactor.run() - sys.exit(app.exec_()) \ No newline at end of file