diff --git a/osx_installer.py b/osx_installer.py index 40d5fd91e6..62b6431cd3 100644 --- a/osx_installer.py +++ b/osx_installer.py @@ -103,7 +103,7 @@ _check_symlinks_prescript() else: debug = 0 return find_modules( - scripts=scripts['console'] + scripts['gui'], + scripts=scripts['console'] + scripts['gui'][1:], includes=list(self.includes) + main_modules['console'], packages=self.packages, excludes=self.excludes, diff --git a/src/libprs500/devices/errors.py b/src/libprs500/devices/errors.py index 5e61277f77..b81c8ab5e2 100644 --- a/src/libprs500/devices/errors.py +++ b/src/libprs500/devices/errors.py @@ -32,9 +32,10 @@ class TimeoutError(ProtocolError): class DeviceError(ProtocolError): """ Raised when device is not found """ - def __init__(self): - ProtocolError.__init__(self, \ - "Unable to find SONY Reader. Is it connected?") + def __init__(self, msg=None): + if msg is None: + msg = "Unable to find SONY Reader. Is it connected?" + ProtocolError.__init__(self, msg) class DeviceBusy(ProtocolError): """ Raised when device is busy """ diff --git a/src/libprs500/devices/interface.py b/src/libprs500/devices/interface.py index 923e864e47..bafac86357 100644 --- a/src/libprs500/devices/interface.py +++ b/src/libprs500/devices/interface.py @@ -46,8 +46,18 @@ class Device(object): raise NotImplementedError() @classmethod - def is_connected(cls): - '''Return True iff the device is physically connected to the computer''' + def get_fdi(cls): + '''Return the FDI description of this device for HAL on linux.''' + return '' + + @classmethod + def is_connected(cls, helper=None): + ''' + Return True iff the device is physically connected to the computer + + @param helper: Platform dependent helper object. For e.g. on windows + an instantiated WMI interface. + ''' raise NotImplementedError() def set_progress_reporter(self, report_progress): diff --git a/src/libprs500/devices/prs505/driver.py b/src/libprs500/devices/prs505/driver.py index d878244a7b..f7a2525649 100644 --- a/src/libprs500/devices/prs505/driver.py +++ b/src/libprs500/devices/prs505/driver.py @@ -18,11 +18,18 @@ import shutil from libprs500.devices.interface import Device from libprs500.devices.errors import DeviceError, FreeSpaceError from libprs500.devices.prs500.books import BookList +from libprs500 import iswindows, islinux, isosx +if not iswindows: + from libprs500.devices.libusb import get_device_by_id -from libprs500 import islinux, iswindows import sys, os +try: + import _winreg +except ImportError: + pass + class File(object): def __init__(self, path): stats = os.stat(path) @@ -40,43 +47,117 @@ class File(object): class PRS505(Device): VENDOR_ID = 0x054c #: SONY Vendor Id PRODUCT_ID = 0x031e #: Product Id for the PRS-505 - PRODUCT_NAME = 'Sony Portable Reader System' + PRODUCT_NAME = 'PRS-505' + VENDOR_NAME = 'SONY' MEDIA_XML = 'database/cache/media.xml' CACHE_XML = 'Sony Reader/database/cache.xml' - LINUX_DEVICE_NODE = 'sony_prs_505' - LINUX_DEVICE_PATH = os.path.join('/dev', LINUX_DEVICE_NODE) + MAIN_MEMORY_VOLUME_LABEL = 'Sony Reader Main Memory' + STORAGE_CARD_VOLUME_LABEL = 'Sony Reader Storage Card' + + FDI_TEMPLATE = \ +''' + + + + + + %(main_memory)s + %(deviceclass)s + + + + + + + + + + + %(storage_card)s + %(deviceclass)s + + + + + +''' + def __init__(self): self._main_prefix = self._card_prefix = None - self.hm = None - if islinux: - import dbus - self.bus = dbus.SystemBus() - self.hm = dbus.Interface(self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager") + + @classmethod + def get_fdi(cls): + return cls.FDI_TEMPLATE%dict( + deviceclass=cls.__name__, + vendor_id=hex(cls.VENDOR_ID), + product_id=hex(cls.PRODUCT_ID), + main_memory=cls.MAIN_MEMORY_VOLUME_LABEL, + storage_card=cls.STORAGE_CARD_VOLUME_LABEL, + ) - def is_connected(self): - if self.hm is not None: # linux - devs = self.hm.FindDeviceStringMatch('info.product', 'Sony Portable Reader System') - for dev in devs: - obj = self.bus.get_object("org.freedesktop.Hal", dev) - if obj.GetPropertyInteger('usb_device.product_id', dbus_interface='org.freedesktop.Hal.Device') == self.__class__.PRODUCT_ID: - return True + @classmethod + def is_device(cls, device_id): + if 'VEN_'+cls.VENDOR_NAME in device_id.upper() and \ + 'PROD_'+cls.PRODUCT_NAME in device_id.upper(): + return True + vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:] + if len(vid) < 4: vid = '0'+vid + if len(pid) < 4: pid = '0'+pid + if 'VID_'+vid in device_id.upper() and \ + 'PID_'+pid in device_id.upper(): + return True return False + @classmethod + def is_connected(cls, helper=None): + if iswindows: + for c in helper.USBControllerDevice(): + if cls.is_device(c.Dependent.DeviceID): + return True + return False + else: + return get_device_by_id(cls.VENDOR_ID, cls.PRODUCT_ID) != None + + + def open_windows(self): + import wmi + c = wmi.WMI() + for drive in c.Win32_DiskDrive(): + if self.__class__.is_device(drive.PNPDeviceID): + if drive.Partitions == 0: + continue + try: + partition = drive.associators("Win32_DiskDriveToDiskPartition")[0] + except IndexError: + continue + logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0] + prefix = logical_disk.DeviceID+os.sep + if drive.Index == 1: + self._main_prefix = prefix + else: + self._card_prefix = prefix + if self._main_prefix is None: + raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,)) + + def open_linux(self): + import dbus + bus = dbus.SystemBus() + hm = dbus.Interface(self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager") try: - mm = self.hm.FindDeviceStringMatch('volume.label', 'Sony Reader Main Memory')[0] + mm = hm.FindDeviceStringMatch('libprs500.mainvolume', self.__class__.__name__)[0] except: raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,)) try: - sc = self.hm.FindDeviceStringMatch('volume.label', 'Sony Reader Storage Card')[0] + sc = hm.FindDeviceStringMatch('libprs500.cardvolume', self.__class__.__name__)[0] except: sc = None def conditional_mount(dev): - mmo = self.bus.get_object("org.freedesktop.Hal", dev) + mmo = bus.get_object("org.freedesktop.Hal", dev) label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device') is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device') mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device') @@ -93,8 +174,10 @@ class PRS505(Device): self._card_prefix = conditional_mount(sc)+os.sep def open(self): - if self.hm is not None: # linux + if islinux: self.open_linux() + if iswindows: + self.open_windows() def set_progress_reporter(self, pr): self.report_progress = pr @@ -105,29 +188,43 @@ class PRS505(Device): def card_prefix(self, end_session=True): return self._card_prefix + @classmethod + def _windows_space(cls, prefix): + if prefix is None: + return 0, 0 + import win32file + sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \ + win32file.GetDiskFreeSpace(prefix[:-1]) + mult = sectors_per_cluster * bytes_per_sector + return total_clusters * mult, free_clusters * mult + def total_space(self, end_session=True): + msz = csz = 0 if not iswindows: - msz = 0 if self._main_prefix is not None: stats = os.statvfs(self._main_prefix) msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree) - csz = 0 if self._card_prefix is not None: stats = os.statvfs(self._card_prefix) csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree) + else: + msz = self._windows_space(self._main_prefix)[0] + csz = self._windows_space(self._card_prefix)[0] return (msz, 0, csz) def free_space(self, end_session=True): + msz = csz = 0 if not iswindows: - msz = 0 if self._main_prefix is not None: stats = os.statvfs(self._main_prefix) msz = stats.f_bsize * stats.f_bavail - csz = 0 if self._card_prefix is not None: stats = os.statvfs(self._card_prefix) csz = stats.f_bsize * stats.f_bavail + else: + msz = self._windows_space(self._main_prefix)[1] + csz = self._windows_space(self._card_prefix)[1] return (msz, 0, csz) diff --git a/src/libprs500/gui2/device.py b/src/libprs500/gui2/device.py index 443623b3c2..bf5a19f975 100644 --- a/src/libprs500/gui2/device.py +++ b/src/libprs500/gui2/device.py @@ -12,6 +12,7 @@ ## 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., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning +from libprs500 import iswindows import sys, os from PyQt4.QtCore import QThread, SIGNAL, QObject @@ -42,10 +43,15 @@ class DeviceDetector(QThread): QThread.__init__(self) def run(self): + helper = None + if iswindows: + import wmi, pythoncom + pythoncom.CoInitialize() + helper = wmi.WMI() while True: for device in self.devices: try: - connected = device[0].is_connected() + connected = device[0].is_connected(helper=helper) except: connected = False if connected and not device[1]: diff --git a/src/libprs500/gui2/main.py b/src/libprs500/gui2/main.py index f88cc133f4..874ad663ab 100644 --- a/src/libprs500/gui2/main.py +++ b/src/libprs500/gui2/main.py @@ -709,7 +709,7 @@ class Main(MainWindow, Ui_MainWindow): -def main(args=sys.argv): +def main(args=sys.argv): from PyQt4.Qt import QApplication pid = os.fork() if islinux else -1 if pid <= 0: diff --git a/src/libprs500/linux.py b/src/libprs500/linux.py index 697eaac585..1ea128aa0d 100644 --- a/src/libprs500/linux.py +++ b/src/libprs500/linux.py @@ -14,9 +14,15 @@ ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning import shutil ''' Post installation script for linux ''' -import sys, os, stat +import sys, os + from subprocess import check_call -from libprs500 import __version__ +from libprs500 import __version__, __appname__ + +from libprs500.devices.prs500.driver import PRS500 +from libprs500.devices.prs505.driver import PRS505 + +DEVICES = (PRS500, PRS505) def options(option_parser): parser = option_parser() @@ -182,36 +188,24 @@ def setup_udev_rules(): '''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,) ) udev.close() - open('/usr/share/hal/fdi/policy/20thirdparty/10-libprs500.fdi', 'w').write( -'''\ - - - + fdi = open('/usr/share/hal/fdi/policy/20thirdparty/10-libprs500.fdi', 'w') + fdi.write('\n\n\n') + for cls in DEVICES: + fdi.write(\ +''' - - - - - Sony Reader Main Memory - - + + + %(cls)s + %(prog)s - - - - - - Sony Reader Storage Card - - - - - - - -''') +'''%dict(cls=cls.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID, + prog=__appname__)) + fdi.write('\n'+cls.get_fdi()) + fdi.write('\n\n') + fdi.close() check_call('/etc/init.d/hald restart', shell=True) try: diff --git a/windows_installer.py b/windows_installer.py index 06759f78c6..0f7216c8f7 100644 --- a/windows_installer.py +++ b/windows_installer.py @@ -446,11 +446,14 @@ setup( options = { 'py2exe' : {'compressed': 1, 'optimize' : 2, 'dist_dir' : PY2EXE_DIR, - 'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg', 'mechanize', 'ClientForm'], + 'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg', + 'mechanize', 'ClientForm', 'wmi', + 'win32file', 'pythoncom'], 'packages' : ['PIL'], 'excludes' : ["Tkconstants", "Tkinter", "tcl", "_imagingtk", "ImageTk", "FixTk", 'pydoc'], + 'dll_excludes' : ['mswsock.dll'], }, },