Sync to trunk.

This commit is contained in:
John Schember 2010-01-12 18:13:25 -05:00
commit 5ea2953092
15 changed files with 233 additions and 233 deletions

View File

@ -1,19 +1,38 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'Kovid Goyal and Sujata Raman, Lorenzo Vigentini'
__copyright__ = '2009, Kovid Goyal and Sujata Raman'
__version__ = 'v1.02'
__date__ = '10, January 2010'
__description__ = 'Providing context and clarity on national and international news, peoples and cultures'
'''csmonitor.com'''
import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class ChristianScienceMonitor(BasicNewsRecipe):
title = 'Christian Science Monitor'
description = 'Providing context and clarity on national and international news, peoples and cultures'
max_articles_per_feed = 20
__author__ = 'Kovid Goyal and Sujata Raman'
author = 'Kovid Goyal, Sujata Raman and Lorenzo Vigentini'
description = 'Providing context and clarity on national and international news, peoples and cultures'
cover_url = 'http://www.csmonitor.com/extension/csm_base/design/csm_design/images/csmlogo_179x46.gif'
title = 'Christian Science Monitor'
publisher = 'The Christian Science Monitor'
category = 'News, politics, culture, economy, general interest'
language = 'en'
encoding = 'utf-8'
no_stylesheets = True
use_embedded_content = False
timefmt = '[%a, %d %b, %Y]'
oldest_article = 16
max_articles_per_feed = 20
use_embedded_content = False
recursion = 10
remove_javascript = True
no_stylesheets = True
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
@ -55,33 +74,15 @@ class ChristianScienceMonitor(BasicNewsRecipe):
]
keep_only_tags = [
dict(name='div', attrs={'id':['story','main']}),
dict(name='div', attrs={'id':'mainColumn'}),
]
remove_tags = [
dict(name='div', attrs={'id':['story-tools','videoPlayer','storyRelatedBottom','enlarge-photo','photo-paginate']}),
dict(name='div', attrs={'class':[ 'spacer3','divvy spacer7','comment','storyIncludeBottom']}),
dict(name='div', attrs={'class':['storyToolbar cfx','podStoryRel','spacer3','divvy spacer7','comment','storyIncludeBottom']}),
dict(name='ul', attrs={'class':[ 'centerliststories']}) ,
dict(name='form', attrs={'id':[ 'commentform']}) ,
]
remove_tags_after = [ dict(name='div', attrs={'class':[ 'ad csmAd']})]
def find_articles(self, section):
ans = []
for x in section.findAll('head4'):
title = ' '.join(x.findAll(text=True)).strip()
a = x.find('a')
if not a: continue
href = a['href']
ans.append({'title':title, 'url':href, 'description':'', 'date': strftime('%a, %d %b')})
#for x in ans:
# x['url'] += '/output/print'
return ans
def postprocess_html(self, soup, first_fetch):
html = soup.find('html')
if html is None:
return soup
html.extract()
return html

View File

@ -48,7 +48,9 @@ class NYTimes(BasicNewsRecipe):
return 'NY Times'
def parse_index(self):
self.encoding = 'cp1252'
soup = self.index_to_soup('http://www.nytimes.com/pages/todayspaper/index.html')
self.encoding = None
def feed_title(div):
return ''.join(div.findAll(text=True, recursive=False)).strip()

View File

@ -9,6 +9,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
class Slashdot(BasicNewsRecipe):
title = u'Slashdot.org'
description = '''Tech news. WARNING: This recipe downloads a lot
of content and can result in your IP being banned from slashdot.org'''
oldest_article = 7
max_articles_per_feed = 100
language = 'en'

View File

