mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04: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