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)
|
isnewosx = isosx and getattr(sys, 'new_app_bundle', False)
|
||||||
islinux = not(iswindows or isosx)
|
islinux = not(iswindows or isosx)
|
||||||
isfrozen = hasattr(sys, 'frozen')
|
isfrozen = hasattr(sys, 'frozen')
|
||||||
|
isunix = isosx or islinux
|
||||||
|
|
||||||
try:
|
try:
|
||||||
preferred_encoding = locale.getpreferredencoding()
|
preferred_encoding = locale.getpreferredencoding()
|
||||||
|
@ -10,7 +10,7 @@ Device driver for Bookeen's Cybook Gen 3
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from calibre import islinux
|
from calibre.constants import isunix
|
||||||
from calibre.devices.usbms.driver import USBMS
|
from calibre.devices.usbms.driver import USBMS
|
||||||
import calibre.devices.cybookg3.t2b as t2b
|
import calibre.devices.cybookg3.t2b as t2b
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ class CYBOOKG3(USBMS):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_handle(cls, device_info, debug=False):
|
def can_handle(cls, device_info, debug=False):
|
||||||
if islinux:
|
if isunix:
|
||||||
return device_info[3] == 'Bookeen' and device_info[4] == 'Cybook Gen3'
|
return device_info[3] == 'Bookeen' and device_info[4] == 'Cybook Gen3'
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -87,6 +87,6 @@ class CYBOOK_OPUS(CYBOOKG3):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_handle(cls, device_info, debug=False):
|
def can_handle(cls, device_info, debug=False):
|
||||||
if islinux:
|
if isunix:
|
||||||
return device_info[3] == 'Bookeen'
|
return device_info[3] == 'Bookeen'
|
||||||
return True
|
return True
|
||||||
|
@ -104,12 +104,12 @@ class DevicePlugin(Plugin):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def is_usb_connected(cls, devices_on_system, debug=False):
|
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
|
:param devices_on_system: List of devices currently connected
|
||||||
'''
|
'''
|
||||||
if iswindows:
|
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_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]
|
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
|
||||||
@ -134,18 +134,20 @@ class DevicePlugin(Plugin):
|
|||||||
if debug:
|
if debug:
|
||||||
cls.print_usb_device_info(dev)
|
cls.print_usb_device_info(dev)
|
||||||
if cls.can_handle(dev, debug=debug):
|
if cls.can_handle(dev, debug=debug):
|
||||||
return True
|
return True, dev
|
||||||
return False
|
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
|
:key: The key to unlock the device
|
||||||
@param log_packets: If true the packet stream to/from the device is logged
|
:log_packets: If true the packet stream to/from the device is logged
|
||||||
@param report_progress: Function that is called with a % progress
|
:report_progress: Function that is called with a % progress
|
||||||
(number between 0 and 100) for various tasks
|
(number between 0 and 100) for various tasks
|
||||||
If it is called with -1 that means that the
|
If it is called with -1 that means that the
|
||||||
task does not have any progress information
|
task does not have any progress information
|
||||||
|
:detected_device: Device information from the device scanner
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -206,9 +206,10 @@ def main():
|
|||||||
scanner.scan()
|
scanner.scan()
|
||||||
connected_devices = []
|
connected_devices = []
|
||||||
for d in device_plugins():
|
for d in device_plugins():
|
||||||
if scanner.is_device_connected(d):
|
ok, det = scanner.is_device_connected(d)
|
||||||
|
if ok:
|
||||||
dev = d
|
dev = d
|
||||||
dev.reset(log_packets=options.log_packets)
|
dev.reset(log_packets=options.log_packets, detected_device=det)
|
||||||
connected_devices.append(dev)
|
connected_devices.append(dev)
|
||||||
|
|
||||||
if dev is None:
|
if dev is None:
|
||||||
|
@ -194,7 +194,8 @@ class PRS500(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
return run_session
|
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 key: The key to unlock the device
|
||||||
@param log_packets: If true the packet stream to/from the device is logged
|
@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.interface import DevicePlugin
|
||||||
from calibre.devices.errors import DeviceError, FreeSpaceError
|
from calibre.devices.errors import DeviceError, FreeSpaceError
|
||||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
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
|
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):
|
class Device(DeviceConfig, DevicePlugin):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -108,8 +131,10 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
|
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">'
|
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._main_prefix = self._card_a_prefix = self._card_b_prefix = None
|
||||||
|
self.detected_device = USBDevice(detected_device)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_gui_name(cls):
|
def get_gui_name(cls):
|
||||||
@ -391,29 +416,80 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
raise
|
raise
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
def open_osx(self):
|
def _osx_bsd_names(self):
|
||||||
mount = self.osx_run_mount()
|
if usbobserver_err:
|
||||||
names = self.get_osx_mountpoints()
|
raise RuntimeError('Failed to load usbobserver: '+usbobserver_err)
|
||||||
dev_pat = r'/dev/%s(\w*)\s+on\s+([^\(]+)\s+'
|
drives = usbobserver.get_usb_drives()
|
||||||
if 'main' not in names.keys():
|
matches = []
|
||||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
|
d = self.detected_device
|
||||||
main_pat = dev_pat % names['main']
|
if d.serial:
|
||||||
main_match = re.search(main_pat, mount)
|
for path, vid, pid, bcd, ven, prod, serial in drives:
|
||||||
if main_match is None:
|
if d.match_serial(serial):
|
||||||
raise DeviceError(_('Unable to detect the %s mount point. Try rebooting.')%self.__class__.__name__)
|
matches.append(path)
|
||||||
self._main_prefix = main_match.group(2) + os.sep
|
if not matches:
|
||||||
card_a_pat = names['carda'] if 'carda' in names.keys() else None
|
if d.manufacturer and d.product:
|
||||||
card_b_pat = names['cardb'] if 'cardb' in names.keys() else None
|
for path, vid, pid, bcd, man, prod, serial in drives:
|
||||||
|
if d.match_strings(vid, pid, bcd, man, prod):
|
||||||
def get_card_prefix(pat):
|
matches.append(path)
|
||||||
if pat is not None:
|
|
||||||
pat = dev_pat % pat
|
|
||||||
return re.search(pat, mount).group(2) + os.sep
|
|
||||||
else:
|
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)
|
pat = re.compile(r'(?P<m>\d+)([a-z]+(?P<p>\d+)){0,1}')
|
||||||
self._card_b_prefix = get_card_prefix(card_b_pat)
|
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):
|
def find_device_nodes(self):
|
||||||
|
|
||||||
|
@ -33,10 +33,6 @@ class USBMS(CLI, Device):
|
|||||||
FORMATS = []
|
FORMATS = []
|
||||||
CAN_SET_METADATA = False
|
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):
|
def get_device_information(self, end_session=True):
|
||||||
self.report_progress(1.0, _('Get device information...'))
|
self.report_progress(1.0, _('Get device information...'))
|
||||||
return (self.__class__.__name__, '', '', '')
|
return (self.__class__.__name__, '', '', '')
|
||||||
|
@ -268,7 +268,7 @@ usbobserver_get_mounted_filesystems(PyObject *self, PyObject *args) {
|
|||||||
buf = (struct statfs*)calloc(num, sizeof(struct statfs));
|
buf = (struct statfs*)calloc(num, sizeof(struct statfs));
|
||||||
if (buf == NULL) return PyErr_NoMemory();
|
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) {
|
if (num == -1) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Call to getfsstat failed");
|
PyErr_SetString(PyExc_RuntimeError, "Call to getfsstat failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -94,8 +94,8 @@ class DeviceManager(Thread):
|
|||||||
import pythoncom
|
import pythoncom
|
||||||
pythoncom.CoInitialize()
|
pythoncom.CoInitialize()
|
||||||
try:
|
try:
|
||||||
for dev in connected_devices:
|
for dev, detected_device in connected_devices:
|
||||||
dev.reset()
|
dev.reset(detected_device=detected_device)
|
||||||
try:
|
try:
|
||||||
dev.open()
|
dev.open()
|
||||||
except:
|
except:
|
||||||
@ -116,10 +116,10 @@ class DeviceManager(Thread):
|
|||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
connected_devices = []
|
connected_devices = []
|
||||||
for device in self.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 device[1] and not device[2]:
|
||||||
# If connected and not showing in GUI and not ejected
|
# 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
|
device[1] = True
|
||||||
elif not connected and device[1]:
|
elif not connected and device[1]:
|
||||||
# Disconnected but showing in GUI
|
# Disconnected but showing in GUI
|
||||||
|
@ -190,10 +190,14 @@ class RecursiveFetcher(object):
|
|||||||
time.sleep(delta)
|
time.sleep(delta)
|
||||||
if isinstance(url, unicode):
|
if isinstance(url, unicode):
|
||||||
url = url.encode('utf-8')
|
url = url.encode('utf-8')
|
||||||
purl = list(urlparse.urlparse(url))
|
# Not sure is this is really needed as I think mechanize
|
||||||
for i in range(2, 6):
|
# handles quoting automatically, but leaving it in
|
||||||
purl[i] = quote(purl[i])
|
# in case it breaks something
|
||||||
url = urlparse.urlunparse(purl)
|
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])
|
||||||
|
url = urlparse.urlunparse(purl)
|
||||||
try:
|
try:
|
||||||
open_func = getattr(self.browser, 'open_novisit', self.browser.open)
|
open_func = getattr(self.browser, 'open_novisit', self.browser.open)
|
||||||
with closing(open_func(url, timeout=self.timeout)) as f:
|
with closing(open_func(url, timeout=self.timeout)) as f:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user