diff --git a/.travis.yml b/.travis.yml index 95b7787..6b31fad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,13 @@ python: - 2.7 before_install: - - sudo apt-get install python-qt4 python-sip-dev + - sudo apt-get install python-qt4 - ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ - ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ - - ln -s /usr/lib/python2.7/dist-packages/sipdistutils.py $VIRTUAL_ENV/lib/python2.7/site-packages/ - - ln -s /usr/lib/python2.7/dist-packages/sipconfig.py $VIRTUAL_ENV/lib/python2.7/site-packages/ - - ln -s /usr/lib/python2.7/dist-packages/sipconfig_nd.py $VIRTUAL_ENV/lib/python2.7/site-packages/ - - pip install twisted pyopenssl qt4reactor + - pip install qt4reactor pyopenssl twisted install: - - scons -C rdpy/core install + - python setup.py install script: - python -m unittest discover -s test -v diff --git a/README.md b/README.md index bc9130b..09754dc 100644 --- a/README.md +++ b/README.md @@ -8,28 +8,30 @@ RDPY is a pure Python implementation ot the Microsoft RDP (Remote Desktop Protoc ## Build -RDPY is fully implemented in python, except the bitmap uncompression algorithm which is implemented in C and binded with SIP (originally conceived for the PyQt project) for performance purposes. +RDPY is fully implemented in python, except the bitmap uncompression algorithm which is implemented in C for performance purposes. ### Depends * python2.7 -* python-twisted -* python-openssl * python-qt4 -* python-qt4reactor -* python-sip-dev -* scons ### Make ``` $ git clone https://github.com/citronneur/rdpy.git rdpy -$ scons -C rdpy/rdpy/core install +$ pip install twisted pyopenssl qt4reactor +$ python rdpy/setup.py install +``` + +For virtualenv, tou need to link qt4 library to it: +``` +ln -s /usr/lib/python2.7/dist-packages/PyQt4/ $VIRTUAL_ENV/lib/python2.7/site-packages/ +ln -s /usr/lib/python2.7/dist-packages/sip.so $VIRTUAL_ENV/lib/python2.7/site-packages/ ``` ## RDPY Binaries -RDPY comes with some very useful binaries; These binaries are linux and windows compatible. Pre-built binaries will be delivered with the first release of the project. +RDPY comes with some very useful binaries; These binaries are linux and windows compatible. ### rdpy-rdpclient diff --git a/bin/rdpy-rdpclient b/bin/rdpy-rdpclient index 5ee7c76..1424e81 100755 --- a/bin/rdpy-rdpclient +++ b/bin/rdpy-rdpclient @@ -24,9 +24,6 @@ example of use rdpy as rdp client import sys, os, getopt -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - from PyQt4 import QtGui from rdpy.ui.qt4 import RDPClientQt from rdpy.protocol.rdp import rdp diff --git a/bin/rdpy-rdpproxy b/bin/rdpy-rdpproxy index b42da23..97950e1 100755 --- a/bin/rdpy-rdpproxy +++ b/bin/rdpy-rdpproxy @@ -30,8 +30,6 @@ Admin ----------------------| """ import sys, os, getopt, json -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) from rdpy.base import log, error from rdpy.protocol.rdp import rdp diff --git a/bin/rdpy-rdpscreenshot b/bin/rdpy-rdpscreenshot index beb40ce..01791ff 100755 --- a/bin/rdpy-rdpscreenshot +++ b/bin/rdpy-rdpscreenshot @@ -25,9 +25,6 @@ take screenshot of login page import sys, os, getopt -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - from PyQt4 import QtCore, QtGui from rdpy.protocol.rdp import rdp from rdpy.ui.qt4 import RDPBitmapToQtImage diff --git a/bin/rdpy-vncclient b/bin/rdpy-vncclient index 689e181..dbc4861 100755 --- a/bin/rdpy-vncclient +++ b/bin/rdpy-vncclient @@ -23,10 +23,6 @@ example of use rdpy as VNC client """ import sys, os, getopt - -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - from PyQt4 import QtGui from rdpy.ui.qt4 import RFBClientQt from rdpy.protocol.rfb import rfb diff --git a/bin/rdpy-vncscreenshot b/bin/rdpy-vncscreenshot index 8cb4b8a..89486f2 100755 --- a/bin/rdpy-vncscreenshot +++ b/bin/rdpy-vncscreenshot @@ -24,10 +24,6 @@ take screenshot of login page """ import sys, os, getopt - -# Change path so we find rdpy -sys.path.insert(1, os.path.join(sys.path[0], '..')) - from PyQt4 import QtCore, QtGui from rdpy.protocol.rfb import rfb import rdpy.base.log as log diff --git a/rdpy/core/src/rle/rle.c b/ext/rle.c similarity index 95% rename from rdpy/core/src/rle/rle.c rename to ext/rle.c index 913405d..2d7da8d 100644 --- a/rdpy/core/src/rle/rle.c +++ b/ext/rle.c @@ -24,12 +24,11 @@ /* indent is confused by this file */ /* *INDENT-OFF* */ -#include "rle.h" +#include /* Specific rename for RDPY integration */ #define uint8 unsigned char #define uint16 unsigned short -#define NULL 0 #define unimpl(str, code) #define RD_BOOL int @@ -891,8 +890,8 @@ bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int siz } /* main decompress function */ -int -bitmap_decompress(char * output, int width, int height, char * input, int size, int Bpp) +static int +bitmap_decompress(uint8 * output, int width, int height, uint8* input, int size, int Bpp) { RD_BOOL rv = False; @@ -918,3 +917,31 @@ bitmap_decompress(char * output, int width, int height, char * input, int size, } /* *INDENT-ON* */ + +static PyObject* +bitmap_decompress_wrapper(PyObject* self, PyObject* args) +{ + Py_buffer output, input; + int width = 0, height = 0, bpp = 0; + + if (!PyArg_ParseTuple(args, "s*iis*i", &output, &width, &height, &input, &bpp)) + return NULL; + + if(bitmap_decompress((uint8*)output.buf, width, height, (uint8*)input.buf, input.len, bpp) == False) + return NULL; + + Py_RETURN_NONE; +} + +static PyMethodDef rle_methods[] = +{ + {"bitmap_decompress", bitmap_decompress_wrapper, METH_VARARGS, "decompress bitmap from microsoft rle algorithm."}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC +initrle(void) +{ + (void) Py_InitModule("rle", rle_methods); +} + diff --git a/rdpy/core/__init__.py b/rdpy/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/rdpy/core/sconstruct b/rdpy/core/sconstruct deleted file mode 100644 index 7ba75cb..0000000 --- a/rdpy/core/sconstruct +++ /dev/null @@ -1,36 +0,0 @@ -import os -import sipconfig - -script_dir = Dir('.').abspath -tmp_dir = os.path.join(script_dir, "tmp") -src_dir = os.path.join(script_dir, "src") -sip_dir = os.path.join(script_dir, "sip") - -def build_sip(target, source, env): - # Get the SIP configuration information. - config = sipconfig.Configuration() - - # Run SIP to generate the code. - os.system(" ".join([config.sip_bin, "-c", os.path.dirname(str(target[0])), str(source[0])])) - -def build_module(name, install_dir, env): - targetName = os.path.join(tmp_dir, name, "%s.so"%name) - - sources = [Glob(os.path.join(src_dir, name,'*.c')), os.path.join(tmp_dir, name, "sip%scmodule.c"%name)] - - env.Sip(os.path.join(tmp_dir, name, "sip%scmodule.c"%name), os.path.join(sip_dir, "%s.sip"%name)) - - #sources.append(sip) - lib = env.SharedLibrary(target = targetName, source = sources, SHLIBPREFIX='') - - env.Install(install_dir, lib) - env.Alias("install", install_dir) - - -#building library -env = Environment() -env.Append(BUILDERS = {'Sip' : Builder(action = build_sip)}) -env.Append(CPPPATH = ["/usr/include/python2.7"]); -env.VariantDir('tmp', 'src', duplicate=0) -build_module("rle", script_dir, env) - diff --git a/rdpy/core/sip/rle.sip b/rdpy/core/sip/rle.sip deleted file mode 100644 index e1bef84..0000000 --- a/rdpy/core/sip/rle.sip +++ /dev/null @@ -1,8 +0,0 @@ -%Module(name=rle, language="C") - -%UnitCode -#include "../../src/rle/rle.h" -%End - -int bitmap_decompress(void * output, int width, int height, char * input, int size, int Bpp); - diff --git a/rdpy/core/src/rle/rle.h b/rdpy/core/src/rle/rle.h deleted file mode 100644 index fea712e..0000000 --- a/rdpy/core/src/rle/rle.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _RLE_H_ -#define _RLE_H_ - -int bitmap_decompress(char * output, int width, int height, char * input, int size, int Bpp); - -#endif diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py index 31c0e02..041e9e2 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt4.py @@ -30,11 +30,7 @@ from rdpy.base.error import CallPureVirtualFuntion import sys import rdpy.base.log as log - -try: - import rdpy.core.rle as rle -except: - log.error("Please build core package before using RLE algorithm : scons -C rdpy/core install") +import rle class QAdaptor(object): """ @@ -186,31 +182,37 @@ def RDPBitmapToQtImage(destLeft, width, height, bitsPerPixel, isCompress, data): @param data: bitmap data """ image = None + #allocate + if bitsPerPixel == 15: if isCompress: - image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB555) - rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2) + buf = bytearray(width * height * 2) + rle.bitmap_decompress(buf, width, height, data, 2) + image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB555) else: image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 16: if isCompress: - image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16) - rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2) + buf = bytearray(width * height * 2) + rle.bitmap_decompress(buf, width, height, data, 2) + image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB16) else: image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 24: if isCompress: - image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB24) - rle.bitmap_decompress(image.bits(), width, height, data, len(data), 3) + buf = bytearray(width * height * 3) + rle.bitmap_decompress(buf, width, height, data, 3) + image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB24) else: image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB24).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) elif bitsPerPixel == 32: if isCompress: - image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32) - rle.bitmap_decompress(image.bits(), width, height, data, len(data), 4) + buf = bytearray(width * height * 4) + rle.bitmap_decompress(buf, width, height, data, 4) + image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB24) else: image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) else: diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e22ad3f --- /dev/null +++ b/setup.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +from distutils.core import setup, Extension + +setup(name='rdpy', + version='1.0', + description='Remote Desktop Protocol in Python', + author='Sylvain Peyrefitte', + author_email='citronneur@gmail.com', + url='https://github.com/citronneur/rdpy', + packages=[ + 'rdpy', + 'rdpy.base', + 'rdpy.network', + 'rdpy.protocol', + 'rdpy.protocol.rdp', + 'rdpy.protocol.rdp.pdu', + 'rdpy.protocol.rfb', + 'rdpy.ui' + ], + ext_modules=[Extension('rle', ['ext/rle.c'])], + scripts = [ + 'bin/rdpy-rdpclient', + 'bin/rdpy-rdpproxy', + 'bin/rdpy-rdpscreenshot', + 'bin/rdpy-vncclient', + 'bin/rdpy-vncscreenshot' + ], + install_requires=[ + 'twisted', + 'pyopenssl', + 'qt4reactor', + ], +)