mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05:00 
			
		
		
		
	Fix 4311
This commit is contained in:
		
							parent
							
								
									57d0a310b2
								
							
						
					
					
						commit
						0b3cf0b19f
					
				@ -24,6 +24,7 @@ isosx     = 'darwin' in sys.platform.lower()
 | 
			
		||||
isnewosx = isosx and getattr(sys, 'new_app_bundle', False)
 | 
			
		||||
islinux   = not(iswindows or isosx)
 | 
			
		||||
isfrozen  = hasattr(sys, 'frozen')
 | 
			
		||||
isunix = isosx or islinux
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    preferred_encoding = locale.getpreferredencoding()
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ Device driver for Bookeen's Cybook Gen 3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from calibre import islinux
 | 
			
		||||
from calibre.constants import isunix
 | 
			
		||||
from calibre.devices.usbms.driver import USBMS
 | 
			
		||||
import calibre.devices.cybookg3.t2b as t2b
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ class CYBOOKG3(USBMS):
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def can_handle(cls, device_info, debug=False):
 | 
			
		||||
        if islinux:
 | 
			
		||||
        if isunix:
 | 
			
		||||
            return device_info[3] == 'Bookeen' and device_info[4] == 'Cybook Gen3'
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
@ -87,6 +87,6 @@ class CYBOOK_OPUS(CYBOOKG3):
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def can_handle(cls, device_info, debug=False):
 | 
			
		||||
        if islinux:
 | 
			
		||||
        if isunix:
 | 
			
		||||
            return device_info[3] == 'Bookeen'
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
@ -104,12 +104,12 @@ class DevicePlugin(Plugin):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def is_usb_connected(cls, devices_on_system, debug=False):
 | 
			
		||||
        '''
 | 
			
		||||
        Return True if a device handled by this plugin is currently connected.
 | 
			
		||||
        Return True, device_info if a device handled by this plugin is currently connected.
 | 
			
		||||
 | 
			
		||||
        :param devices_on_system: List of devices currently connected
 | 
			
		||||
        '''
 | 
			
		||||
        if iswindows:
 | 
			
		||||
            return cls.is_usb_connected_windows(devices_on_system, debug=debug)
 | 
			
		||||
            return cls.is_usb_connected_windows(devices_on_system, debug=debug), None
 | 
			
		||||
 | 
			
		||||
        vendors_on_system = set([x[0] for x in devices_on_system])
 | 
			
		||||
        vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
 | 
			
		||||
@ -134,18 +134,20 @@ class DevicePlugin(Plugin):
 | 
			
		||||
                                if debug:
 | 
			
		||||
                                    cls.print_usb_device_info(dev)
 | 
			
		||||
                                if cls.can_handle(dev, debug=debug):
 | 
			
		||||
                                    return True
 | 
			
		||||
        return False
 | 
			
		||||
                                    return True, dev
 | 
			
		||||
        return False, None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None) :
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None,
 | 
			
		||||
            detected_device=None) :
 | 
			
		||||
        """
 | 
			
		||||
        @param key: The key to unlock the device
 | 
			
		||||
        @param log_packets: If true the packet stream to/from the device is logged
 | 
			
		||||
        @param report_progress: Function that is called with a % progress
 | 
			
		||||
        :key: The key to unlock the device
 | 
			
		||||
        :log_packets: If true the packet stream to/from the device is logged
 | 
			
		||||
        :report_progress: Function that is called with a % progress
 | 
			
		||||
                                (number between 0 and 100) for various tasks
 | 
			
		||||
                                If it is called with -1 that means that the
 | 
			
		||||
                                task does not have any progress information
 | 
			
		||||
        :detected_device: Device information from the device scanner
 | 
			
		||||
        """
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -206,9 +206,10 @@ def main():
 | 
			
		||||
    scanner.scan()
 | 
			
		||||
    connected_devices = []
 | 
			
		||||
    for d in device_plugins():
 | 
			
		||||
        if scanner.is_device_connected(d):
 | 
			
		||||
        ok, det = scanner.is_device_connected(d)
 | 
			
		||||
        if ok:
 | 
			
		||||
            dev = d
 | 
			
		||||
            dev.reset(log_packets=options.log_packets)
 | 
			
		||||
            dev.reset(log_packets=options.log_packets, detected_device=det)
 | 
			
		||||
            connected_devices.append(dev)
 | 
			
		||||
 | 
			
		||||
    if dev is None:
 | 
			
		||||
 | 
			
		||||
