Merge branch 'master' of https://github.com/cbhaley/calibre into master

Fix #1892611 [Random book appears in the Quickview panel when calibre starts](https://bugs.launchpad.net/calibre/+bug/1892611)
This commit is contained in:
Kovid Goyal 2020-08-23 18:05:47 +05:30
commit db35c0ca1f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 117 additions and 3 deletions

View File

@ -384,6 +384,10 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
self.debug_start_time = time.time() self.debug_start_time = time.time()
self.debug_time = time.time() self.debug_time = time.time()
self.is_connected = False self.is_connected = False
# Hack to work around the newly-enforced 15 character service name limit.
# "monkeypatch" zeroconf with a function without the check
import zeroconf
zeroconf.service_type_name = service_type_name
# Don't call this method from the GUI unless you are sure that there is no # Don't call this method from the GUI unless you are sure that there is no
# network traffic in progress. Otherwise the gui might hang waiting for the # network traffic in progress. Otherwise the gui might hang waiting for the
@ -2032,3 +2036,111 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
def is_running(self): def is_running(self):
return getattr(self, 'listen_socket', None) is not None return getattr(self, 'listen_socket', None) is not None
# Function to monkeypatch zeroconf to remove the 15 character name length restriction.
# Copied from https://github.com/jstasiak/python-zeroconf version 0.28.1
from zeroconf import (BadTypeInNameException, _HAS_A_TO_Z,
_HAS_ONLY_A_TO_Z_NUM_HYPHEN_UNDERSCORE,
_HAS_ASCII_CONTROL_CHARS,
_HAS_ONLY_A_TO_Z_NUM_HYPHEN)
def service_type_name(type_: str, *, allow_underscores: bool = False) -> str:
"""
Validate a fully qualified service name, instance or subtype. [rfc6763]
Returns fully qualified service name.
Domain names used by mDNS-SD take the following forms:
<sn> . <_tcp|_udp> . local.
<Instance> . <sn> . <_tcp|_udp> . local.
<sub>._sub . <sn> . <_tcp|_udp> . local.
1) must end with 'local.'
This is true because we are implementing mDNS and since the 'm' means
multi-cast, the 'local.' domain is mandatory.
2) local is preceded with either '_udp.' or '_tcp.'
3) service name <sn> precedes <_tcp|_udp>
The rules for Service Names [RFC6335] state that they may be no more
than fifteen characters long (not counting the mandatory underscore),
consisting of only letters, digits, and hyphens, must begin and end
with a letter or digit, must not contain consecutive hyphens, and
must contain at least one letter.
The instance name <Instance> and sub type <sub> may be up to 63 bytes.
The portion of the Service Instance Name is a user-
friendly name consisting of arbitrary Net-Unicode text [RFC5198]. It
MUST NOT contain ASCII control characters (byte values 0x00-0x1F and
0x7F) [RFC20] but otherwise is allowed to contain any characters,
without restriction, including spaces, uppercase, lowercase,
punctuation -- including dots -- accented characters, non-Roman text,
and anything else that may be represented using Net-Unicode.
:param type_: Type, SubType or service name to validate
:return: fully qualified service name (eg: _http._tcp.local.)
"""
if not (type_.endswith('._tcp.local.') or type_.endswith('._udp.local.')):
raise BadTypeInNameException("Type '%s' must end with '._tcp.local.' or '._udp.local.'" % type_)
remaining = type_[: -len('._tcp.local.')].split('.')
name = remaining.pop()
if not name:
raise BadTypeInNameException("No Service name found")
if len(remaining) == 1 and len(remaining[0]) == 0:
raise BadTypeInNameException("Type '%s' must not start with '.'" % type_)
if name[0] != '_':
raise BadTypeInNameException("Service name (%s) must start with '_'" % name)
# remove leading underscore
name = name[1:]
# if len(name) > 15:
# raise BadTypeInNameException("Service name (%s) must be <= 15 bytes" % name)
if '--' in name:
raise BadTypeInNameException("Service name (%s) must not contain '--'" % name)
if '-' in (name[0], name[-1]):
raise BadTypeInNameException("Service name (%s) may not start or end with '-'" % name)
if not _HAS_A_TO_Z.search(name):
raise BadTypeInNameException("Service name (%s) must contain at least one letter (eg: 'A-Z')" % name)
allowed_characters_re = (
_HAS_ONLY_A_TO_Z_NUM_HYPHEN_UNDERSCORE if allow_underscores else _HAS_ONLY_A_TO_Z_NUM_HYPHEN
)
if not allowed_characters_re.search(name):
raise BadTypeInNameException(
"Service name (%s) must contain only these characters: "
"A-Z, a-z, 0-9, hyphen ('-')%s" % (name, ", underscore ('_')" if allow_underscores else "")
)
if remaining and remaining[-1] == '_sub':
remaining.pop()
if len(remaining) == 0 or len(remaining[0]) == 0:
raise BadTypeInNameException("_sub requires a subtype name")
if len(remaining) > 1:
remaining = ['.'.join(remaining)]
if remaining:
length = len(remaining[0].encode('utf-8'))
if length > 63:
raise BadTypeInNameException("Too long: '%s'" % remaining[0])
if _HAS_ASCII_CONTROL_CHARS.search(remaining[0]):
raise BadTypeInNameException(
"Ascii control character 0x00-0x1F and 0x7F illegal in '%s'" % remaining[0]
)
return '_' + name + type_[-len('._tcp.local.') :]

View File

@ -466,13 +466,15 @@ class Quickview(QDialog, Ui_Quickview):
Given a cell in the library view, display the information. This method Given a cell in the library view, display the information. This method
converts the index into the lookup key converts the index into the lookup key
''' '''
if self.lock_qv.isChecked(): if self.lock_qv.isChecked() or not idx.isValid():
return return
try: try:
self.current_column = ( self.current_column = (
self.view.column_map.index('authors') if self.current_column is None and self.view.column_map[idx.column()] == 'title' self.view.column_map.index('authors')
else idx.column()) if self.current_column is None
and self.view.column_map[idx.column()] == 'title'
else idx.column())
key = self.view.column_map[self.current_column] key = self.view.column_map[self.current_column]
book_id = self.view.model().id(idx.row()) book_id = self.view.model().id(idx.row())
if self.current_book_id == book_id and self.current_key == key: if self.current_book_id == book_id and self.current_key == key: