This commit is contained in:
Kovid Goyal 2009-12-27 11:57:54 -07:00
parent 57d0a310b2
commit 0b3cf0b19f
10 changed files with 131 additions and 50 deletions

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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__, '', '', '')

View File

@ -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;

View File

@ -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

View File

@ -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: