tools v5.4.1

This commit is contained in:
Apprentice Alf
2012-11-20 13:28:12 +00:00
parent 0dcd18d524
commit b661a6cdc5
80 changed files with 5564 additions and 4784 deletions

View File

@@ -1,4 +1,8 @@
<html>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Ignoble Epub DeDRM Plugin Configuration</title>
@@ -7,10 +11,10 @@
<body>
<h1>Ignoble Epub DeDRM Plugin</h1>
<h3>(version 0.2.3)</h3>
<h3>(version 0.2.4)</h3>
<h3> For additional help read the <a href="http://apprenticealf.wordpress.com/2011/01/17/frequently-asked-questions-about-the-drm-removal-tools/" target="_blank">FAQ</a> on <a href="http://apprenticealf.wordpress.com" target="_blank">Apprentice Alf's Blog</a> and ask questions in the comments section of the <a href="http://apprenticealf.wordpress.com/2012/09/10/drm-removal-tools-for-ebooks/" target="_blank">first post</a>.</h3>
<p>All credit given to I &lt;3 Cabbages for the original standalone scripts (I had the much easier job of converting them to a calibre plugin).</p>
<p>All credit given to I Cabbages for the original standalone scripts (I had the much easier job of converting them to a calibre plugin).</p>
<p>This plugin is meant to decrypt Barnes & Noble ePubs that are protected with Adobe's Adept encryption. It is meant to function without having to install any dependencies... other than having calibre installed, of course. It will still work if you have Python and PyCrypto already installed, but they aren't necessary.</p>
@@ -83,6 +87,8 @@
0.2.1 - an updated/modified zipfix.py and included zipfilerugged.py
0.2.2 - added in potential fixes from 0.1.7 that had been missed.
0.2.3 - fixed possible output/unicode problem
0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp.
- added ability to rename existing keys.
</pre>
</body>

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
# -*- coding: utf-8 -*-
from __future__ import with_statement
__license__ = 'GPL v3'
@@ -11,7 +12,7 @@ __docformat__ = 'restructuredtext en'
#
# Requires Calibre version 0.7.55 or higher.
#
# All credit given to I <3 Cabbages for the original standalone scripts.
# All credit given to I Cabbages for the original standalone scripts.
# I had the much easier job of converting them to Calibre a plugin.
#
# This plugin is meant to decrypt Barnes & Noble Epubs that are protected
@@ -40,13 +41,15 @@ __docformat__ = 'restructuredtext en'
# 0.2.1 - an updated/modified zipfix.py and included zipfilerugged.py
# 0.2.2 - added in potential fixes from 0.1.7 that had been missed.
# 0.2.3 - fixed possible output/unicode problem
# 0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp.
# - added ability to rename existing keys.
"""
Decrypt Barnes & Noble ADEPT encrypted EPUB books.
"""
PLUGIN_NAME = 'Ignoble Epub DeDRM'
PLUGIN_VERSION_TUPLE = (0, 2, 3)
PLUGIN_VERSION_TUPLE = (0, 2, 4)
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
# Include an html helpfile in the plugin's zipfile with the following name.
RESOURCE_NAME = PLUGIN_NAME + '_Help.htm'
@@ -225,7 +228,7 @@ from calibre.gui2 import is_ok_to_use_qt
class IgnobleDeDRM(FileTypePlugin):
name = PLUGIN_NAME
description = 'Removes DRM from secure Barnes & Noble epub files. Credit given to I <3 Cabbages for the original stand-alone scripts.'
description = 'Removes DRM from secure Barnes & Noble epub files. Credit given to I Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer'
version = PLUGIN_VERSION_TUPLE
@@ -258,10 +261,12 @@ class IgnobleDeDRM(FileTypePlugin):
import calibre_plugins.ignoble_epub.config as cfg
if not cfg.prefs['configured']:
titlemsg = '%s v%s' % (PLUGIN_NAME, PLUGIN_VERSION)
errmsg = 'Plugin not configured! Decryption unsuccessful.\n' + \
'\nThis may be the first time you\'ve used this plugin\n' + \
'(or the first time since upgrading this plugin).\n' + \
'\nYou\'ll need to open the customization dialog (Preferences->Plugins->File type plugins).'
errmsg = titlemsg + ' not (properly) configured!\n' + \
'\nThis may be the first time you\'ve used this plugin' + \
' (or the first time since upgrading this plugin).' + \
' You\'ll need to open the customization dialog (Preferences->Plugins->File type plugins)' + \
' and follow the instructions there.\n' + \
'\nIf you don\'t use the ' + PLUGIN_NAME + ' plugin, you should disable or uninstall it.'
if is_ok_to_use_qt():
from PyQt4.Qt import QMessageBox
d = QMessageBox(QMessageBox.Warning, titlemsg, errmsg )

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
@@ -21,8 +22,8 @@ from calibre.utils.config import dynamic, config_dir, JSONConfig
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
from calibre_plugins.ignoble_epub.__init__ import RESOURCE_NAME as help_file_name
from calibre_plugins.ignoble_epub.utilities import (_load_crypto, normalize_name,
generate_keyfile, caselessStrCmp, AddKeyDialog,
DETAILED_MESSAGE, parseCustString)
generate_keyfile, uStrCmp, DETAILED_MESSAGE, parseCustString)
from calibre_plugins.ignoble_epub.dialogs import AddKeyDialog, RenameKeyDialog
JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_')
JSON_PATH = 'plugins/' + JSON_NAME + '.json'
@@ -135,6 +136,12 @@ class ConfigWidget(QWidget):
self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
self._delete_key_button.clicked.connect(self.delete_key)
button_layout.addWidget(self._delete_key_button)
self._rename_key_button = QtGui.QToolButton(self)
self._rename_key_button.setToolTip(_('Rename highlighted key'))
self._rename_key_button.setIcon(QIcon(I('edit-select-all.png')))
self._rename_key_button.clicked.connect(self.rename_key)
button_layout.addWidget(self._rename_key_button)
self.export_key_button = QtGui.QToolButton(self)
self.export_key_button.setToolTip(_('Export highlighted key'))
@@ -171,10 +178,34 @@ class ConfigWidget(QWidget):
self.listy.clear()
self.populate_list()
def rename_key(self):
if not self.listy.currentItem():
errmsg = '<p>No keyfile selected to export. Highlight a keyfile first.'
r = error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
return
d = RenameKeyDialog(self)
d.exec_()
if d.result() != d.Accepted:
# rename cancelled or moot.
return
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
if not question_dialog(self, _('Are you sure?'), _('<p>'+
'Do you really want to rename the Ignoble key named <strong>%s</strong> to <strong>%s</strong>?') % (keyname, d.key_name),
show_copy_button=False, default_yes=False):
return
self.plugin_keys[d.key_name] = self.plugin_keys[keyname]
del self.plugin_keys[keyname]
self.listy.clear()
self.populate_list()
def delete_key(self):
if not self.listy.currentItem():
return
keyname = unicode(self.listy.currentItem().text())
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
if not question_dialog(self, _('Are you sure?'), _('<p>'+
'Do you really want to delete the Ignoble key named <strong>%s</strong>?') % keyname,
show_copy_button=False, default_yes=False):
@@ -214,21 +245,20 @@ class ConfigWidget(QWidget):
new_key_name = os.path.splitext(os.path.basename(filename))[0]
match = False
for key in self.plugin_keys.keys():
if caselessStrCmp(new_key_name, key) == 0:
if uStrCmp(new_key_name, key, True):
skipped += 1
msg = '<p>A key with the name <strong>' + new_key_name + '</strong> already exists! </p>' + \
'<p>Skipping key file named <strong>' + filename + '</strong>.</p>' + \
'<p>Either delete the existing key and re-migrate, or ' + \
'create that key manually with a different name.'
inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'),
_(msg), show=True)
match = True
break
if not match:
with open(fpath, 'rb') as f:
counter += 1
self.plugin_keys[unicode(new_key_name)] = f.read()
else:
skipped += 1
msg = '<p>A key with the name <strong>' + new_key_name + '</strong> already exists! </p>' + \
'<p>Skipping key file named <strong>' + filename + '</strong>.</p>' + \
'<p>Either delete the existing key and re-migrate, or ' + \
'create that key manually with a different name.'
inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'),
_(msg), show=True)
msg = '<p>Done migrating <strong>' + str(counter) + '</strong> ' + \
'key files...</p><p>Skipped <strong>' + str(skipped) + '</strong> key files.'
@@ -249,12 +279,12 @@ class ConfigWidget(QWidget):
_(errmsg), show=True, show_copy_button=False)
return
filter = QString('Ignoble Key Files (*.b64)')
keyname = unicode(self.listy.currentItem().text())
keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8')
if dynamic.get(PLUGIN_NAME + 'save_dir'):
defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), keyname + '.b64')
else:
defaultname = os.path.join(os.path.expanduser('~'), keyname + '.b64')
filename = str(QtGui.QFileDialog.getSaveFileName(self, "Save Ignoble Key File as...", defaultname,
filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save Ignoble Key File as...", defaultname,
"Ignoble Key Files (*.b64)", filter))
if filename:
dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
@@ -266,7 +296,7 @@ class ConfigWidget(QWidget):
filter = QString('Text files (*.txt)')
default_basefilename = PLUGIN_NAME + ' old customization data.txt'
defaultname = os.path.join(os.path.expanduser('~'), default_basefilename)
filename = str(QtGui.QFileDialog.getSaveFileName(self, "Save old plugin style customization data as...", defaultname,
filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save old plugin style customization data as...", defaultname,
"Text Files (*.txt)", filter))
if filename:
fname = open(filename, 'w')

View File

@@ -0,0 +1,160 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
from PyQt4.Qt import (Qt, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
QGroupBox, QDialog, QDialogButtonBox)
from calibre.gui2 import error_dialog
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
from calibre_plugins.ignoble_epub.utilities import uStrCmp
class AddKeyDialog(QDialog):
def __init__(self, parent=None,):
QDialog.__init__(self, parent)
self.parent = parent
self.setWindowTitle('Create New Ignoble Key')
layout = QVBoxLayout(self)
self.setLayout(layout)
data_group_box = QGroupBox('', self)
layout.addWidget(data_group_box)
data_group_box_layout = QVBoxLayout()
data_group_box.setLayout(data_group_box_layout)
key_group = QHBoxLayout()
data_group_box_layout.addLayout(key_group)
key_group.addWidget(QLabel('Unique Key Name:', self))
self.key_ledit = QLineEdit('', self)
self.key_ledit.setToolTip(_('<p>Enter an identifying name for this new Ignoble key.</p>' +
'<p>It should be something that will help you remember ' +
'what personal information was used to create it.'))
key_group.addWidget(self.key_ledit)
key_label = QLabel(_(''), self)
key_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(key_label)
name_group = QHBoxLayout()
data_group_box_layout.addLayout(name_group)
name_group.addWidget(QLabel('Your Name:', self))
self.name_ledit = QLineEdit('', self)
self.name_ledit.setToolTip(_('<p>Enter your name as it appears in your B&N ' +
'account and/or on your credit card.</p>' +
'<p>It will only be used to generate this ' +
'one-time key and won\'t be stored anywhere ' +
'in calibre or on your computer.</p>' +
'<p>(ex: Jonathan Smith)'))
name_group.addWidget(self.name_ledit)
name_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
name_disclaimer_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(name_disclaimer_label)
ccn_group = QHBoxLayout()
data_group_box_layout.addLayout(ccn_group)
ccn_group.addWidget(QLabel('Credit Card#:', self))
self.cc_ledit = QLineEdit('', self)
self.cc_ledit.setToolTip(_('<p>Enter the full credit card number on record ' +
'in your B&N account.</p>' +
'<p>No spaces or dashes... just the numbers. ' +
'This CC# will only be used to generate this ' +
'one-time key and won\'t be stored anywhere in ' +
'calibre or on your computer.'))
ccn_group.addWidget(self.cc_ledit)
ccn_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(ccn_disclaimer_label)
layout.addSpacing(20)
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
self.resize(self.parent.sizeHint())
def accept(self):
if (self.key_ledit.text().isEmpty() or self.name_ledit.text().isEmpty()
or self.cc_ledit.text().isEmpty()):
errmsg = '<p>All fields are required!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
if (unicode(self.key_ledit.text()).isspace() or unicode(self.name_ledit.text()).isspace()
or unicode(self.cc_ledit.text()).isspace()):
errmsg = '<p>All fields are required!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
if not unicode(self.cc_ledit.text()).isdigit():
errmsg = '<p>Numbers only in the credit card number field!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
if len(self.key_ledit.text()) < 4:
errmsg = '<p>Key name must be at <i>least</i> 4 characters long!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
for k in self.parent.plugin_keys.keys():
if uStrCmp(self.key_ledit.text(), k, True):
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
QDialog.accept(self)
@property
def user_name(self):
return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','')
@property
def cc_number(self):
return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','')
@property
def key_name(self):
return unicode(self.key_ledit.text().toUtf8(), 'utf8')
class RenameKeyDialog(QDialog):
def __init__(self, parent=None,):
QDialog.__init__(self, parent)
self.parent = parent
self.setWindowTitle('Rename Ignoble Key')
layout = QVBoxLayout(self)
self.setLayout(layout)
data_group_box = QGroupBox('', self)
layout.addWidget(data_group_box)
data_group_box_layout = QVBoxLayout()
data_group_box.setLayout(data_group_box_layout)
data_group_box_layout.addWidget(QLabel('Key Name:', self))
self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
self.key_ledit.setToolTip(_('<p>Enter a new name for this existing Ignoble key.'))
data_group_box_layout.addWidget(self.key_ledit)
layout.addSpacing(20)
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
def accept(self):
if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace():
errmsg = '<p>Key name field cannot be empty!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
if len(self.key_ledit.text()) < 4:
errmsg = '<p>Key name must be at <i>least</i> 4 characters long!'
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()):
# Same exact name ... do nothing.
return QDialog.reject(self)
for k in self.parent.plugin_keys.keys():
if (uStrCmp(self.key_ledit.text(), k, True) and
not uStrCmp(k, self.parent.listy.currentItem().text(), True)):
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
return error_dialog(None, PLUGIN_NAME,
_(errmsg), show=True, show_copy_button=False)
QDialog.accept(self)
@property
def key_name(self):
return unicode(self.key_ledit.text().toUtf8(), 'utf8')

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
@@ -6,15 +7,10 @@ __license__ = 'GPL v3'
import hashlib
from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_int, c_long, \
Structure, c_ulong, create_string_buffer, cast
Structure, c_ulong, create_string_buffer, cast
from ctypes.util import find_library
from PyQt4.Qt import (Qt, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
QGroupBox, QDialog, QDialogButtonBox)
from calibre.gui2 import error_dialog
from calibre.constants import iswindows
from calibre_plugins.ignoble_epub.__init__ import PLUGIN_NAME, PLUGIN_VERSION
DETAILED_MESSAGE = \
@@ -37,18 +33,18 @@ def normalize_name(name): # Strip spaces and convert to lowercase.
# These are the key ENCRYPTING aes crypto functions
def generate_keyfile(name, ccn):
# Load the necessary crypto libs.
AES = _load_crypto()
name = normalize_name(name) + '\x00'
ccn = ccn + '\x00'
name_sha = hashlib.sha1(name).digest()[:16]
ccn_sha = hashlib.sha1(ccn).digest()[:16]
both_sha = hashlib.sha1(name + ccn).digest()
aes = AES(ccn_sha, name_sha)
crypt = aes.encrypt(both_sha + ('\x0c' * 0x0c))
userkey = hashlib.sha1(crypt).digest()
# Load the necessary crypto libs.
AES = _load_crypto()
name = normalize_name(name) + '\x00'
ccn = ccn + '\x00'
name_sha = hashlib.sha1(name).digest()[:16]
ccn_sha = hashlib.sha1(ccn).digest()[:16]
both_sha = hashlib.sha1(name + ccn).digest()
aes = AES(ccn_sha, name_sha)
crypt = aes.encrypt(both_sha + ('\x0c' * 0x0c))
userkey = hashlib.sha1(crypt).digest()
return userkey.encode('base64')
return userkey.encode('base64')
def _load_crypto_libcrypto():
if iswindows:
@@ -122,139 +118,23 @@ def _load_crypto():
pass
return _aes
def caselessStrCmp(s1, s2):
"""
A function to case-insensitively compare strings. Python's .lower() function
isn't always very accurate when it comes to unicode. Using the standard C lib's
strcasecmp instead. Maybe a tad slower, but we're not scouring scads of string lists here.
"""
str1 = unicode(s1)
str2 = unicode(s2)
c_char_pp = POINTER(c_char_p)
c_int_p = POINTER(c_int)
if iswindows:
libc = find_library('msvcrt')
def uStrCmp (s1, s2, caseless=False):
import unicodedata as ud
str1 = s1 if isinstance(s1, unicode) else unicode(s1)
str2 = s2 if isinstance(s2, unicode) else unicode(s2)
if caseless:
return ud.normalize('NFC', str1.lower()) == ud.normalize('NFC', str2.lower())
else:
libc = find_library('c')
if libc is None:
raise IgnobleError('libc not found')
libc = CDLL(libc)
def F(restype, name, argtypes):
func = getattr(libc, name)
func.restype = restype
func.argtypes = argtypes
return func
if iswindows:
_stricmp = F(c_int, '_stricmp', [c_char_p, c_char_p])
return _stricmp(str1, str2)
strcasecmp = F(c_int, 'strcasecmp', [c_char_p, c_char_p])
return strcasecmp(str1, str2)
class AddKeyDialog(QDialog):
def __init__(self, parent=None,):
QDialog.__init__(self, parent)
self.parent = parent
self.setWindowTitle('Create New Ignoble Key')
layout = QVBoxLayout(self)
self.setLayout(layout)
data_group_box = QGroupBox('', self)
layout.addWidget(data_group_box)
data_group_box_layout = QVBoxLayout()
data_group_box.setLayout(data_group_box_layout)
key_group = QHBoxLayout()
data_group_box_layout.addLayout(key_group)
key_group.addWidget(QLabel('Unique Key Name:', self))
self.key_ledit = QLineEdit('', self)
self.key_ledit.setToolTip(_('<p>Enter an identifying name for this new Ignoble key.</p>' +
'<p>It should be something that will help you remember ' +
'what personal information was used to create it.'))
key_group.addWidget(self.key_ledit)
key_label = QLabel(_(''), self)
key_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(key_label)
name_group = QHBoxLayout()
data_group_box_layout.addLayout(name_group)
name_group.addWidget(QLabel('Your Name:', self))
self.name_ledit = QLineEdit('', self)
self.name_ledit.setToolTip(_('<p>Enter your name as it appears in your B&N ' +
'account and/or on your credit card.</p>' +
'<p>It will only be used to generate this ' +
'one-time key and won\'t be stored anywhere ' +
'in calibre or on your computer.</p>' +
'<p>(ex: Jonathan Smith)'))
name_group.addWidget(self.name_ledit)
name_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
name_disclaimer_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(name_disclaimer_label)
ccn_group = QHBoxLayout()
data_group_box_layout.addLayout(ccn_group)
ccn_group.addWidget(QLabel('Credit Card#:', self))
self.cc_ledit = QLineEdit('', self)
self.cc_ledit.setToolTip(_('<p>Enter the full credit card number on record ' +
'in your B&N account.</p>' +
'<p>No spaces or dashes... just the numbers. ' +
'This CC# will only be used to generate this ' +
'one-time key and won\'t be stored anywhere in ' +
'calibre or on your computer.'))
ccn_group.addWidget(self.cc_ledit)
ccn_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self)
ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
data_group_box_layout.addWidget(ccn_disclaimer_label)
layout.addSpacing(20)
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
self.resize(self.parent.sizeHint())
def accept(self):
match = False
if (self.key_ledit.text().isEmpty() or self.name_ledit.text().isEmpty()
or self.cc_ledit.text().isEmpty()):
errmsg = '<p>All fields are required!'
return error_dialog(None, PLUGIN_NAME + 'error_dialog',
_(errmsg), show=True, show_copy_button=False)
for k in self.parent.plugin_keys.keys():
if caselessStrCmp(self.key_ledit.text(), k) == 0:
match = True
break
if match:
errmsg = '<p>The key name <strong>%s</strong> is already being used.' % self.key_ledit.text()
return error_dialog(None, PLUGIN_NAME + 'error_dialog',
_(errmsg), show=True, show_copy_button=False)
else:
QDialog.accept(self)
@property
def user_name(self):
return unicode(self.name_ledit.text()).strip().lower().replace(' ', '')
@property
def cc_number(self):
return unicode(self.cc_ledit.text()).strip().replace(' ', '').replace('-','')
@property
def key_name(self):
return unicode(self.key_ledit.text())
return ud.normalize('NFC', str1) == ud.normalize('NFC', str2)
def parseCustString(keystuff):
userkeys = []
ar = keystuff.split(':')
for i in ar:
try:
name, ccn = i.split(',')
except:
return False
# Generate Barnes & Noble EPUB user key from name and credit card number.
userkeys.append(generate_keyfile(name, ccn))
return userkeys
userkeys = []
ar = keystuff.split(':')
for i in ar:
try:
name, ccn = i.split(',')
except:
return False
# Generate Barnes & Noble EPUB user key from name and credit card number.
userkeys.append(generate_keyfile(name, ccn))
return userkeys