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)
islinux = not(iswindows or isosx)
isfrozen = hasattr(sys, 'frozen')
isunix = isosx or islinux
try:
preferred_encoding = locale.getpreferredencoding()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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