@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
Device drivers.
'''
import sys, os, time, pprint
import sys, time, pprint
from functools import partial
from StringIO import StringIO
@ -29,7 +29,7 @@ def strftime(epoch, zone=time.gmtime):
def debug(ioreg_to_tmp=False, buf=None):
from calibre.customize.ui import device_plugins
from calibre.devices.scanner import DeviceScanner
from calibre.devices.scanner import DeviceScanner, win_pnp_drives
from calibre.constants import iswindows, isosx, __version__
from calibre import prints
oldo, olde = sys.stdout, sys.stderr
@ -37,19 +37,11 @@ def debug(ioreg_to_tmp=False, buf=None):
if buf is None:
buf = StringIO()
sys.stdout = sys.stderr = buf
if iswindows:
import pythoncom
pythoncom.CoInitialize()
try:
out = partial(prints, file=buf)
out('Version:', __version__)
wmi = Wmi =None
if iswindows:
wmi = __import__('wmi', globals(), locals(), [], -1)
Wmi = wmi.WMI(find_classes=False)
s = DeviceScanner()
s.wmi = Wmi
s.scan()
devices = (s.devices)
if not iswindows:
@ -60,21 +52,9 @@ def debug(ioreg_to_tmp=False, buf=None):
out('USB devices on system:')
out(pprint.pformat(devices))
if iswindows:
drives = []
drives = win_pnp_drives(debug=True)
out('Drives detected:')
out('\t', '(ID, Partitions, Drive letter)')
for drive in Wmi.Win32_DiskDrive():
if drive.Partitions == 0:
continue
try:
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID+os.sep
drives.append((str(drive.PNPDeviceID), drive.Index, prefix))
except IndexError:
drives.append((str(drive.PNPDeviceID), 'No mount points found'))
for drive in drives:
out('\t', drive)
out(pprint.pformat(drives))
ioreg = None
if isosx:
@ -84,13 +64,10 @@ def debug(ioreg_to_tmp=False, buf=None):
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
connected_devices = []
for dev in device_plugins():
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
out('Looking for', dev.__class__.__name__)
connected, det = s.is_device_connected(dev, debug=True)
if connected:
connected_devices.append((dev, det))
dev.wmi = owmi
errors = {}
success = False
@ -102,8 +79,6 @@ def debug(ioreg_to_tmp=False, buf=None):
out(' ')
for dev, det in connected_devices:
out('Trying to open', dev.name, '...', end=' ')
owmi = getattr(dev, 'wmi', None)
dev.wmi = Wmi
try:
dev.reset(detected_device=det)
dev.open()
@ -113,8 +88,6 @@ def debug(ioreg_to_tmp=False, buf=None):
errors[dev] = traceback.format_exc()
out('failed')
continue
finally:
dev.wmi = owmi
success = True
if hasattr(dev, '_main_prefix'):
out('Main memory:', repr(dev._main_prefix))
@ -142,7 +115,4 @@ def debug(ioreg_to_tmp=False, buf=None):
finally:
sys.stdout = oldo
sys.stderr = olde
if iswindows:
import pythoncom
pythoncom.CoUninitialize()

View File

@ -60,7 +60,7 @@ class DevicePlugin(Plugin):
import traceback
traceback.print_exc()
def is_usb_connected_windows(self, devices_on_system, pnp_id_iterator, debug=False):
def is_usb_connected_windows(self, devices_on_system, debug=False):
def id_iterator():
if hasattr(self.VENDOR_ID, 'keys'):
@ -85,7 +85,7 @@ class DevicePlugin(Plugin):
self.test_bcd_windows(device_id, bcd):
if debug:
self.print_usb_device_info(device_id)
if self.can_handle_windows(device_id, pnp_id_iterator, debug=debug):
if self.can_handle_windows(device_id, debug=debug):
return True
return False
@ -97,7 +97,7 @@ class DevicePlugin(Plugin):
return True
return False
def is_usb_connected(self, devices_on_system, pnp_id_iterator, debug=False):
def is_usb_connected(self, devices_on_system, debug=False):
'''
Return True, device_info if a device handled by this plugin is currently connected.
@ -105,7 +105,7 @@ class DevicePlugin(Plugin):
'''
if iswindows:
return self.is_usb_connected_windows(devices_on_system,
pnp_id_iterator, debug=debug), None
debug=debug), None
vendors_on_system = set([x[0] for x in devices_on_system])
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
@ -147,7 +147,7 @@ class DevicePlugin(Plugin):
"""
raise NotImplementedError()
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
def can_handle_windows(self, device_id, debug=False):
'''
Optional method to perform further checks on a device to see if this driver
is capable of handling it. If it is not it should return False. This method