@ -194,7 +194,8 @@ class PRS500(DeviceConfig, DevicePlugin):
 | 
			
		||||
 | 
			
		||||
        return run_session
 | 
			
		||||
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None) :
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None,
 | 
			
		||||
            detected_device=None) :
 | 
			
		||||
        """
 | 
			
		||||
        @param key: The key to unlock the device
 | 
			
		||||
        @param log_packets: If true the packet stream to/from the device is logged
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,32 @@ from itertools import repeat
 | 
			
		||||
from calibre.devices.interface import DevicePlugin
 | 
			
		||||
from calibre.devices.errors import DeviceError, FreeSpaceError
 | 
			
		||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
 | 
			
		||||
from calibre import iswindows, islinux, isosx, __appname__
 | 
			
		||||
from calibre.constants import iswindows, islinux, isosx, __appname__, plugins
 | 
			
		||||
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
 | 
			
		||||
 | 
			
		||||
if isosx:
 | 
			
		||||
    usbobserver, usbobserver_err = plugins['usbobserver']
 | 
			
		||||
 | 
			
		||||
class USBDevice:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, dev):
 | 
			
		||||
        self.idVendor = dev[0]
 | 
			
		||||
        self.idProduct = dev[1]
 | 
			
		||||
        self.bcdDevice = dev[2]
 | 
			
		||||
        self.manufacturer = dev[3]
 | 
			
		||||
        self.product = dev[4]
 | 
			
		||||
        self.serial = dev[5]
 | 
			
		||||
 | 
			
		||||
    def match_serial(self, serial):
 | 
			
		||||
        return self.serial and self.serial == serial
 | 
			
		||||
 | 
			
		||||
    def match_numbers(self, vid, pid, bcd):
 | 
			
		||||
        return self.idVendor == vid and self.idProduct == pid and self.bcdDevice == bcd
 | 
			
		||||
 | 
			
		||||
    def match_strings(self, vid, pid, bcd, man, prod):
 | 
			
		||||
        return self.match_numbers(vid, pid, bcd) and \
 | 
			
		||||
                self.manufacturer == man and self.product == prod
 | 
			
		||||
 | 
			
		||||
class Device(DeviceConfig, DevicePlugin):
 | 
			
		||||
 | 
			
		||||
    '''
 | 
			
		||||
@ -108,8 +131,10 @@ class Device(DeviceConfig, DevicePlugin):
 | 
			
		||||
    FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
 | 
			
		||||
    FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
 | 
			
		||||
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None) :
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None,
 | 
			
		||||
            detected_device=None):
 | 
			
		||||
        self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
 | 
			
		||||
        self.detected_device = USBDevice(detected_device)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_gui_name(cls):
 | 
			
		||||
@ -391,29 +416,80 @@ class Device(DeviceConfig, DevicePlugin):
 | 
			
		||||
                    raise
 | 
			
		||||
            time.sleep(2)
 | 
			
		||||
 | 
			
		||||
    def open_osx(self):
 | 
			
		||||
        mount = self.osx_run_mount()
 | 
			
		||||
        names = self.get_osx_mountpoints()
 | 
			
		||||
        dev_pat = r'/dev/%s(\w*)\s+on\s+([^\(]+)\s+'
 | 
			
		||||
        if 'main' not in names.keys():
 | 
			
		||||
            raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
 | 
			
		||||
        main_pat = dev_pat % names['main']
 | 
			
		||||
        main_match = re.search(main_pat, mount)
 | 
			
		||||
        if main_match is None:
 | 
			
		||||
            raise DeviceError(_('Unable to detect the %s mount point. Try rebooting.')%self.__class__.__name__)
 | 
			
		||||
        self._main_prefix = main_match.group(2) + os.sep
 | 
			
		||||
        card_a_pat = names['carda'] if 'carda' in names.keys() else None
 | 
			
		||||
        card_b_pat = names['cardb'] if 'cardb' in names.keys() else None
 | 
			
		||||
 | 
			
		||||
        def get_card_prefix(pat):
 | 
			
		||||
            if pat is not None:
 | 
			
		||||
                pat = dev_pat % pat
 | 
			
		||||
                return re.search(pat, mount).group(2) + os.sep
 | 
			
		||||
    def _osx_bsd_names(self):
 | 
			
		||||
        if usbobserver_err:
 | 
			
		||||
            raise RuntimeError('Failed to load usbobserver: '+usbobserver_err)
 | 
			
		||||
        drives = usbobserver.get_usb_drives()
 | 
			
		||||
        matches = []
 | 
			
		||||
        d = self.detected_device
 | 
			
		||||
        if d.serial:
 | 
			
		||||
            for path, vid, pid, bcd, ven, prod, serial in drives:
 | 
			
		||||
                if d.match_serial(serial):
 | 
			
		||||
                    matches.append(path)
 | 
			
		||||
        if not matches:
 | 
			
		||||
            if d.manufacturer and d.product:
 | 
			
		||||
                for path, vid, pid, bcd, man, prod, serial in drives:
 | 
			
		||||
                    if d.match_strings(vid, pid, bcd, man, prod):
 | 
			
		||||
                        matches.append(path)
 | 
			
		||||
            else:
 | 
			
		||||
                return None
 | 
			
		||||
                for path, vid, pid, bcd, man, prod, serial in drives:
 | 
			
		||||
                    if d.match_numbers(vid, pid, bcd):
 | 
			
		||||
                        matches.append(path)
 | 
			
		||||
        if not matches:
 | 
			
		||||
            raise DeviceError(
 | 
			
		||||
             'Could not detect BSD names for %s. Try rebooting.' % self.name)
 | 
			
		||||
 | 
			
		||||
        self._card_a_prefix = get_card_prefix(card_a_pat)
 | 
			
		||||
        self._card_b_prefix = get_card_prefix(card_b_pat)
 | 
			
		||||
        pat = re.compile(r'(?P<m>\d+)([a-z]+(?P<p>\d+)){0,1}')
 | 
			
		||||
        def nums(x):
 | 
			
		||||
            m = pat.search(x)
 | 
			
		||||
            if m is None:
 | 
			
		||||
                return (10000, 0)
 | 
			
		||||
            g = m.groupdict()
 | 
			
		||||
            if g['p'] is None:
 | 
			
		||||
                g['p'] = 0
 | 
			
		||||
            return map(int, (g.get('m'), g.get('p')))
 | 
			
		||||
 | 
			
		||||
        def dcmp(x, y):
 | 
			
		||||
            x = x.rpartition('/')[-1]
 | 
			
		||||
            y = y.rpartition('/')[-1]
 | 
			
		||||
            x, y = nums(x), nums(y)
 | 
			
		||||
            ans = cmp(x[0], y[0])
 | 
			
		||||
            if ans == 0:
 | 
			
		||||
                ans = cmp(x[1], y[1])
 | 
			
		||||
            return ans
 | 
			
		||||
 | 
			
		||||
        matches.sort(cmp=dcmp)
 | 
			
		||||
        drives = {'main':matches[0]}
 | 
			
		||||
        if len(matches > 1):
 | 
			
		||||
            drives['carda'] = matches[1]
 | 
			
		||||
        if len(matches > 2):
 | 
			
		||||
            drives['cardb'] = matches[2]
 | 
			
		||||
 | 
			
		||||
        return drives
 | 
			
		||||
 | 
			
		||||
    def osx_bsd_names(self):
 | 
			
		||||
        try:
 | 
			
		||||
            return self._osx_bsd_names()
 | 
			
		||||
        except:
 | 
			
		||||
            time.sleep(2)
 | 
			
		||||
        return self._osx_bsd_names()
 | 
			
		||||
 | 
			
		||||
    def open_osx(self):
 | 
			
		||||
        drives = self.osx_bsd_names()
 | 
			
		||||
        drives = self.osx_sort_names(drives)
 | 
			
		||||
        mount_map = usbobserver.get_mounted_filesystems()
 | 
			
		||||
        for k, v in drives.items():
 | 
			
		||||
            drives[k] = mount_map.get(k, None)
 | 
			
		||||
        if drives['main'] is None:
 | 
			
		||||
            raise DeviceError(_('Unable to detect the %s mount point. Try rebooting.')%self.__class__.__name__)
 | 
			
		||||
        self._main_prefix = drives['main']+os.sep
 | 
			
		||||
        def get_card_prefix(c):
 | 
			
		||||
            ans = drives.get(c, None)
 | 
			
		||||
            if ans is not None:
 | 
			
		||||
                ans += os.sep
 | 
			
		||||
            return ans
 | 
			
		||||
        self._card_a_prefix = get_card_prefix('carda')
 | 
			
		||||
        self._card_b_prefix = get_card_prefix('cardb')
 | 
			
		||||
 | 
			
		||||
    def find_device_nodes(self):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,10 +33,6 @@ class USBMS(CLI, Device):
 | 
			
		||||
    FORMATS = []
 | 
			
		||||
    CAN_SET_METADATA = False
 | 
			
		||||
 | 
			
		||||
    def reset(self, key='-1', log_packets=False, report_progress=None):
 | 
			
		||||
        Device.reset(self, key=key, log_packets=log_packets,
 | 
			
		||||
                        report_progress=report_progress)
 | 
			
		||||
 | 
			
		||||
    def get_device_information(self, end_session=True):
 | 
			
		||||
        self.report_progress(1.0, _('Get device information...'))
 | 
			
		||||
        return (self.__class__.__name__, '', '', '')
 | 
			
		||||
 | 
			
		||||
@ -268,7 +268,7 @@ usbobserver_get_mounted_filesystems(PyObject *self, PyObject *args) {
 | 
			
		||||
    buf = (struct statfs*)calloc(num, sizeof(struct statfs));
 | 
			
		||||
    if (buf == NULL) return PyErr_NoMemory();
 | 
			
		||||
 | 
			
		||||
    num = getfsstat(buf, num*sizeof(struct statfs), MNT_WAIT);
 | 
			
		||||
    num = getfsstat(buf, num*sizeof(struct statfs), MNT_NOWAIT);
 | 
			
		||||
    if (num == -1) {
 | 
			
		||||
        PyErr_SetString(PyExc_RuntimeError, "Call to getfsstat failed");
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
@ -94,8 +94,8 @@ class DeviceManager(Thread):
 | 
			
		||||
            import pythoncom
 | 
			
		||||
            pythoncom.CoInitialize()
 | 
			
		||||
        try:
 | 
			
		||||
            for dev in connected_devices:
 | 
			
		||||
                dev.reset()
 | 
			
		||||
            for dev, detected_device in connected_devices:
 | 
			
		||||
                dev.reset(detected_device=detected_device)
 | 
			
		||||
                try:
 | 
			
		||||
                    dev.open()
 | 
			
		||||
                except:
 | 
			
		||||
@ -116,10 +116,10 @@ class DeviceManager(Thread):
 | 
			
		||||
        self.scanner.scan()
 | 
			
		||||
        connected_devices = []
 | 
			
		||||
        for device in self.devices:
 | 
			
		||||
            connected = self.scanner.is_device_connected(device[0])
 | 
			
		||||
            connected, detected_device = self.scanner.is_device_connected(device[0])
 | 
			
		||||
            if connected and not device[1] and not device[2]:
 | 
			
		||||
                # If connected and not showing in GUI and not ejected
 | 
			
		||||
                connected_devices.append(device[0])
 | 
			
		||||
                connected_devices.append((device[0], detected_device))
 | 
			
		||||
                device[1] = True
 | 
			
		||||
            elif not connected and device[1]:
 | 
			
		||||
                # Disconnected but showing in GUI
 | 
			
		||||
 | 
			
		||||
@ -190,6 +190,10 @@ class RecursiveFetcher(object):
 | 
			
		||||
            time.sleep(delta)
 | 
			
		||||
        if isinstance(url, unicode):
 | 
			
		||||
            url = url.encode('utf-8')
 | 
			
		||||
        # Not sure is this is really needed as I think mechanize
 | 
			
		||||
        # handles quoting automatically, but leaving it in
 | 
			
		||||
        # in case it breaks something
 | 
			
		||||
        if re.search(r'\s+|,', url) is not None:
 | 
			
		||||
            purl = list(urlparse.urlparse(url))
 | 
			
		||||
            for i in range(2, 6):
 | 
			
		||||
                purl[i] = quote(purl[i])
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user