View File

@ -9,7 +9,7 @@ For usage information run the script.
import StringIO, sys, time, os
from optparse import OptionParser
from calibre import __version__, iswindows, __appname__
from calibre import __version__, __appname__
from calibre.devices.errors import PathError
from calibre.utils.terminfo import TerminalController
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
@ -198,14 +198,9 @@ def main():
args = args[1:]
dev = None
scanner = DeviceScanner()
if iswindows:
import wmi, pythoncom
pythoncom.CoInitialize()
scanner.wmi = wmi.WMI(find_classes=False)
scanner.scan()
connected_devices = []
for d in device_plugins():
d.wmi = scanner.wmi
ok, det = scanner.is_device_connected(d)
if ok:
dev = d

View File

@ -6,6 +6,7 @@ manner.
'''
import sys, os
from threading import RLock
from calibre import iswindows, isosx, plugins, islinux
@ -22,6 +23,54 @@ elif isosx:
except:
raise RuntimeError('Failed to load the usbobserver plugin: %s'%plugins['usbobserver'][1])
class WinPNPScanner(object):
def __init__(self):
self.scanner = None
if iswindows:
self.scanner = plugins['winutil'][0].get_removable_drives
self.lock = RLock()
def drive_is_ok(self, letter, debug=False):
import win32api, win32file
with self.lock:
oldError = win32api.SetErrorMode(1) #SEM_FAILCRITICALERRORS = 1
try:
ans = True
try:
win32file.GetDiskFreeSpaceEx(letter+':\\')
except:
ans = False
return ans
finally:
win32api.SetErrorMode(oldError)
def __call__(self, debug=False):
if self.scanner is None:
return {}
try:
drives = self.scanner(debug)
except:
drives = {}
if debug:
import traceback
traceback.print_exc()
remove = set([])
for letter in drives:
if not self.drive_is_ok(letter, debug=debug):
remove.add(letter)
for letter in remove:
drives.pop(letter)
ans = {}
for key, val in drives.items():
val = [x.upper() for x in val]
val = [x for x in val if 'USBSTOR' in x]
if val:
ans[key+':\\'] = val[-1]
return ans
win_pnp_drives = WinPNPScanner()
class LinuxScanner(object):
SYSFS_PATH = os.environ.get('SYSFS_PATH', '/sys')
@ -85,26 +134,13 @@ class DeviceScanner(object):
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = []
self.wmi = None
self.pnp_ids = set([])
self.rescan_pnp_ids = True
def scan(self):
'''Fetch list of connected USB devices from operating system'''
self.devices = self.scanner()
if self.rescan_pnp_ids:
self.pnp_ids = set([])
def pnp_id_iterator(self):
if self.wmi is not None and not self.pnp_ids:
for drive in self.wmi.Win32_DiskDrive():
if drive.Partitions > 0:
self.pnp_ids.add(str(drive.PNPDeviceID))
for x in self.pnp_ids:
yield x
def is_device_connected(self, device, debug=False):
return device.is_usb_connected(self.devices, self.pnp_id_iterator, debug=debug)
return device.is_usb_connected(self.devices, debug=debug)
def main(args=sys.argv):

View File

@ -203,18 +203,6 @@ class Device(DeviceConfig, DevicePlugin):
return False
def windows_get_drive_prefix(self, drive):
prefix = None
try:
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID + os.sep
except IndexError:
pass
return prefix
def windows_sort_drives(self, drives):
'''
Called to disambiguate main memory and storage card for devices that
@ -223,8 +211,10 @@ class Device(DeviceConfig, DevicePlugin):
'''
return drives
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
for pnp_id in pnp_id_iterator():
def can_handle_windows(self, device_id, debug=False):
from calibre.devices.scanner import win_pnp_drives
drives = win_pnp_drives()
for pnp_id in drives.values():
if self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM'):
return True
if debug:
@ -232,29 +222,20 @@ class Device(DeviceConfig, DevicePlugin):
return False
def open_windows(self):
from calibre.devices.scanner import win_pnp_drives
def matches_q(drive, attr):
q = getattr(self, attr)
if q is None: return False
if isinstance(q, basestring):
q = [q]
pnp = str(drive.PNPDeviceID)
for x in q:
if x in pnp:
return True
return False
time.sleep(8)
time.sleep(5)
drives = {}
c = self.wmi
for drive in c.Win32_DiskDrive():
pnp_id = str(drive.PNPDeviceID)
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None):
drives['carda'] = self.windows_get_drive_prefix(drive)
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None):
drives['cardb'] = self.windows_get_drive_prefix(drive)
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
drives['main'] = self.windows_get_drive_prefix(drive)
for drive, pnp_id in win_pnp_drives().items():
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and \
not drives.get('carda', False):
drives['carda'] = drive
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and \
not drives.get('cardb', False):
drives['cardb'] = drive
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and \
not drives.get('main', False):
drives['main'] = drive
if 'main' in drives.keys() and 'carda' in drives.keys() and \
'cardb' in drives.keys():

View File

@ -168,6 +168,7 @@ class Stylizer(object):
self.rules = rules
self._styles = {}
class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE)
capital_sel_pat = re.compile(r'h|[A-Z]+')
for _, _, cssdict, text, _ in rules:
try:
selector = CSSSelector(text)
@ -176,6 +177,15 @@ class Stylizer(object):
SelectorSyntaxError):
continue
matches = selector(tree)
if not matches:
ntext = capital_sel_pat.sub(lambda m: m.group().lower(), text)
if ntext != text:
self.logger.warn('Transformed CSS selector', text, 'to',
ntext)
selector = CSSSelector(ntext)
matches = selector(tree)
if not matches and class_sel_pat.match(text):
found = False
for x in tree.xpath('//*[@class]'):

View File

@ -13,7 +13,6 @@ from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, QPixmap, \
from calibre.customize.ui import available_input_formats, available_output_formats, \
device_plugins
from calibre.devices.interface import DevicePlugin
from calibre.constants import iswindows
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
from calibre.utils.ipc.job import BaseJob
from calibre.devices.scanner import DeviceScanner
@ -85,7 +84,6 @@ class DeviceManager(Thread):
self.job_manager = job_manager
self.current_job = None
self.scanner = DeviceScanner()
self.wmi = None
self.connected_device = None
self.ejected_devices = set([])
@ -133,7 +131,6 @@ class DeviceManager(Thread):
self.connected_device = None
def detect_device(self):
self.scanner.rescan_pnp_ids = not self.is_device_connected
self.scanner.scan()
if self.is_device_connected:
connected, detected_device = \
@ -170,30 +167,18 @@ class DeviceManager(Thread):
pass
def run(self):
if iswindows:
import pythoncom
pythoncom.CoInitialize()
wmi = __import__('wmi', globals(), locals(), [], -1)
self.wmi = wmi.WMI(find_classes=False)
self.scanner.wmi = self.wmi
for x in self.devices:
x.wmi = self.wmi
try:
while self.keep_going:
self.detect_device()
while True:
job = self.next()
if job is not None:
self.current_job = job
self.device.set_progress_reporter(job.report_progress)
self.current_job.run()
self.current_job = None
else:
break
time.sleep(self.sleep_time)
finally:
if iswindows:
pythoncom.CoUninitialize()
while self.keep_going:
self.detect_device()
while True:
job = self.next()
if job is not None:
self.current_job = job
self.device.set_progress_reporter(job.report_progress)
self.current_job.run()
self.current_job = None
else:
break
time.sleep(self.sleep_time)
def create_job(self, func, done, description, args=[], kwargs={}):

View File

@ -7,7 +7,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>838</width>
<width>884</width>
<height>730</height>
</rect>
</property>
@ -89,7 +89,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>562</width>
<width>608</width>
<height>683</height>
</rect>
</property>

View File

@ -171,7 +171,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
if self._add_formats(paths):
event.accept()
def remove_format(self, x=None):
def remove_format(self, *args):
rows = self.formats.selectionModel().selectedRows(0)
for row in rows:
self.formats.takeItem(row.row())

View File

@ -23,9 +23,10 @@ KEY = Qt.UserRole + 3
class Customize(QFrame, Ui_Frame):
def __init__(self, dup_check, parent=None):
def __init__(self, index, dup_check, parent=None):
QFrame.__init__(self, parent)
self.setupUi(self)
self.data_model = index.model()
self.setFocusPolicy(Qt.StrongFocus)
self.setAutoFillBackground(True)
self.custom.toggled.connect(self.custom_toggled)
@ -86,12 +87,21 @@ class Delegate(QStyledItemDelegate):
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.editing_indices = {}
self.closeEditor.connect(self.editing_done)
def to_doc(self, index):
doc = QTextDocument()
doc.setHtml(index.data().toString())
return doc
def editing_done(self, editor, hint):
remove = None
for row, w in self.editing_indices.items():
remove = (row, w.data_model.index(row))
if remove is not None:
self.editing_indices.pop(remove[0])
self.sizeHintChanged.emit(remove[1])
def sizeHint(self, option, index):
if index.row() in self.editing_indices:
return QSize(200, 200)
@ -111,7 +121,7 @@ class Delegate(QStyledItemDelegate):
painter.restore()
def createEditor(self, parent, option, index):
w = Customize(index.model().duplicate_check, parent=parent)
w = Customize(index, index.model().duplicate_check, parent=parent)
self.editing_indices[index.row()] = w
self.sizeHintChanged.emit(index)
return w
@ -135,8 +145,6 @@ class Delegate(QStyledItemDelegate):
setattr(editor, 'shortcut%d'%(x+1), seq)
def setModelData(self, editor, model, index):
self.editing_indices.pop(index.row())
self.sizeHintChanged.emit(index)
self.closeEditor.emit(editor, self.NoHint)
custom = []
if editor.custom.isChecked():

View File

@ -141,8 +141,8 @@ class FormatList(QListWidget):
if event.key() == Qt.Key_Delete:
self.emit(SIGNAL('delete_format()'))
else:
QListWidget.keyPressEvent(self, event)
return QListWidget.keyPressEvent(self, event)
class ImageView(QLabel):

View File

@ -204,23 +204,22 @@ get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iter
return buffer;
}
static BOOL
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
unsigned int j;
swprintf(xVid, L"vid_%4.4x", vid);
swprintf(dVid, L"vid_%4.4d", vid);
swprintf(xPid, L"pid_%4.4x", pid);
swprintf(dPid, L"pid_%4.4d", pid);
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
);
}
static BOOL
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
unsigned int j;
_snwprintf_s(xVid, 9, _TRUNCATE, L"vid_%4.4x", vid);
_snwprintf_s(dVid, 9, _TRUNCATE, L"vid_%4.4d", vid);
_snwprintf_s(xPid, 9, _TRUNCATE, L"pid_%4.4x", pid);
_snwprintf_s(dPid, 9, _TRUNCATE, L"pid_%4.4d", pid);
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
);
}
static HDEVINFO
create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) {
HDEVINFO hDevInfo;
@ -286,7 +285,7 @@ get_all_removable_disks(struct tagDrives *g_drives)
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE))
{
g_drives[g_count].letter = caDrive[0];
wcscpy(g_drives[g_count].volume, volume);
wcscpy_s(g_drives[g_count].volume, BUFSIZE, volume);
g_count ++;
}
@ -515,15 +514,17 @@ winutil_eject_drive(PyObject *self, PyObject *args) {
PSP_DEVICE_INTERFACE_DETAIL_DATA
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
BOOL *iterate) {
get_device_ancestors(HDEVINFO hDevInfo, DWORD index, PyObject *candidates, BOOL *iterate, BOOL ddebug) {
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA devInfoData;
BOOL status;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD interfaceDetailDataSize,
reqSize;
DEVINST parent;
DEVINST parent, pos;
wchar_t temp[BUFSIZE];
int i;
PyObject *devid;
interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
@ -549,7 +550,7 @@ get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_i
);
interfaceDetailDataSize = reqSize;
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+10);
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+50);
if ( interfaceDetailData == NULL ) {
PyErr_NoMemory();
return NULL;
@ -563,38 +564,49 @@ get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_i
interfaceDetailDataSize, // Interface detail data size
&reqSize, // Buffer size required to get the detail data
&devInfoData); // Interface device info
if (ddebug) printf("Getting ancestors\n"); fflush(stdout);
if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}
// Get the device instance of parent. This points to USBSTOR.
CM_Get_Parent(&parent, devInfoData.DevInst, 0);
// Get the device ID of the USBSTORAGE volume
CM_Get_Device_ID(parent, volume_id, BUFSIZE, 0);
// Get the device instance of grand parent. This points to USB root.
CM_Get_Parent(&parent, parent, 0);
// Get the device ID of the USB root.
CM_Get_Device_ID(parent, buf, BUFSIZE, 0);
pos = devInfoData.DevInst;
for(i = 0; i < 10; i++) {
// Get the device instance of parent.
if (CM_Get_Parent(&parent, pos, 0) != CR_SUCCESS) break;
if (CM_Get_Device_ID(parent, temp, BUFSIZE, 0) == CR_SUCCESS) {
if (ddebug) wprintf(L"device id: %s\n", temp); fflush(stdout);
devid = PyUnicode_FromWideChar(temp, wcslen(temp));
if (devid) {
PyList_Append(candidates, devid);
Py_DECREF(devid);
}
}
pos = parent;
}
return interfaceDetailData;
}
static PyObject *
winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) {
unsigned int vid, pid, length, j;
HDEVINFO hDevInfo;
BOOL iterate = TRUE;
winutil_get_removable_drives(PyObject *self, PyObject *args) {
HDEVINFO hDevInfo;
BOOL iterate = TRUE, ddebug = FALSE;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD i;
WCHAR buf[BUFSIZE], volume[BUFSIZE], volume_id[BUFSIZE];
unsigned int j, length;
WCHAR volume[BUFSIZE];
struct tagDrives g_drives[MAX_DRIVES];
PyObject *volumes, *key, *val;
PyObject *volumes, *key, *candidates, *pdebug = Py_False, *temp;
if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) {
if (!PyArg_ParseTuple(args, "|O", &pdebug)) {
return NULL;
}
ddebug = PyObject_IsTrue(pdebug);
volumes = PyDict_New();
if (volumes == NULL) return NULL;
for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0;
@ -609,47 +621,44 @@ winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) {
// Enumerate through the set
for (i=0; iterate; i++) {
interfaceDetailData = get_device_grandparent(hDevInfo, i, buf, volume_id, &iterate);
candidates = PyList_New(0);
if (candidates == NULL) return PyErr_NoMemory();
interfaceDetailData = get_device_ancestors(hDevInfo, i, candidates, &iterate, ddebug);
if (interfaceDetailData == NULL) {
PyErr_Print(); continue;
}
debug("Device num: %d Device Id: %ws\n\n", i, buf);
if (check_device_id(buf, vid, pid)) {
debug("Device matches\n\n");
length = wcslen(interfaceDetailData->DevicePath);
interfaceDetailData->DevicePath[length] = '\\';
interfaceDetailData->DevicePath[length+1] = 0;
if(GetVolumeNameForVolumeMountPoint(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
for(j = 0; j < MAX_DRIVES; j++) {
// Compare volume mount point with the one stored earlier.
// If both match, return the corresponding drive letter.
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0)
{
key = PyUnicode_FromWideChar(volume_id, wcslen(volume_id));
val = PyString_FromFormat("%c", (char)g_drives[j].letter);
if (key == NULL || val == NULL) {
PyErr_NoMemory();
PyMem_Free(interfaceDetailData);
return NULL;
}
PyDict_SetItem(volumes, key, val);
}
length = wcslen(interfaceDetailData->DevicePath);
interfaceDetailData->DevicePath[length] = L'\\';
interfaceDetailData->DevicePath[length+1] = 0;
if (ddebug) wprintf(L"Device path: %s\n", interfaceDetailData->DevicePath); fflush(stdout);
// On Vista+ DevicePath contains the information we need.
temp = PyUnicode_FromWideChar(interfaceDetailData->DevicePath, length);
if (temp == NULL) return PyErr_NoMemory();
PyList_Append(candidates, temp);
Py_DECREF(temp);
if(GetVolumeNameForVolumeMountPointW(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
if (ddebug) wprintf(L"Volume: %s\n", volume); fflush(stdout);
for(j = 0; j < MAX_DRIVES; j++) {
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0) {
if (ddebug) printf("Found drive: %c\n", (char)g_drives[j].letter); fflush(stdout);
key = PyBytes_FromFormat("%c", (char)g_drives[j].letter);
if (key == NULL) return PyErr_NoMemory();
PyDict_SetItem(volumes, key, candidates);
Py_DECREF(candidates);
break;
}
} else {
debug("Failed to get volume name for volume mount point:\n");
if (DEBUG) debug("%ws\n\n", format_last_error());
}
PyMem_Free(interfaceDetailData);
}
PyMem_Free(interfaceDetailData);
} //for
SetupDiDestroyDeviceInfoList(hDevInfo);
return volumes;
}
static PyObject *
@ -876,21 +885,22 @@ static PyMethodDef WinutilMethods[] = {
"script being run. So to replace sys.argv, you should use "
"sys.argv[1:] = argv()[1:]."},
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
"is_usb_device_connected(vid, pid) -> bool\n\n"
"Check if the USB device identified by VendorID: vid (integer) and"
" ProductID: pid (integer) is currently connected."},
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
"is_usb_device_connected(vid, pid) -> bool\n\n"
"Check if the USB device identified by VendorID: vid (integer) and"
" ProductID: pid (integer) is currently connected."},
{"get_usb_devices", winutil_get_usb_devices, METH_VARARGS,
"get_usb_devices() -> list of strings\n\n"
"Return a list of the hardware IDs of all USB devices "
"connected to the system."},
{"get_mounted_volumes_for_usb_device", winutil_get_mounted_volumes_for_usb_device, METH_VARARGS,
"get_mounted_volumes_for_usb_device(vid, pid) -> dict\n\n"
"Return a dictionary of volume_id:drive_letter for all"
"volumes mounted on the system that belong to the"
"usb device specified by vid (integer) and pid (integer)."},
{"get_removable_drives", winutil_get_removable_drives, METH_VARARGS,
"get_removable_drives(debug=False) -> dict\n\n"
"Return mapping of all removable drives in the system. Maps drive letters "
"to a list of device id strings, atleast one of which will carry the information "
"needed for device matching. On Vista+ it is always the last string in the list. "
"Note that you should upper case all strings."},
{"set_debug", winutil_set_debug, METH_VARARGS,
"set_debug(bool)\n\nSet debugging mode."