summaryrefslogtreecommitdiffstats
path: root/DeDRM_Macintosh_Application
diff options
context:
space:
mode:
authorApprentice Alf <[email protected]>2013-04-05 17:44:48 +0100
committerApprentice Alf <[email protected]>2015-03-07 14:45:12 +0000
commitd586f74faabe2011ea4f7d2116563b15e45a9052 (patch)
tree8fe992e1d922c7c43f45a625f0cbc285f5db9f48 /DeDRM_Macintosh_Application
parenta2f044e672e301a5a0166e426a77620c8f2162c3 (diff)
tools v6.0.2
Diffstat (limited to 'DeDRM_Macintosh_Application')
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist4
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm7
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm4
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scptbin293024 -> 293570 bytes
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py288
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py22
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py1103
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py719
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py18
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py18
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py20
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py18
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py18
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py293
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/wineutils.py60
15 files changed, 1372 insertions, 1220 deletions
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
index 2069280..26f91e9 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
@@ -24,7 +24,7 @@
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleGetInfoString</key>
- <string>DeDRM AppleScript 6.0.1. Written 2010–2013 by Apprentice Alf and others.</string>
+ <string>DeDRM AppleScript 6.0.2. Written 2010–2013 by Apprentice Alf and others.</string>
<key>CFBundleIconFile</key>
<string>DeDRM</string>
<key>CFBundleInfoDictionaryVersion</key>
@@ -34,7 +34,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>6.0.1</string>
+ <string>6.0.2</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSRequiresCarbon</key>
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm
index ee9edb2..b258afe 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm
@@ -44,11 +44,16 @@ li {margin-top: 0.5em}
<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.</p>
+<h3>Linux Users: WINEPREFIX</h3>
+
+<p>Under the list of keys, Linux users will see a text field labeled "WINEPREFIX". If you are use Adobe Digital Editions under Wine, and your wine installation containing Adobe Digital Editions isn't the default Wine installation, you may enter the full path to the correct Wine installation here. Leave blank if you are unsure.</p>
+
<h3>Importing Existing Keyfiles:</h3>
<p>At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.der’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the adobekey.pyw script running under Wine on Linux systems.</p>
-<p>Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.</p>
+<p>Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes will only be saved permanently when you click OK in the main configuration dialog.</p>
+
</body>
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm
index c714581..35f1a50 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm
@@ -44,6 +44,10 @@ li {margin-top: 0.5em}
<p>On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.</p>
+<h3>Linux Users: WINEPREFIX</h3>
+
+<p>Under the list of keys, Linux users will see a text field labeled "WINEPREFIX". If you are use Kindle for PC under Wine, and your wine installation containing Kindle for PC isn't the default Wine installation, you may enter the full path to the correct Wine installation here. Leave blank if you are unsure.</p>
+
<h3>Importing Existing Keyfiles:</h3>
<p>At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.k4i’ key files. Key files might come from being exported from this plugin, or may have been generated using the kindlekey.pyw script running under Wine on Linux systems.</p>
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt
index 009e52d..868ae10 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt
Binary files differ
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
index 6509179..ce72c8d 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
@@ -26,14 +26,15 @@ __docformat__ = 'restructuredtext en'
#
# Revision history:
# 6.0.0 - Initial release
-# 6.0.1 - Bug Fixes for Windows App
+# 6.0.1 - Bug Fixes for Windows App, Kindle for Mac and Windows Adobe Digital Editions
+# 6.0.2 - Restored call to Wine to get Kindle for PC keys
"""
Decrypt DRMed ebooks.
"""
PLUGIN_NAME = u"DeDRM"
-PLUGIN_VERSION_TUPLE = (6, 0, 1)
+PLUGIN_VERSION_TUPLE = (6, 0, 2)
PLUGIN_VERSION = u".".join([unicode(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'
@@ -83,9 +84,11 @@ class DeDRM(FileTypePlugin):
def initialize(self):
# convert old preferences, if necessary.
- import calibre_plugins.dedrm.config
-
- config.convertprefs()
+ try:
+ from calibre_plugins.dedrm.prefs import convertprefs
+ convertprefs()
+ except:
+ traceback.print_exc()
"""
Dynamic modules can't be imported/loaded from a zipfile... so this routine
@@ -101,7 +104,7 @@ class DeDRM(FileTypePlugin):
elif isosx:
names = [u"libalfcrypto.dylib"]
else:
- names = [u"libalfcrypto32.so",u"libalfcrypto64.so"]
+ names = [u"libalfcrypto32.so",u"libalfcrypto64.so",u"kindlekey.py",u"adobekey.py",u"subasyncio.py"]
lib_dict = self.load_resources(names)
self.pluginsdir = os.path.join(config_dir,u"plugins")
if not os.path.exists(self.pluginsdir):
@@ -112,7 +115,7 @@ class DeDRM(FileTypePlugin):
self.helpdir = os.path.join(self.maindir,u"help")
if not os.path.exists(self.helpdir):
os.mkdir(self.helpdir)
- self.alfdir = os.path.join(self.maindir,u"alfcrypto")
+ self.alfdir = os.path.join(self.maindir,u"libraryfiles")
if not os.path.exists(self.alfdir):
os.mkdir(self.alfdir)
for entry, data in lib_dict.items():
@@ -129,25 +132,27 @@ class DeDRM(FileTypePlugin):
inf = self.temporary_file(u".epub")
try:
- print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION)
+ print u"{0} v{1}: Verifying zip archive integrity".format(PLUGIN_NAME, PLUGIN_VERSION)
fr = zipfix.fixZip(path_to_ebook, inf.name)
fr.fix()
except Exception, e:
- print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])
+ print u"{0} v{1}: Error \'{2}\' when checking zip archive".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])
raise Exception(e)
# import the decryption keys
- import calibre_plugins.dedrm.config as config
+ import calibre_plugins.dedrm.prefs as prefs
+ dedrmprefs = prefs.DeDRM_Prefs()
# import the Barnes & Noble ePub handler
import calibre_plugins.dedrm.ignobleepub as ignobleepub
+
#check the book
if ignobleepub.ignobleBook(inf.name):
- print u"{0} v{1}: “{2}” is a secure Barnes & Noble ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
+ print u"{0} v{1}: “{2}” is a secure Barnes & Noble ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
# Attempt to decrypt epub with each encryption key (generated or provided).
- for keyname, userkey in config.dedrmprefs['bandnkeys'].items():
+ for keyname, userkey in dedrmprefs['bandnkeys'].items():
keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname)
print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked)
of = self.temporary_file(u".epub")
@@ -162,7 +167,7 @@ class DeDRM(FileTypePlugin):
# Return the modified PersistentTemporary file to calibre.
return of.name
- print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)
+ print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)
print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime))
@@ -171,10 +176,10 @@ class DeDRM(FileTypePlugin):
import calibre_plugins.dedrm.ineptepub as ineptepub
if ineptepub.adeptBook(inf.name):
- print u"{0} v{1}: {2} is a secure Adobe Adept ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
+ print u"{0} v{1}: {2} is a secure Adobe Adept ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
# Attempt to decrypt epub with each encryption key (generated or provided).
- for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items():
+ for keyname, userkeyhex in dedrmprefs['adeptkeys'].items():
userkey = userkeyhex.decode('hex')
print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname)
of = self.temporary_file(u".epub")
@@ -192,54 +197,64 @@ class DeDRM(FileTypePlugin):
# Return the modified PersistentTemporary file to calibre.
return of.name
- print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime)
+ print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime)
# perhaps we need to get a new default ADE key
- if iswindows or isosx:
- print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION)
+ print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)
- # get the default Adobe keys
- import calibre_plugins.dedrm.adobekey as adobe
+ # get the default Adobe keys
+ defaultkeys = []
- try:
- defaultkeys = adobe.adeptkeys()
- except:
- defaultkeys = []
+ try:
+ if iswindows or isosx:
+ from calibre_plugins.dedrm.adobekey import adeptkeys
+
+ defaultkeys = adeptkeys()
+ else: # linux
+ from wineutils import WineGetKeys
- newkeys = []
- for keyvalue in defaultkeys:
- if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values():
- newkeys.append(keyvalue)
+ scriptpath = os.join(self.alfdir,u"adobekey.py")
+ defaultkeys = WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
- if len(newkeys) > 0:
- try:
- for i,userkey in enumerate(newkeys):
- print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION)
- of = self.temporary_file(u".epub")
+ self.default_key = default_keys[0]
+ except:
+ traceback.print_exc()
+ self.default_key = u""
- # Give the user key, ebook and TemporaryPersistent file to the decryption function.
+ newkeys = []
+ for keyvalue in defaultkeys:
+ if keyvalue.encode('hex') not in dedrmprefs['adeptkeys'].values():
+ newkeys.append(keyvalue)
+
+ if len(newkeys) > 0:
+ try:
+ for i,userkey in enumerate(newkeys):
+ print u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)
+ of = self.temporary_file(u".epub")
+
+ # Give the user key, ebook and TemporaryPersistent file to the decryption function.
+ try:
+ result = ineptepub.decryptBook(userkey, inf.name, of.name)
+ except:
+ result = 1
+
+ of.close()
+
+ if result == 0:
+ # Decryption was a success
+ # Store the new successful key in the defaults
+ print u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)
try:
- result = ineptepub.decryptBook(userkey, inf.name, of.name)
+ dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex'))
+ dedrmprefs.writeprefs()
except:
- result = 1
-
- of.close()
-
- if result == 0:
- # Decryption was a success
- # Store the new successful key in the defaults
- print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION)
- try:
- config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex'))
- config.writeprefs()
- except:
- traceback.print_exc()
- # Return the modified PersistentTemporary file to calibre.
- return of.name
-
- print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
- except Exception, e:
- pass
+ traceback.print_exc()
+ # Return the modified PersistentTemporary file to calibre.
+ return of.name
+
+ print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
+ except Exception, e:
+ pass
# Something went wrong with decryption.
print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
@@ -247,16 +262,17 @@ class DeDRM(FileTypePlugin):
# Not a Barnes & Noble nor an Adobe Adept
# Import the fixed epub.
- print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
+ print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
return inf.name
def PDFDecrypt(self,path_to_ebook):
- import calibre_plugins.dedrm.config as config
+ import calibre_plugins.dedrm.prefs as prefs
import calibre_plugins.dedrm.ineptpdf
+ dedrmprefs = prefs.DeDRM_Prefs()
# Attempt to decrypt epub with each encryption key (generated or provided).
- print u"{0} v{1}: {2} is a PDF ebook.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
- for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items():
+ print u"{0} v{1}: {2} is a PDF ebook".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
+ for keyname, userkeyhex in dedrmprefs['adeptkeys'].items():
userkey = userkeyhex.decode('hex')
print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname)
of = self.temporary_file(u".pdf")
@@ -275,56 +291,68 @@ class DeDRM(FileTypePlugin):
return of.name
# perhaps we need to get a new default ADE key
- if iswindows or isosx:
- print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION)
+ print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)
+
+ # get the default Adobe keys
+ defaultkeys = []
- # get the default Adobe keys
+ if iswindows or isosx:
import calibre_plugins.dedrm.adobekey as adobe
try:
defaultkeys = adobe.adeptkeys()
except:
- defaultkeys = []
+ pass
+ else:
+ # linux
+ try:
+ from wineutils import WineGetKeys
- newkeys = []
- for keyvalue in defaultkeys:
- if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values():
- newkeys.append(keyvalue)
+ scriptpath = os.join(self.alfdir,u"adobekey.py")
+ defaultkeys = self.WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
+ except:
+ pass
- if len(newkeys) > 0:
- try:
- for i,userkey in enumerate(newkeys):
- print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION)
- of = self.temporary_file(u".pdf")
+ newkeys = []
+ for keyvalue in defaultkeys:
+ if keyvalue.encode('hex') not in dedrmprefs['adeptkeys'].values():
+ newkeys.append(keyvalue)
- # Give the user key, ebook and TemporaryPersistent file to the decryption function.
+ if len(newkeys) > 0:
+ try:
+ for i,userkey in enumerate(newkeys):
+ print u"{0} v{1}: Trying a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)
+ of = self.temporary_file(u".pdf")
+
+ # Give the user key, ebook and TemporaryPersistent file to the decryption function.
+ try:
+ result = ineptepdf.decryptBook(userkey, inf.name, of.name)
+ except:
+ result = 1
+
+ of.close()
+
+ if result == 0:
+ # Decryption was a success
+ # Store the new successful key in the defaults
+ print u"{0} v{1}: Saving a new default key".format(PLUGIN_NAME, PLUGIN_VERSION)
try:
- result = ineptepdf.decryptBook(userkey, inf.name, of.name)
+ dedrmprefs.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex'))
+ dedrmprefs.writeprefs()
except:
- result = 1
-
- of.close()
-
- if result == 0:
- # Decryption was a success
- # Store the new successful key in the defaults
- print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION)
- try:
- config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex'))
- config.writeprefs()
- except:
- traceback.print_exc()
- # Return the modified PersistentTemporary file to calibre.
- return of.name
-
- print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
- except Exception, e:
- pass
+ traceback.print_exc()
+ # Return the modified PersistentTemporary file to calibre.
+ return of.name
+
+ print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
+ except Exception, e:
+ pass
# Something went wrong with decryption.
print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime))
+
def KindleMobiDecrypt(self,path_to_ebook):
# add the alfcrypto directory to sys.path so alfcrypto.py
@@ -333,42 +361,53 @@ class DeDRM(FileTypePlugin):
# Had to move this import here so the custom libs can be
# extracted to the appropriate places beforehand these routines
# look for them.
- import calibre_plugins.dedrm.config as config
+ import calibre_plugins.dedrm.prefs as prefs
import calibre_plugins.dedrm.k4mobidedrm
- pids = config.dedrmprefs['pids']
- serials = config.dedrmprefs['serials']
- kindleDatabases = config.dedrmprefs['kindlekeys'].items()
+ dedrmprefs = prefs.DeDRM_Prefs()
+ pids = dedrmprefs['pids']
+ serials = dedrmprefs['serials']
+ kindleDatabases = dedrmprefs['kindlekeys'].items()
try:
book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kindleDatabases,serials,pids,self.starttime)
except Exception, e:
decoded = False
# perhaps we need to get a new default Kindle for Mac/PC key
- if iswindows or isosx:
- print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0])
- print u"{0} v{1}: Looking for new default Kindle Key".format(PLUGIN_NAME, PLUGIN_VERSION)
- import calibre_plugins.dedrm.kindlekey as amazon
+ defaultkeys = []
+ print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0])
+ print u"{0} v{1}: Looking for new default Kindle Key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)
+
+ try:
+ if iswindows or isosx:
+ from calibre_plugins.dedrm.kindlekey import kindlekeys
+ defaultkeys = kindlekeys()
+ else: # linux
+ from wineutils import WineGetKeys
+
+ scriptpath = os.join(self.alfdir,u"kindlekey.py")
+ defaultkeys = self.WineGetKeys(scriptpath, u".k4i",dedrmprefs['kindlewineprefix'])
+ except:
+ pass
+
+ newkeys = {}
+ for i,keyvalue in enumerate(defaultkeys):
+ keyname = u"default_key_{0:d}".format(i+1)
+ if keyvalue not in dedrmprefs['kindlekeys'].values():
+ newkeys[keyname] = keyvalue
+ if len(newkeys) > 0:
+ print u"{0} v{1}: Found {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys")
try:
- defaultkeys = amazon.kindlekeys()
- except:
- defaultkeys = []
- newkeys = {}
- for i,keyvalue in enumerate(defaultkeys):
- keyname = u"default_key_{0:d}".format(i+1)
- if keyvalue not in config.dedrmprefs['kindlekeys'].values():
- newkeys[keyname] = keyvalue
- if len(newkeys) > 0:
- try:
- book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],self.starttime)
- decoded = True
- # store the new successful keys in the defaults
- for keyvalue in newkeys.values():
- config.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue)
- config.writeprefs()
- except Exception, e:
- pass
+ book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],self.starttime)
+ decoded = True
+ # store the new successful keys in the defaults
+ print u"{0} v{1}: Saving {2} new {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(newkeys), u"key" if len(newkeys)==1 else u"keys")
+ for keyvalue in newkeys.values():
+ dedrmprefs.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue)
+ dedrmprefs.writeprefs()
+ except Exception, e:
+ pass
if not decoded:
#if you reached here then no luck raise and exception
print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
@@ -384,11 +423,12 @@ class DeDRM(FileTypePlugin):
def eReaderDecrypt(self,path_to_ebook):
- import calibre_plugins.dedrm.config as config
+ import calibre_plugins.dedrm.prefs as prefs
import calibre_plugins.dedrm.erdr2pml
+ dedrmrefs = prefs.DeDRM_Prefs()
# Attempt to decrypt epub with each encryption key (generated or provided).
- for keyname, userkey in config.dedrmprefs['ereaderkeys'].items():
+ for keyname, userkey in dedrmprefs['ereaderkeys'].items():
keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname)
print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked)
of = self.temporary_file(u".pmlz")
@@ -403,7 +443,7 @@ class DeDRM(FileTypePlugin):
if result == 0:
return of.name
- print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)
+ print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime)
print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime))
@@ -415,7 +455,7 @@ class DeDRM(FileTypePlugin):
sys.stdout=SafeUnbuffered(sys.stdout)
sys.stderr=SafeUnbuffered(sys.stderr)
- print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
+ print u"{0} v{1}: Trying to decrypt {2}".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))
self.starttime = time.time()
booktype = os.path.splitext(path_to_ebook)[1].lower()[1:]
@@ -434,7 +474,7 @@ class DeDRM(FileTypePlugin):
# Adobe Adept or B&N ePub
decrypted_ebook = self.ePubDecrypt(path_to_ebook)
else:
- print u"Unknown booktype {0}. Passing back to calibre unchanged.".format(booktype)
+ print u"Unknown booktype {0}. Passing back to calibre unchanged".format(booktype)
return path_to_ebook
print u"{0} v{1}: Successfully decrypted book after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)
return decrypted_ebook
@@ -445,7 +485,7 @@ class DeDRM(FileTypePlugin):
def config_widget(self):
import calibre_plugins.dedrm.config as config
- return config.ConfigWidget(self.plugin_path)
+ return config.ConfigWidget(self.plugin_path, self.alfdir)
def save_settings(self, config_widget):
config_widget.save_settings()
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py
index 1dcef1d..bfa542b 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py
@@ -47,13 +47,14 @@ from __future__ import with_statement
# 5.7 - Unicode support added, renamed adobekey from ineptkey
# 5.8 - Added getkey interface for Windows DeDRM application
# 5.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 6.0 - Work if TkInter is missing
"""
Retrieve Adobe ADEPT user key.
"""
__license__ = 'GPL v3'
-__version__ = '5.9'
+__version__ = '6.0'
import sys, os, struct, getopt
@@ -402,9 +403,11 @@ if iswindows:
aes = AES(keykey)
userkey = aes.decrypt(userkey)
userkey = userkey[26:-ord(userkey[-1])]
+ #print "found key:",userkey.encode('hex')
keys.append(userkey)
if len(keys) == 0:
raise ADEPTError('Could not locate privateLicenseKey')
+ print u"Found {0:d} keys".format(len(keys))
return keys
@@ -485,6 +488,8 @@ def usage(progname):
print u" {0:s} [-h] [<outpath>]".format(progname)
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and Apprentice Alf".format(progname,__version__)
@@ -541,10 +546,13 @@ def cli_main():
def gui_main():
- import Tkinter
- import Tkconstants
- import tkMessageBox
- import traceback
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class ExceptionDialog(Tkinter.Frame):
def __init__(self, root, text):
@@ -577,7 +585,7 @@ def gui_main():
keyfileout.write(key)
success = True
tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile))
- except DrmException, e:
+ except ADEPTError, e:
tkMessageBox.showerror(progname, u"Error: {0}".format(str(e)))
except Exception:
root.wm_state('normal')
@@ -591,7 +599,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py
index 04d87c6..f2cd005 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py
@@ -6,15 +6,14 @@ from __future__ import with_statement
__license__ = 'GPL v3'
# Standard Python modules.
-import os, sys, re, hashlib
+import os, traceback
# PyQT4 modules (part of calibre).
from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
QGroupBox, QPushButton, QListWidget, QListWidgetItem,
- QAbstractItemView, QIcon, QDialog, QUrl, QString)
+ QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl, QString)
from PyQt4 import QtGui
-import zipfile
from zipfile import ZipFile
# calibre modules and constants.
@@ -26,50 +25,21 @@ from calibre.constants import iswindows, isosx
# modules from this plugin's zipfile.
from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name
-from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE)
-
-import calibre_plugins.dedrm.dialogs as dialogs
-import calibre_plugins.dedrm.ignoblekeygen as bandn
-import calibre_plugins.dedrm.erdr2pml as ereader
-import calibre_plugins.dedrm.adobekey as adobe
-import calibre_plugins.dedrm.kindlekey as amazon
-
-JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_')
-JSON_PATH = os.path.join(u"plugins", JSON_NAME + '.json')
-
-IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM"
-EREADERPLUGINNAME = "eReader PDB 2 PML"
-OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM"
-
-# This is where all preferences for this plugin will be stored
-# You should always prefix your config file name with plugins/,
-# so as to ensure you dont accidentally clobber a calibre config file
-dedrmprefs = JSONConfig(JSON_PATH)
-
-# get prefs from older tools
-kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM"))
-ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm"))
-
-# Set defaults for the prefs
-dedrmprefs.defaults['configured'] = False
-dedrmprefs.defaults['bandnkeys'] = {}
-dedrmprefs.defaults['adeptkeys'] = {}
-dedrmprefs.defaults['ereaderkeys'] = {}
-dedrmprefs.defaults['kindlekeys'] = {}
-dedrmprefs.defaults['pids'] = []
-dedrmprefs.defaults['serials'] = []
+from calibre_plugins.dedrm.utilities import uStrCmp
+import calibre_plugins.dedrm.prefs as prefs
class ConfigWidget(QWidget):
- def __init__(self, plugin_path):
+ def __init__(self, plugin_path, alfdir):
QWidget.__init__(self)
self.plugin_path = plugin_path
+ self.alfdir = alfdir
- # get copy of the prefs from the file
- # Otherwise we seem to get a persistent local copy.
- self.dedrmprefs = JSONConfig(JSON_PATH)
+ # get the prefs
+ self.dedrmprefs = prefs.DeDRM_Prefs()
+ # make a local copy
self.tempdedrmprefs = {}
self.tempdedrmprefs['bandnkeys'] = self.dedrmprefs['bandnkeys'].copy()
self.tempdedrmprefs['adeptkeys'] = self.dedrmprefs['adeptkeys'].copy()
@@ -77,6 +47,8 @@ class ConfigWidget(QWidget):
self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy()
self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids'])
self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials'])
+ self.tempdedrmprefs['adobewineprefix'] = self.dedrmprefs['adobewineprefix']
+ self.tempdedrmprefs['kindlewineprefix'] = self.dedrmprefs['kindlewineprefix']
# Start Qt Gui dialog layout
layout = QVBoxLayout(self)
@@ -133,27 +105,37 @@ class ConfigWidget(QWidget):
self.resize(self.sizeHint())
def kindle_serials(self):
- d = dialogs.ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], dialogs.AddSerialDialog)
+ d = ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
d.exec_()
def kindle_keys(self):
- d = dialogs.ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], dialogs.AddKindleDialog, 'k4i')
+ if isosx or iswindows:
+ d = ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i')
+ else:
+ # linux
+ d = ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i', self.tempdedrmprefs['kindlewineprefix'])
d.exec_()
+ self.tempdedrmprefs['kindlewineprefix'] = d.getwineprefix()
def adept_keys(self):
- d = dialogs.ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], dialogs.AddAdeptDialog, 'der')
+ if isosx or iswindows:
+ d = ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der')
+ else:
+ # linux
+ d = ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der', self.tempdedrmprefs['adobewineprefix'])
d.exec_()
+ self.tempdedrmprefs['adobewineprefix'] = d.getwineprefix()
def mobi_keys(self):
- d = dialogs.ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], dialogs.AddPIDDialog)
+ d = ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], AddPIDDialog)
d.exec_()
def bandn_keys(self):
- d = dialogs.ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], dialogs.AddBandNKeyDialog, 'b64')
+ d = ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], AddBandNKeyDialog, 'b64')
d.exec_()
def ereader_keys(self):
- d = dialogs.ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], dialogs.AddEReaderDialog, 'b63')
+ d = ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], AddEReaderDialog, 'b63')
d.exec_()
def help_link_activated(self, url):
@@ -168,13 +150,16 @@ class ConfigWidget(QWidget):
open_url(QUrl(url))
def save_settings(self):
- self.dedrmprefs['bandnkeys'] = self.tempdedrmprefs['bandnkeys']
- self.dedrmprefs['adeptkeys'] = self.tempdedrmprefs['adeptkeys']
- self.dedrmprefs['ereaderkeys'] = self.tempdedrmprefs['ereaderkeys']
- self.dedrmprefs['kindlekeys'] = self.tempdedrmprefs['kindlekeys']
- self.dedrmprefs['pids'] = self.tempdedrmprefs['pids']
- self.dedrmprefs['serials'] = self.tempdedrmprefs['serials']
- self.dedrmprefs['configured'] = True
+ self.dedrmprefs.set('bandnkeys', self.tempdedrmprefs['bandnkeys'])
+ self.dedrmprefs.set('adeptkeys', self.tempdedrmprefs['adeptkeys'])
+ self.dedrmprefs.set('ereaderkeys', self.tempdedrmprefs['ereaderkeys'])
+ self.dedrmprefs.set('kindlekeys', self.tempdedrmprefs['kindlekeys'])
+ self.dedrmprefs.set('pids', self.tempdedrmprefs['pids'])
+ self.dedrmprefs.set('serials', self.tempdedrmprefs['serials'])
+ self.dedrmprefs.set('adobewineprefix', self.tempdedrmprefs['adobewineprefix'])
+ self.dedrmprefs.set('kindlewineprefix', self.tempdedrmprefs['kindlewineprefix'])
+ self.dedrmprefs.set('configured', True)
+ self.dedrmprefs.writeprefs()
def load_resource(self, name):
with ZipFile(self.plugin_path, 'r') as zf:
@@ -182,283 +167,741 @@ class ConfigWidget(QWidget):
return zf.read(name)
return ""
-def writeprefs(value = True):
- dedrmprefs['configured'] = value
-
-def addnamedvaluetoprefs(prefkind, keyname, keyvalue):
- try:
- if keyvalue not in dedrmprefs[prefkind].values():
- # ensure that the keyname is unique
- # by adding a number (starting with 2) to the name if it is not
- namecount = 1
- newname = keyname
- while newname in dedrmprefs[prefkind]:
- namecount += 1
- newname = "{0:s}_{1:d}".format(keyname,namecount)
- # add to the preferences
- dedrmprefs[prefkind][newname] = keyvalue
- return (True, newname)
- except:
- pass
- return (False, keyname)
-
-def addvaluetoprefs(prefkind, prefsvalue):
- # ensure the keyvalue isn't already in the preferences
- if prefsvalue not in dedrmprefs[prefkind]:
- dedrmprefs[prefkind].append(prefsvalue)
- return True
- return False
-
-def convertprefs(always = False):
-
- def parseIgnobleString(keystuff):
- userkeys = {}
- ar = keystuff.split(':')
- for i, keystring in enumerate(ar):
- try:
- name, ccn = keystring.split(',')
- # Generate Barnes & Noble EPUB user key from name and credit card number.
- keyname = u"{0}_{1}_{2:d}".format(name.strip(),ccn.strip()[-4:],i+1)
- keyvalue = bandn.generate_key(name, ccn)
- if keyvalue not in userkeys.values():
- while keyname in dedrmprefs['bandnkeys']:
- keyname = keyname + keyname[-1]
- userkeys[keyname] = keyvalue
- except Exception, e:
- print e.args[0]
- pass
- return userkeys
-
- def parseeReaderString(keystuff):
- userkeys = {}
- ar = keystuff.split(':')
- for i, keystring in enumerate(ar):
- try:
- name, cc = keystring.split(',')
- # Generate eReader user key from name and credit card number.
- keyname = u"{0}_{1}_{2:d}".format(name.strip(),cc.strip()[-4:],i+1)
- keyvalue = ereader.getuser_key(name,cc).encode('hex')
- if keyvalue not in userkeys.values():
- while keyname in dedrmprefs['ereaderkeys']:
- keyname = keyname + keyname[-1]
- userkeys[keyname] = keyvalue
- except Exception, e:
- print e.args[0]
- pass
- return userkeys
-
- def parseKindleString(keystuff):
- pids = []
- serials = []
- ar = keystuff.split(',')
- for keystring in ar:
- keystring = str(keystring).strip().replace(" ","")
- if len(keystring) == 10 or len(keystring) == 8 and keystring not in pids:
- pids.append(keystring)
- elif len(keystring) == 16 and keystring[0] == 'B' and keystring not in serials:
- serials.append(keystring)
- return (pids,serials)
-
- def addConfigFiles(extension, prefskey, encoding = ''):
- # get any files with extension 'extension' in the config dir
- files = [f for f in os.listdir(config_dir) if f.endswith(extension)]
- try:
- priorkeycount = len(dedrmprefs[prefskey])
+
+
+class ManageKeysDialog(QDialog):
+ def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u"", wineprefix = None):
+ QDialog.__init__(self,parent)
+ self.parent = parent
+ self.key_type_name = key_type_name
+ self.plugin_keys = plugin_keys
+ self.create_key = create_key
+ self.keyfile_ext = keyfile_ext
+ self.import_key = (keyfile_ext != u"")
+ self.binary_file = (keyfile_ext == u".der")
+ self.json_file = (keyfile_ext == u".k4i")
+ self.wineprefix = wineprefix
+
+ self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
+
+ # Start Qt Gui dialog layout
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ help_layout = QHBoxLayout()
+ layout.addLayout(help_layout)
+ # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked.
+ help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self)
+ help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)
+ help_label.setAlignment(Qt.AlignRight)
+ help_label.linkActivated.connect(self.help_link_activated)
+ help_layout.addWidget(help_label)
+
+ keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
+ layout.addWidget(keys_group_box)
+ keys_group_box_layout = QHBoxLayout()
+ keys_group_box.setLayout(keys_group_box_layout)
+
+ self.listy = QListWidget(self)
+ self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
+ self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
+ self.populate_list()
+ keys_group_box_layout.addWidget(self.listy)
+
+ button_layout = QVBoxLayout()
+ keys_group_box_layout.addLayout(button_layout)
+ self._add_key_button = QtGui.QToolButton(self)
+ self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
+ self._add_key_button.setIcon(QIcon(I('plus.png')))
+ self._add_key_button.clicked.connect(self.add_key)
+ button_layout.addWidget(self._add_key_button)
+
+ self._delete_key_button = QtGui.QToolButton(self)
+ self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
+ 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)
+
+ if type(self.plugin_keys) == dict and self.import_key:
+ self._rename_key_button = QtGui.QToolButton(self)
+ self._rename_key_button.setToolTip(_(u"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(u"Save highlighted key to a .{0} file".format(self.keyfile_ext))
+ self.export_key_button.setIcon(QIcon(I('save.png')))
+ self.export_key_button.clicked.connect(self.export_key)
+ button_layout.addWidget(self.export_key_button)
+ spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
+ button_layout.addItem(spacerItem)
+
+ if self.wineprefix is not None:
+ layout.addSpacing(5)
+ wineprefix_layout = QHBoxLayout()
+ layout.addLayout(wineprefix_layout)
+ wineprefix_layout.setAlignment(Qt.AlignCenter)
+ self.wp_label = QLabel(u"WINEPREFIX:")
+ wineprefix_layout.addWidget(self.wp_label)
+ self.wp_lineedit = QLineEdit(self)
+ wineprefix_layout.addWidget(self.wp_lineedit)
+ self.wp_label.setBuddy(self.wp_lineedit)
+ self.wp_lineedit.setText(self.wineprefix)
+
+ layout.addSpacing(5)
+ migrate_layout = QHBoxLayout()
+ layout.addLayout(migrate_layout)
+ if self.import_key:
+ migrate_layout.setAlignment(Qt.AlignJustify)
+ self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self)
+ self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext))
+ self.migrate_btn.clicked.connect(self.migrate_wrapper)
+ migrate_layout.addWidget(self.migrate_btn)
+ migrate_layout.addStretch()
+ self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
+ self.button_box.rejected.connect(self.close)
+ migrate_layout.addWidget(self.button_box)
+
+ self.resize(self.sizeHint())
+
+ def getwineprefix(self):
+ if self.wineprefix is not None:
+ return unicode(self.wp_lineedit.text().toUtf8(), 'utf8').strip()
+ return u""
+
+ def populate_list(self):
+ if type(self.plugin_keys) == dict:
+ for key in self.plugin_keys.keys():
+ self.listy.addItem(QListWidgetItem(key))
+ else:
+ for key in self.plugin_keys:
+ self.listy.addItem(QListWidgetItem(key))
+
+ def add_key(self):
+ d = self.create_key(self)
+ d.exec_()
+
+ if d.result() != d.Accepted:
+ # New key generation cancelled.
+ return
+ new_key_value = d.key_value
+ if type(self.plugin_keys) == dict:
+ if new_key_value in self.plugin_keys.values():
+ old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
+ info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
+ u"The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added.".format(old_key_name,self.key_type_name), show=True)
+ return
+ self.plugin_keys[d.key_name] = new_key_value
+ else:
+ if new_key_value in self.plugin_keys:
+ info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
+ u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
+ return
+
+ self.plugin_keys.append(d.key_value)
+ self.listy.clear()
+ self.populate_list()
+
+ def rename_key(self):
+ if not self.listy.currentItem():
+ errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name)
+ r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(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, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?".format(keyname,d.key_name,self.key_type_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().toUtf8(), 'utf8')
+ if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
+ return
+ if type(self.plugin_keys) == dict:
+ del self.plugin_keys[keyname]
+ else:
+ self.plugin_keys.remove(keyname)
+
+ self.listy.clear()
+ self.populate_list()
+
+ def help_link_activated(self, url):
+ def get_help_file_resource():
+ # Copy the HTML helpfile to the plugin directory each time the
+ # link is clicked in case the helpfile is updated in newer plugins.
+ help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
+ file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name)
+ with open(file_path,'w') as f:
+ f.write(self.parent.load_resource(help_file_name))
+ return file_path
+ url = 'file:///' + get_help_file_resource()
+ open_url(QUrl(url))
+
+ def migrate_files(self):
+ dynamic[PLUGIN_NAME + u"config_dir"] = config_dir
+ files = choose_files(self, PLUGIN_NAME + u"config_dir",
+ u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False)
+ counter = 0
+ skipped = 0
+ if files:
for filename in files:
fpath = os.path.join(config_dir, filename)
- key = os.path.splitext(filename)[0]
- value = open(fpath, 'rb').read()
- if encoding is not '':
- value = value.encode(encoding)
- if value not in dedrmprefs[prefskey].values():
- while key in dedrmprefs[prefskey]:
- key = key+key[-1]
- dedrmprefs[prefskey][key] = value
- #os.remove(fpath)
- return len(dedrmprefs[prefskey])-priorkeycount
- except IOError:
- return -1
-
- if (not always) and dedrmprefs['configured']:
- # We've already converted old preferences,
- # and we're not being forced to do it again, so just return
- return
-
- # initialise
- # we must actually set the prefs that are dictionaries and lists
- # to empty dictionaries and lists, otherwise we are unable to add to them
- # as then it just adds to the (memory only) dedrmprefs.defaults versions!
- if dedrmprefs['bandnkeys'] == {}:
- dedrmprefs['bandnkeys'] = {}
- if dedrmprefs['adeptkeys'] == {}:
- dedrmprefs['adeptkeys'] = {}
- if dedrmprefs['ereaderkeys'] == {}:
- dedrmprefs['ereaderkeys'] = {}
- if dedrmprefs['kindlekeys'] == {}:
- dedrmprefs['kindlekeys'] = {}
- if dedrmprefs['pids'] == []:
- dedrmprefs['pids'] = []
- if dedrmprefs['serials'] == []:
- dedrmprefs['serials'] = []
-
- # get default adobe adept key(s)
- priorkeycount = len(dedrmprefs['adeptkeys'])
- try:
- defaultkeys = adobe.adeptkeys()
- except:
- defaultkeys = []
- defaultcount = 1
- for keyvalue in defaultkeys:
- keyname = u"default_key_{0:d}".format(defaultcount)
- keyvaluehex = keyvalue.encode('hex')
- if keyvaluehex not in dedrmprefs['adeptkeys'].values():
- while keyname in dedrmprefs['adeptkeys']:
- defaultcount += 1
- keyname = u"default_key_{0:d}".format(defaultcount)
- dedrmprefs['adeptkeys'][keyname] = keyvaluehex
- addedkeycount = len(dedrmprefs['adeptkeys']) - priorkeycount
- if addedkeycount > 0:
- print u"{0} v{1}: {2:d} Default Adobe Adept {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
-
- # get default kindle key(s)
- priorkeycount = len(dedrmprefs['kindlekeys'])
- try:
- defaultkeys = amazon.kindlekeys()
- except:
- defaultkeys = []
- defaultcount = 1
- for keyvalue in defaultkeys:
- keyname = u"default_key_{0:d}".format(defaultcount)
- if keyvalue not in dedrmprefs['kindlekeys'].values():
- while keyname in dedrmprefs['kindlekeys']:
- defaultcount += 1
- keyname = u"default_key_{0:d}".format(defaultcount)
- dedrmprefs['kindlekeys'][keyname] = keyvalue
- addedkeycount = len(dedrmprefs['kindlekeys']) - priorkeycount
- if addedkeycount > 0:
- print u"{0} v{1}: {2:d} Default Kindle for Mac/PC {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- print u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION)
-
- # Handle the old ignoble plugin's customization string by converting the
- # old string to stored keys... get that personal data out of plain sight.
- from calibre.customize.ui import config
- sc = config['plugin_customization']
- val = sc.pop(IGNOBLEPLUGINNAME, None)
- if val is not None:
- print u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
- priorkeycount = len(dedrmprefs['bandnkeys'])
- userkeys = parseIgnobleString(str(val))
- for key in userkeys:
- value = userkeys[key]
- if value not in dedrmprefs['bandnkeys'].values():
- while key in dedrmprefs['bandnkeys']:
- key = key+key[-1]
- dedrmprefs['bandnkeys'][key] = value
- addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount
- print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # Handle the old eReader plugin's customization string by converting the
- # old string to stored keys... get that personal data out of plain sight.
- val = sc.pop(EREADERPLUGINNAME, None)
- if val is not None:
- print u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
- priorkeycount = len(dedrmprefs['ereaderkeys'])
- userkeys = parseeReaderString(str(val))
- for key in userkeys:
- value = userkeys[key]
- if value not in dedrmprefs['ereaderkeys'].values():
- while key in dedrmprefs['ereaderkeys']:
- key = key+key[-1]
- dedrmprefs['ereaderkeys'][key] = value
- addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount
- print u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # get old Kindle plugin configuration string
- val = sc.pop(OLDKINDLEPLUGINNAME, None)
- if val is not None:
- print u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
- priorpidcount = len(dedrmprefs['pids'])
- priorserialcount = len(dedrmprefs['serials'])
- pids, serials = parseKindleString(val)
- for pid in pids:
- if pid not in dedrmprefs['pids']:
- dedrmprefs['pids'].append(pid)
- for serial in serials:
- if serial not in dedrmprefs['serials']:
- dedrmprefs['serials'].append(serial)
- addedpidcount = len(dedrmprefs['pids']) - priorpidcount
- addedserialcount = len(dedrmprefs['serials']) - priorserialcount
- print u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # copy the customisations back into calibre preferences, as we've now removed the nasty plaintext
- config['plugin_customization'] = sc
-
- # get any .b64 files in the config dir
- ignoblecount = addConfigFiles('.b64', 'bandnkeys')
- if ignoblecount > 0:
- print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ignoblecount, u"key file" if ignoblecount==1 else u"key files")
- elif ignoblecount < 0:
- print u"{0} v{1}: Error reading Barnes & Noble keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION)
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # get any .der files in the config dir
- ineptcount = addConfigFiles('.der', 'adeptkeys','hex')
- if ineptcount > 0:
- print u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ineptcount, u"keyfile" if ineptcount==1 else u"keyfiles")
- elif ineptcount < 0:
- print u"{0} v{1}: Error reading Adobe Adept keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION)
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # get ignoble json prefs
- if 'keys' in ignobleprefs:
- priorkeycount = len(dedrmprefs['bandnkeys'])
- for key in ignobleprefs['keys']:
- value = ignobleprefs['keys'][key]
- if value not in dedrmprefs['bandnkeys'].values():
- while key in dedrmprefs['bandnkeys']:
- key = key+key[-1]
- dedrmprefs['bandnkeys'][key] = value
- addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount
- # no need to delete old prefs, since they contain no recoverable private data
- if addedkeycount > 0:
- print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
- # Make the json write all the prefs to disk
- writeprefs(False)
-
- # get kindle json prefs
- priorpidcount = len(dedrmprefs['pids'])
- priorserialcount = len(dedrmprefs['serials'])
- if 'pids' in kindleprefs:
- pids, serials = parseKindleString(kindleprefs['pids'])
- for pid in pids:
- if pid not in dedrmprefs['pids']:
- dedrmprefs['pids'].append(pid)
- if 'serials' in kindleprefs:
- pids, serials = parseKindleString(kindleprefs['serials'])
- for serial in serials:
- if serial not in dedrmprefs['serials']:
- dedrmprefs['serials'].append(serial)
- addedpidcount = len(dedrmprefs['pids']) - priorpidcount
- if addedpidcount > 0:
- print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs")
- addedserialcount = len(dedrmprefs['serials']) - priorserialcount
- if addedserialcount > 0:
- print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers")
-
- # Make the json write all the prefs to disk
- writeprefs()
- print u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION)
+ filename = os.path.basename(filename)
+ new_key_name = os.path.splitext(os.path.basename(filename))[0]
+ with open(fpath,'rb') as keyfile:
+ new_key_value = keyfile.read()
+ if self.binary_file:
+ new_key_value = new_key_value.encode('hex')
+ elif self.json_file:
+ new_key_value = json.loads(new_key_value)
+ match = False
+ for key in self.plugin_keys.keys():
+ if uStrCmp(new_key_name, key, True):
+ skipped += 1
+ msg = u"A key with the name <strong>{0}</strong> already exists!\nSkipping key file <strong>{1}</strong>.\nRename the existing key and import again".format(new_key_name,filename)
+ inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(msg), show_copy_button=False, show=True)
+ match = True
+ break
+ if not match:
+ if new_key_value in self.plugin_keys.values():
+ old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
+ skipped += 1
+ info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ u"The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True)
+ else:
+ counter += 1
+ self.plugin_keys[new_key_name] = new_key_value
+
+ msg = u""
+ if counter+skipped > 1:
+ if counter > 0:
+ msg += u"Imported <strong>{0:d}</strong> key {1}. ".format(counter, u"file" if counter == 1 else u"files")
+ if skipped > 0:
+ msg += u"Skipped <strong>{0:d}</strong> key {1}.".format(skipped, u"file" if counter == 1 else u"files")
+ inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(msg), show_copy_button=False, show=True)
+ return counter > 0
+
+ def migrate_wrapper(self):
+ if self.migrate_files():
+ self.listy.clear()
+ self.populate_list()
+
+ def export_key(self):
+ if not self.listy.currentItem():
+ errmsg = u"No keyfile selected to export. Highlight a keyfile first."
+ r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(errmsg), show=True, show_copy_button=False)
+ return
+ filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext))
+ 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'), u"{0}.{1}".format(keyname , self.keyfile_ext))
+ else:
+ defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext))
+ filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname,
+ u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter))
+ if filename:
+ dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
+ with file(filename, 'w') as fname:
+ if self.binary_file:
+ fname.write(self.plugin_keys[keyname].decode('hex'))
+ elif self.json_file:
+ fname.write(json.dumps(self.plugin_keys[keyname]))
+ else:
+ fname.write(self.plugin_keys[keyname])
+
+
+
+
+class RenameKeyDialog(QDialog):
+ def __init__(self, parent=None,):
+ print repr(self), repr(parent)
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name))
+ 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('New Key Name:', self))
+ self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
+ self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name))
+ 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)
+
+ self.resize(self.sizeHint())
+
+ def accept(self):
+ if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace():
+ errmsg = u"Key name field cannot be empty!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(errmsg), show=True, show_copy_button=False)
+ if len(self.key_ledit.text()) < 4:
+ errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(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 = u"The key name <strong>{0}</strong> is already being used.".format(self.key_ledit.text())
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
+ _(errmsg), show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+
+
+
+
+
+
+
+class AddBandNKeyDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
+ self.key_ledit = QLineEdit("", self)
+ self.key_ledit.setToolTip(_(u"<p>Enter an identifying name for this new key.</p>" +
+ u"<p>It should be something that will help you remember " +
+ u"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(u"Your Name:", self))
+ self.name_ledit = QLineEdit(u"", self)
+ self.name_ledit.setToolTip(_(u"<p>Enter your name as it appears in your B&N " +
+ u"account or on your credit card.</p>" +
+ u"<p>It will only be used to generate this " +
+ u"one-time key and won\'t be stored anywhere " +
+ u"in calibre or on your computer.</p>" +
+ u"<p>(ex: Jonathan Smith)"))
+ name_group.addWidget(self.name_ledit)
+ name_disclaimer_label = QLabel(_(u"(Will not be 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(u"Credit Card#:", self))
+ self.cc_ledit = QLineEdit(u"", self)
+ self.cc_ledit.setToolTip(_(u"<p>Enter the full credit card number on record " +
+ u"in your B&N account.</p>" +
+ u"<p>No spaces or dashes... just the numbers. " +
+ u"This number will only be used to generate this " +
+ u"one-time key and won\'t be stored anywhere in " +
+ u"calibre or on your computer."))
+ ccn_group.addWidget(self.cc_ledit)
+ ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self)
+ ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(ccn_disclaimer_label)
+ layout.addSpacing(10)
+
+ 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.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ from calibre_plugins.dedrm.ignoblekeygen import generate_key as generate_bandn_key
+ return generate_bandn_key(self.user_name,self.cc_number)
+
+ @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('-','')
+
+
+ def accept(self):
+ if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
+ errmsg = u"All fields are required!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if not self.cc_number.isdigit():
+ errmsg = u"Numbers only in the credit card number field!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) < 4:
+ errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+class AddEReaderDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
+ self.key_ledit = QLineEdit("", self)
+ self.key_ledit.setToolTip(u"<p>Enter an identifying name for this new key.\nIt 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(u"Your Name:", self))
+ self.name_ledit = QLineEdit(u"", self)
+ self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)")
+ name_group.addWidget(self.name_ledit)
+ name_disclaimer_label = QLabel(_(u"(Will not be 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(u"Credit Card#:", self))
+ self.cc_ledit = QLineEdit(u"", self)
+ self.cc_ledit.setToolTip(u"<p>Enter the last 8 digits of credit card number for this eReader key.\nThey 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 saved in configuration data)'), self)
+ ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(ccn_disclaimer_label)
+ layout.addSpacing(10)
+
+ 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.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key
+ return generate_ereader_key(self.user_name,self.cc_number).encode('hex')
+
+ @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('-','')
+
+
+ def accept(self):
+ if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
+ errmsg = u"All fields are required!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if not self.cc_number.isdigit():
+ errmsg = u"Numbers only in the credit card number field!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) < 4:
+ errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+
+class AddAdeptDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ try:
+ if iswindows or isosx:
+ from calibre_plugins.dedrm.adobekey import adeptkeys
+
+ defaultkeys = adeptkeys()
+ else: # linux
+ from wineutils import WineGetKeys
+
+ scriptpath = os.path.join(parent.parent.alfdir,u"adobekey.py")
+ defaultkeys = WineGetKeys(scriptpath, u".der",parent.getwineprefix())
+
+ self.default_key = defaultkeys[0]
+ except:
+ traceback.print_exc()
+ self.default_key = u""
+
+ self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+
+ if len(self.default_key)>0:
+ data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
+ self.key_ledit = QLineEdit(u"default_key", self)
+ self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Adobe Digital Editions key.")
+ key_group.addWidget(self.key_ledit)
+ key_label = QLabel(_(''), self)
+ key_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(key_label)
+ self.button_box.accepted.connect(self.accept)
+ else:
+ default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self)
+ default_key_error.setAlignment(Qt.AlignHCenter)
+ layout.addWidget(default_key_error)
+ # if no default, bot buttons do the same
+ self.button_box.accepted.connect(self.reject)
+
+ self.button_box.rejected.connect(self.reject)
+ layout.addWidget(self.button_box)
+
+ self.resize(self.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ return self.default_key.encode('hex')
+
+
+ def accept(self):
+ if len(self.key_name) == 0 or self.key_name.isspace():
+ errmsg = u"All fields are required!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) < 4:
+ errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+
+class AddKindleDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ try:
+ if iswindows or isosx:
+ from calibre_plugins.dedrm.kindlekey import kindlekeys
+
+ defaultkeys = kindlekeys()
+ else: # linux
+ from wineutils import WineGetKeys
+
+ scriptpath = os.path.join(parent.parent.alfdir,u"kindlekey.py")
+ defaultkeys = WineGetKeys(scriptpath, u".k4i",parent.getwineprefix())
+
+ self.default_key = defaultkeys[0]
+ except:
+ traceback.print_exc()
+ self.default_key = u""
+
+ self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+
+ if len(self.default_key)>0:
+ data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
+ self.key_ledit = QLineEdit(u"default_key", self)
+ self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Kindle for Mac/PC key.")
+ key_group.addWidget(self.key_ledit)
+ key_label = QLabel(_(''), self)
+ key_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(key_label)
+ self.button_box.accepted.connect(self.accept)
+ else:
+ default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self)
+ default_key_error.setAlignment(Qt.AlignHCenter)
+ layout.addWidget(default_key_error)
+ # if no default, bot buttons do the same
+ self.button_box.accepted.connect(self.reject)
+
+ self.button_box.rejected.connect(self.reject)
+ layout.addWidget(self.button_box)
+
+ self.resize(self.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ return self.default_key
+
+
+ def accept(self):
+ if len(self.key_name) == 0 or self.key_name.isspace():
+ errmsg = u"All fields are required!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) < 4:
+ errmsg = u"Key name must be at <i>least</i> 4 characters long!"
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+
+class AddSerialDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ data_group_box = QGroupBox(u"", 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(u"EInk Kindle Serial Number:", self))
+ self.key_ledit = QLineEdit("", self)
+ self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
+ key_group.addWidget(self.key_ledit)
+ key_label = QLabel(_(''), self)
+ key_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(key_label)
+
+ 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.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ def accept(self):
+ if len(self.key_name) == 0 or self.key_name.isspace():
+ errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) != 16:
+ errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name))
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+
+class AddPIDDialog(QDialog):
+ def __init__(self, parent=None,):
+ QDialog.__init__(self, parent)
+ self.parent = parent
+ self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
+ layout = QVBoxLayout(self)
+ self.setLayout(layout)
+
+ data_group_box = QGroupBox(u"", 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(u"PID:", self))
+ self.key_ledit = QLineEdit("", self)
+ self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
+ key_group.addWidget(self.key_ledit)
+ key_label = QLabel(_(''), self)
+ key_label.setAlignment(Qt.AlignHCenter)
+ data_group_box_layout.addWidget(key_label)
+
+ 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.sizeHint())
+
+ @property
+ def key_name(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ @property
+ def key_value(self):
+ return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
+
+ def accept(self):
+ if len(self.key_name) == 0 or self.key_name.isspace():
+ errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog."
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ if len(self.key_name) != 8 and len(self.key_name) != 10:
+ errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name))
+ return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
+ QDialog.accept(self)
+
+
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py
deleted file mode 100644
index 21c1dad..0000000
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py
+++ /dev/null
@@ -1,719 +0,0 @@
-#!/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'
-
-# Standard Python modules.
-import os, sys, re, hashlib
-import json
-
-from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QListWidget, QListWidgetItem, QAbstractItemView, QLineEdit, QPushButton, QIcon, QGroupBox, QDialog, QDialogButtonBox, QUrl, QString)
-from PyQt4 import QtGui
-
-# calibre modules and constants.
-from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url,
- choose_dir, choose_files)
-from calibre.utils.config import dynamic, config_dir, JSONConfig
-
-from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
-from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE, parseCustString)
-from calibre_plugins.dedrm.ignoblekeygen import generate_key as generate_bandn_key
-from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key
-from calibre_plugins.dedrm.adobekey import adeptkeys as retrieve_adept_keys
-from calibre_plugins.dedrm.kindlekey import kindlekeys as retrieve_kindle_keys
-
-class ManageKeysDialog(QDialog):
- def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""):
- QDialog.__init__(self,parent)
- self.parent = parent
- self.key_type_name = key_type_name
- self.plugin_keys = plugin_keys
- self.create_key = create_key
- self.keyfile_ext = keyfile_ext
- self.import_key = (keyfile_ext != u"")
- self.binary_file = (key_type_name == u"Adobe Digital Editions Key")
- self.json_file = (key_type_name == u"Kindle for Mac and PC Key")
-
- self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
-
- # Start Qt Gui dialog layout
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- help_layout = QHBoxLayout()
- layout.addLayout(help_layout)
- # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked.
- help_label = QLabel('<a href="http://www.foo.com/">Help</a>', self)
- help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)
- help_label.setAlignment(Qt.AlignRight)
- help_label.linkActivated.connect(self.help_link_activated)
- help_layout.addWidget(help_label)
-
- keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
- layout.addWidget(keys_group_box)
- keys_group_box_layout = QHBoxLayout()
- keys_group_box.setLayout(keys_group_box_layout)
-
- self.listy = QListWidget(self)
- self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
- self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
- self.populate_list()
- keys_group_box_layout.addWidget(self.listy)
-
- button_layout = QVBoxLayout()
- keys_group_box_layout.addLayout(button_layout)
- self._add_key_button = QtGui.QToolButton(self)
- self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
- self._add_key_button.setIcon(QIcon(I('plus.png')))
- self._add_key_button.clicked.connect(self.add_key)
- button_layout.addWidget(self._add_key_button)
-
- self._delete_key_button = QtGui.QToolButton(self)
- self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
- 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)
-
- if type(self.plugin_keys) == dict:
- self._rename_key_button = QtGui.QToolButton(self)
- self._rename_key_button.setToolTip(_(u"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(u"Save highlighted key to a .{0} file".format(self.keyfile_ext))
- self.export_key_button.setIcon(QIcon(I('save.png')))
- self.export_key_button.clicked.connect(self.export_key)
- button_layout.addWidget(self.export_key_button)
- spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
- button_layout.addItem(spacerItem)
-
- layout.addSpacing(5)
- migrate_layout = QHBoxLayout()
- layout.addLayout(migrate_layout)
- if self.import_key:
- migrate_layout.setAlignment(Qt.AlignJustify)
- self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self)
- self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext))
- self.migrate_btn.clicked.connect(self.migrate_wrapper)
- migrate_layout.addWidget(self.migrate_btn)
- migrate_layout.addStretch()
- self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
- self.button_box.rejected.connect(self.close)
- migrate_layout.addWidget(self.button_box)
-
- self.resize(self.sizeHint())
-
- def populate_list(self):
- if type(self.plugin_keys) == dict:
- for key in self.plugin_keys.keys():
- self.listy.addItem(QListWidgetItem(key))
- else:
- for key in self.plugin_keys:
- self.listy.addItem(QListWidgetItem(key))
-
- def add_key(self):
- d = self.create_key(self)
- d.exec_()
-
- if d.result() != d.Accepted:
- # New key generation cancelled.
- return
- new_key_value = d.key_value
- if type(self.plugin_keys) == dict:
- if new_key_value in self.plugin_keys.values():
- old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
- info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
- u"The new {1} is the same as the existing {1} named <strong>{0}</strong> and has not been added.".format(old_key_name,self.key_type_name), show=True)
- return
- self.plugin_keys[d.key_name] = new_key_value
- else:
- if new_key_value in self.plugin_keys:
- info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
- u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
- return
-
- self.plugin_keys.append(d.key_value)
- self.listy.clear()
- self.populate_list()
-
- def rename_key(self):
- if not self.listy.currentItem():
- errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name)
- r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(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, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?".format(keyname,d.key_name,self.key_type_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().toUtf8(), 'utf8')
- if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
- return
- if type(self.plugin_keys) == dict:
- del self.plugin_keys[keyname]
- else:
- self.plugin_keys.remove(keyname)
-
- self.listy.clear()
- self.populate_list()
-
- def help_link_activated(self, url):
- def get_help_file_resource():
- # Copy the HTML helpfile to the plugin directory each time the
- # link is clicked in case the helpfile is updated in newer plugins.
- help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
- file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name)
- with open(file_path,'w') as f:
- f.write(self.parent.load_resource(help_file_name))
- return file_path
- url = 'file:///' + get_help_file_resource()
- open_url(QUrl(url))
-
- def migrate_files(self):
- dynamic[PLUGIN_NAME + u"config_dir"] = config_dir
- files = choose_files(self, PLUGIN_NAME + u"config_dir",
- u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False)
- counter = 0
- skipped = 0
- if files:
- for filename in files:
- fpath = os.path.join(config_dir, filename)
- filename = os.path.basename(filename)
- new_key_name = os.path.splitext(os.path.basename(filename))[0]
- with open(fpath,'rb') as keyfile:
- new_key_value = keyfile.read()
- if self.binary_file:
- new_key_value = new_key_value.encode('hex')
- elif self.json_file:
- new_key_value = json.loads(new_key_value)
- match = False
- for key in self.plugin_keys.keys():
- if uStrCmp(new_key_name, key, True):
- skipped += 1
- msg = u"A key with the name <strong>{0}</strong> already exists!\nSkipping key file <strong>{1}</strong>.\nRename the existing key and import again".format(new_key_name,filename)
- inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(msg), show_copy_button=False, show=True)
- match = True
- break
- if not match:
- if new_key_value in self.plugin_keys.values():
- old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0]
- skipped += 1
- info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- u"The key in file {0} is the same as the existing key <strong>{1}</strong> and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True)
- else:
- counter += 1
- self.plugin_keys[new_key_name] = new_key_value
-
- msg = u""
- if counter+skipped > 1:
- if counter > 0:
- msg += u"Imported <strong>{0:d}</strong> key {1}. ".format(counter, u"file" if counter == 1 else u"files")
- if skipped > 0:
- msg += u"Skipped <strong>{0:d}</strong> key {1}.".format(skipped, u"file" if counter == 1 else u"files")
- inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(msg), show_copy_button=False, show=True)
- return counter > 0
-
- def migrate_wrapper(self):
- if self.migrate_files():
- self.listy.clear()
- self.populate_list()
-
- def export_key(self):
- if not self.listy.currentItem():
- errmsg = u"No keyfile selected to export. Highlight a keyfile first."
- r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(errmsg), show=True, show_copy_button=False)
- return
- filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext))
- 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'), u"{0}.{1}".format(keyname , self.keyfile_ext))
- else:
- defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext))
- filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname,
- u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter))
- if filename:
- dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0]
- with file(filename, 'w') as fname:
- if self.binary_file:
- fname.write(self.plugin_keys[keyname].decode('hex'))
- elif self.json_file:
- fname.write(json.dumps(self.plugin_keys[keyname]))
- else:
- fname.write(self.plugin_keys[keyname])
-
-
-
-
-class RenameKeyDialog(QDialog):
- def __init__(self, parent=None,):
- print repr(self), repr(parent)
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name))
- 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('New Key Name:', self))
- self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self)
- self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name))
- 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)
-
- self.resize(self.sizeHint())
-
- def accept(self):
- if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace():
- errmsg = u"Key name field cannot be empty!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(errmsg), show=True, show_copy_button=False)
- if len(self.key_ledit.text()) < 4:
- errmsg = u"Key name must be at <i>least</i> 4 characters long!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(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 = u"The key name <strong>{0}</strong> is already being used.".format(self.key_ledit.text())
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
- _(errmsg), show=True, show_copy_button=False)
- QDialog.accept(self)
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
-
-
-
-
-
-
-
-class AddBandNKeyDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(_(u"<p>Enter an identifying name for this new key.</p>" +
- u"<p>It should be something that will help you remember " +
- u"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(u"Your Name:", self))
- self.name_ledit = QLineEdit(u"", self)
- self.name_ledit.setToolTip(_(u"<p>Enter your name as it appears in your B&N " +
- u"account or on your credit card.</p>" +
- u"<p>It will only be used to generate this " +
- u"one-time key and won\'t be stored anywhere " +
- u"in calibre or on your computer.</p>" +
- u"<p>(ex: Jonathan Smith)"))
- name_group.addWidget(self.name_ledit)
- name_disclaimer_label = QLabel(_(u"(Will not be 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(u"Credit Card#:", self))
- self.cc_ledit = QLineEdit(u"", self)
- self.cc_ledit.setToolTip(_(u"<p>Enter the full credit card number on record " +
- u"in your B&N account.</p>" +
- u"<p>No spaces or dashes... just the numbers. " +
- u"This number will only be used to generate this " +
- u"one-time key and won\'t be stored anywhere in " +
- u"calibre or on your computer."))
- ccn_group.addWidget(self.cc_ledit)
- ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self)
- ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(ccn_disclaimer_label)
- layout.addSpacing(10)
-
- 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.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return generate_bandn_key(self.user_name,self.cc_number)
-
- @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('-','')
-
-
- def accept(self):
- if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
- errmsg = u"All fields are required!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if not self.cc_number.isdigit():
- errmsg = u"Numbers only in the credit card number field!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) < 4:
- errmsg = u"Key name must be at <i>least</i> 4 characters long!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-class AddEReaderDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(u"<p>Enter an identifying name for this new key.\nIt 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(u"Your Name:", self))
- self.name_ledit = QLineEdit(u"", self)
- self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)")
- name_group.addWidget(self.name_ledit)
- name_disclaimer_label = QLabel(_(u"(Will not be 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(u"Credit Card#:", self))
- self.cc_ledit = QLineEdit(u"", self)
- self.cc_ledit.setToolTip(u"<p>Enter the last 8 digits of credit card number for this eReader key.\nThey 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 saved in configuration data)'), self)
- ccn_disclaimer_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(ccn_disclaimer_label)
- layout.addSpacing(10)
-
- 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.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return generate_ereader_key(self.user_name,self.cc_number).encode('hex')
-
- @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('-','')
-
-
- def accept(self):
- if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace():
- errmsg = u"All fields are required!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if not self.cc_number.isdigit():
- errmsg = u"Numbers only in the credit card number field!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) < 4:
- errmsg = u"Key name must be at <i>least</i> 4 characters long!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-
-class AddAdeptDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- try:
- self.default_key = retrieve_adept_keys()[0]
- except:
- self.default_key = u""
-
- self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
-
- if len(self.default_key)>0:
- data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Adobe Digital Editions key.")
- key_group.addWidget(self.key_ledit)
- key_label = QLabel(_(''), self)
- key_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(key_label)
- self.button_box.accepted.connect(self.accept)
- else:
- default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self)
- default_key_error.setAlignment(Qt.AlignHCenter)
- layout.addWidget(default_key_error)
- # if no default, bot buttons do the same
- self.button_box.accepted.connect(self.reject)
-
- self.button_box.rejected.connect(self.reject)
- layout.addWidget(self.button_box)
-
- self.resize(self.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return self.default_key.encode('hex')
-
-
- def accept(self):
- if len(self.key_name) == 0 or self.key_name.isspace():
- errmsg = u"All fields are required!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) < 4:
- errmsg = u"Key name must be at <i>least</i> 4 characters long!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-
-class AddKindleDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- try:
- self.default_key = retrieve_kindle_keys()[0]
- except:
- self.default_key = u""
-
- self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
-
- if len(self.default_key)>0:
- data_group_box = QGroupBox(u"", 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(u"Unique Key Name:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(u"<p>Enter an identifying name for the current default Kindle for Mac/PC key.")
- key_group.addWidget(self.key_ledit)
- key_label = QLabel(_(''), self)
- key_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(key_label)
- self.button_box.accepted.connect(self.accept)
- else:
- default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self)
- default_key_error.setAlignment(Qt.AlignHCenter)
- layout.addWidget(default_key_error)
- # if no default, bot buttons do the same
- self.button_box.accepted.connect(self.reject)
-
- self.button_box.rejected.connect(self.reject)
- layout.addWidget(self.button_box)
-
- self.resize(self.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return self.default_key
-
-
- def accept(self):
- if len(self.key_name) == 0 or self.key_name.isspace():
- errmsg = u"All fields are required!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) < 4:
- errmsg = u"Key name must be at <i>least</i> 4 characters long!"
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-
-class AddSerialDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- data_group_box = QGroupBox(u"", 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(u"EInk Kindle Serial Number:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
- key_group.addWidget(self.key_ledit)
- key_label = QLabel(_(''), self)
- key_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(key_label)
-
- 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.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- def accept(self):
- if len(self.key_name) == 0 or self.key_name.isspace():
- errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) != 16:
- errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name))
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-
-class AddPIDDialog(QDialog):
- def __init__(self, parent=None,):
- QDialog.__init__(self, parent)
- self.parent = parent
- self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
- layout = QVBoxLayout(self)
- self.setLayout(layout)
-
- data_group_box = QGroupBox(u"", 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(u"PID:", self))
- self.key_ledit = QLineEdit("", self)
- self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
- key_group.addWidget(self.key_ledit)
- key_label = QLabel(_(''), self)
- key_label.setAlignment(Qt.AlignHCenter)
- data_group_box_layout.addWidget(key_label)
-
- 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.sizeHint())
-
- @property
- def key_name(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- @property
- def key_value(self):
- return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip()
-
- def accept(self):
- if len(self.key_name) == 0 or self.key_name.isspace():
- errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog."
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- if len(self.key_name) != 8 and len(self.key_name) != 10:
- errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name))
- return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- QDialog.accept(self)
-
-
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py
index 277cdde..ac73d1e 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py
@@ -34,13 +34,14 @@ from __future__ import with_statement
# 3.7 - Tweaked to match ineptepub more closely
# 3.8 - Fixed to retain zip file metadata (e.g. file modification date)
# 3.9 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 4.0 - Work if TkInter is missing
"""
Decrypt Barnes & Noble encrypted ePub books.
"""
__license__ = 'GPL v3'
-__version__ = "3.9"
+__version__ = "4.0"
import sys
import os
@@ -318,6 +319,8 @@ def decryptBook(keyb64, inpath, outpath):
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
if len(argv) != 4:
@@ -331,10 +334,13 @@ def cli_main():
return result
def gui_main():
- import Tkinter
- import Tkconstants
- import tkFileDialog
- import traceback
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class DecryptionDialog(Tkinter.Frame):
def __init__(self, root):
@@ -442,7 +448,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py
index a6e5dca..5118c87 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py
@@ -32,13 +32,14 @@ from __future__ import with_statement
# 2.4 - Improvements to UI and now works in plugins
# 2.5 - Additional improvement for unicode and plugin support
# 2.6 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 2.7 - Work if TkInter is missing
"""
Generate Barnes & Noble EPUB user key from name and credit card number.
"""
__license__ = 'GPL v3'
-__version__ = "2.6"
+__version__ = "2.7"
import sys
import os
@@ -216,6 +217,8 @@ def generate_key(name, ccn):
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
if AES is None:
@@ -233,10 +236,13 @@ def cli_main():
def gui_main():
- import Tkinter
- import Tkconstants
- import tkFileDialog
- import tkMessageBox
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class DecryptionDialog(Tkinter.Frame):
def __init__(self, root):
@@ -320,7 +326,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py
index 3fe07d9..225ffa7 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py
@@ -35,14 +35,15 @@ from __future__ import with_statement
# 5.7 - Fix for potential problem with PyCrypto
# 5.8 - Revised to allow use in calibre plugins to eliminate need for duplicate code
# 5.9 - Fixed to retain zip file metadata (e.g. file modification date)
-# 5.10 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 6.0 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 6.1 - Work if TkInter is missing
"""
Decrypt Adobe Digital Editions encrypted ePub books.
"""
__license__ = 'GPL v3'
-__version__ = "5.10"
+__version__ = "6.1"
import sys
import os
@@ -460,6 +461,8 @@ def decryptBook(userkey, inpath, outpath):
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
if len(argv) != 4:
@@ -473,10 +476,13 @@ def cli_main():
return result
def gui_main():
- import Tkinter
- import Tkconstants
- import tkFileDialog
- import traceback
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class DecryptionDialog(Tkinter.Frame):
def __init__(self, root):
@@ -584,7 +590,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py
index 69028c6..797db60 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py
@@ -51,13 +51,14 @@ from __future__ import with_statement
# 7.12 - Revised to allow use in calibre plugins to eliminate need for duplicate code
# 7.13 - Fixed erroneous mentions of ineptepub
# 7.14 - moved unicode_argv call inside main for Windows DeDRM compatibility
+# 8.0 - Work if TkInter is missing
"""
Decrypts Adobe ADEPT-encrypted PDF files.
"""
__license__ = 'GPL v3'
-__version__ = "7.14"
+__version__ = "8.0"
import sys
import os
@@ -2187,6 +2188,8 @@ def decryptBook(userkey, inpath, outpath):
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
if len(argv) != 4:
@@ -2201,10 +2204,13 @@ def cli_main():
def gui_main():
- import Tkinter
- import Tkconstants
- import tkFileDialog
- import tkMessageBox
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class DecryptionDialog(Tkinter.Frame):
def __init__(self, root):
@@ -2321,7 +2327,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
index 453de14..c84c458 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
@@ -17,6 +17,7 @@ from __future__ import with_statement
# 1.4 - Remove dependency on alfcrypto
# 1.5 - moved unicode_argv call inside main for Windows DeDRM compatibility
# 1.6 - Fixed a problem getting the disk serial numbers
+# 1.7 - Work if TkInter is missing
"""
@@ -24,7 +25,7 @@ Retrieve Kindle for PC/Mac user key.
"""
__license__ = 'GPL v3'
-__version__ = '1.6'
+__version__ = '1.7'
import sys, os, re
from struct import pack, unpack, unpack_from
@@ -1804,6 +1805,8 @@ def usage(progname):
def cli_main():
+ sys.stdout=SafeUnbuffered(sys.stdout)
+ sys.stderr=SafeUnbuffered(sys.stderr)
argv=unicode_argv()
progname = os.path.basename(argv[0])
print u"{0} v{1}\nCopyright © 2010-2013 some_updates and Apprentice Alf".format(progname,__version__)
@@ -1845,10 +1848,13 @@ def cli_main():
def gui_main():
- import Tkinter
- import Tkconstants
- import tkMessageBox
- import traceback
+ try:
+ import Tkinter
+ import Tkconstants
+ import tkMessageBox
+ import traceback
+ except:
+ return cli_main()
class ExceptionDialog(Tkinter.Frame):
def __init__(self, root, text):
@@ -1895,7 +1901,5 @@ def gui_main():
if __name__ == '__main__':
if len(sys.argv) > 1:
- sys.stdout=SafeUnbuffered(sys.stdout)
- sys.stderr=SafeUnbuffered(sys.stderr)
sys.exit(cli_main())
sys.exit(gui_main())
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py
new file mode 100644
index 0000000..2c8c665
--- /dev/null
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/prefs.py
@@ -0,0 +1,293 @@
+#!/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'
+
+# Standard Python modules.
+import os, sys, re, hashlib
+import json
+import traceback
+
+from calibre.utils.config import dynamic, config_dir, JSONConfig
+from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
+from calibre.constants import iswindows, isosx
+
+class DeDRM_Prefs():
+ def __init__(self):
+ JSON_PATH = os.path.join(u"plugins", PLUGIN_NAME.strip().lower().replace(' ', '_') + '.json')
+ self.dedrmprefs = JSONConfig(JSON_PATH)
+
+ self.dedrmprefs.defaults['configured'] = False
+ self.dedrmprefs.defaults['bandnkeys'] = {}
+ self.dedrmprefs.defaults['adeptkeys'] = {}
+ self.dedrmprefs.defaults['ereaderkeys'] = {}
+ self.dedrmprefs.defaults['kindlekeys'] = {}
+ self.dedrmprefs.defaults['pids'] = []
+ self.dedrmprefs.defaults['serials'] = []
+ self.dedrmprefs.defaults['adobewineprefix'] = ""
+ self.dedrmprefs.defaults['kindlewineprefix'] = ""
+
+ # initialise
+ # we must actually set the prefs that are dictionaries and lists
+ # to empty dictionaries and lists, otherwise we are unable to add to them
+ # as then it just adds to the (memory only) dedrmprefs.defaults versions!
+ if self.dedrmprefs['bandnkeys'] == {}:
+ self.dedrmprefs['bandnkeys'] = {}
+ if self.dedrmprefs['adeptkeys'] == {}:
+ self.dedrmprefs['adeptkeys'] = {}
+ if self.dedrmprefs['ereaderkeys'] == {}:
+ self.dedrmprefs['ereaderkeys'] = {}
+ if self.dedrmprefs['kindlekeys'] == {}:
+ self.dedrmprefs['kindlekeys'] = {}
+ if self.dedrmprefs['pids'] == []:
+ self.dedrmprefs['pids'] = []
+ if self.dedrmprefs['serials'] == []:
+ self.dedrmprefs['serials'] = []
+
+ def __getitem__(self,kind = None):
+ if kind is not None:
+ return self.dedrmprefs[kind]
+ return self.dedrmprefs
+
+ def set(self, kind, value):
+ self.dedrmprefs[kind] = value
+
+ def writeprefs(self,value = True):
+ self.dedrmprefs['configured'] = value
+
+ def addnamedvaluetoprefs(self, prefkind, keyname, keyvalue):
+ try:
+ if keyvalue not in self.dedrmprefs[prefkind].values():
+ # ensure that the keyname is unique
+ # by adding a number (starting with 2) to the name if it is not
+ namecount = 1
+ newname = keyname
+ while newname in self.dedrmprefs[prefkind]:
+ namecount += 1
+ newname = "{0:s}_{1:d}".format(keyname,namecount)
+ # add to the preferences
+ self.dedrmprefs[prefkind][newname] = keyvalue
+ return (True, newname)
+ except:
+ traceback.print_exc()
+ pass
+ return (False, keyname)
+
+ def addvaluetoprefs(self, prefkind, prefsvalue):
+ # ensure the keyvalue isn't already in the preferences
+ try:
+ if prefsvalue not in self.dedrmprefs[prefkind]:
+ self.dedrmprefs[prefkind].append(prefsvalue)
+ return True
+ except:
+ traceback.print_exc()
+ return False
+
+
+def convertprefs(always = False):
+
+ def parseIgnobleString(keystuff):
+ from calibre_plugins.dedrm.ignoblekeygen import generate_key
+ userkeys = []
+ ar = keystuff.split(':')
+ for keystring in ar:
+ try:
+ name, ccn = keystring.split(',')
+ # Generate Barnes & Noble EPUB user key from name and credit card number.
+ keyname = u"{0}_{1}".format(name.strip(),ccn.strip()[-4:])
+ keyvalue = generate_key(name, ccn)
+ userkeys.append([keyname,keyvalue])
+ except Exception, e:
+ traceback.print_exc()
+ print e.args[0]
+ pass
+ return userkeys
+
+ def parseeReaderString(keystuff):
+ from calibre_plugins.dedrm.erdr2pml import getuser_key
+ userkeys = []
+ ar = keystuff.split(':')
+ for keystring in ar:
+ try:
+ name, cc = keystring.split(',')
+ # Generate eReader user key from name and credit card number.
+ keyname = u"{0}_{1}".format(name.strip(),cc.strip()[-4:])
+ keyvalue = getuser_key(name,cc).encode('hex')
+ userkeysappend([keyname,keyvalue])
+ except Exception, e:
+ traceback.print_exc()
+ print e.args[0]
+ pass
+ return userkeys
+
+ def parseKindleString(keystuff):
+ pids = []
+ serials = []
+ ar = keystuff.split(',')
+ for keystring in ar:
+ keystring = str(keystring).strip().replace(" ","")
+ if len(keystring) == 10 or len(keystring) == 8 and keystring not in pids:
+ pids.append(keystring)
+ elif len(keystring) == 16 and keystring[0] == 'B' and keystring not in serials:
+ serials.append(keystring)
+ return (pids,serials)
+
+ def getConfigFiles(extension, encoding = None):
+ # get any files with extension 'extension' in the config dir
+ userkeys = []
+ files = [f for f in os.listdir(config_dir) if f.endswith(extension)]
+ for filename in files:
+ try:
+ fpath = os.path.join(config_dir, filename)
+ key = os.path.splitext(filename)[0]
+ value = open(fpath, 'rb').read()
+ if encoding is not None:
+ value = value.encode(encoding)
+ userkeys.append([key,value])
+ except:
+ traceback.print_exc()
+ pass
+ return userkeys
+
+ dedrmprefs = DeDRM_Prefs()
+
+ if (not always) and dedrmprefs['configured']:
+ # We've already converted old preferences,
+ # and we're not being forced to do it again, so just return
+ return
+
+
+ print u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION)
+
+ IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM"
+ EREADERPLUGINNAME = "eReader PDB 2 PML"
+ OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM"
+
+ # get prefs from older tools
+ kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM"))
+ ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm"))
+
+ # Handle the old ignoble plugin's customization string by converting the
+ # old string to stored keys... get that personal data out of plain sight.
+ from calibre.customize.ui import config
+ sc = config['plugin_customization']
+ val = sc.pop(IGNOBLEPLUGINNAME, None)
+ if val is not None:
+ print u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
+ priorkeycount = len(dedrmprefs['bandnkeys'])
+ userkeys = parseIgnobleString(str(val))
+ for keypair in userkeys:
+ name = keypair[0]
+ value = keypair[1]
+ dedrmprefs.addnamedvaluetoprefs('bandnkeys', name, value)
+ addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount
+ print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # Handle the old eReader plugin's customization string by converting the
+ # old string to stored keys... get that personal data out of plain sight.
+ val = sc.pop(EREADERPLUGINNAME, None)
+ if val is not None:
+ print u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
+ priorkeycount = len(dedrmprefs['ereaderkeys'])
+ userkeys = parseeReaderString(str(val))
+ for keypair in userkeys:
+ name = keypair[0]
+ value = keypair[1]
+ dedrmprefs.addnamedvaluetoprefs('ereaderkeys', name, value)
+ addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount
+ print u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # get old Kindle plugin configuration string
+ val = sc.pop(OLDKINDLEPLUGINNAME, None)
+ if val is not None:
+ print u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION)
+ priorpidcount = len(dedrmprefs['pids'])
+ priorserialcount = len(dedrmprefs['serials'])
+ pids, serials = parseKindleString(val)
+ for pid in pids:
+ dedrmprefs.addvaluetoprefs('pids',pid)
+ for serial in serials:
+ dedrmprefs.addvaluetoprefs('serials',serial)
+ addedpidcount = len(dedrmprefs['pids']) - priorpidcount
+ addedserialcount = len(dedrmprefs['serials']) - priorserialcount
+ print u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # copy the customisations back into calibre preferences, as we've now removed the nasty plaintext
+ config['plugin_customization'] = sc
+
+ # get any .b64 files in the config dir
+ priorkeycount = len(dedrmprefs['bandnkeys'])
+ bandnfilekeys = getConfigFiles('.b64')
+ for keypair in bandnfilekeys:
+ name = keypair[0]
+ value = keypair[1]
+ dedrmprefs.addnamedvaluetoprefs('bandnkeys', name, value)
+ addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount
+ if addedkeycount > 0:
+ print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ignoblecount, u"key file" if ignoblecount==1 else u"key files")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # get any .der files in the config dir
+ priorkeycount = len(dedrmprefs['adeptkeys'])
+ adeptfilekeys = getConfigFiles('.der','hex')
+ ineptcount = addConfigFiles('.der', 'adeptkeys')
+ for keypair in adeptfilekeys:
+ name = keypair[0]
+ value = keypair[1]
+ dedrmprefs.addnamedvaluetoprefs('adeptkeys', name, value)
+ addedkeycount = len(dedrmprefs['adeptkeys'])-priorkeycount
+ if addedkeycount > 0:
+ print u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ineptcount, u"keyfile" if ineptcount==1 else u"keyfiles")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # get ignoble json prefs
+ if 'keys' in ignobleprefs:
+ priorkeycount = len(dedrmprefs['bandnkeys'])
+ for name in ignobleprefs['keys']:
+ value = ignobleprefs['keys'][name]
+ dedrmprefs.addnamedvaluetoprefs('bandnkeys', name, value)
+ addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount
+ # no need to delete old prefs, since they contain no recoverable private data
+ if addedkeycount > 0:
+ print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys")
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs(False)
+
+ # get kindle json prefs
+ priorpidcount = len(dedrmprefs['pids'])
+ priorserialcount = len(dedrmprefs['serials'])
+ if 'pids' in kindleprefs:
+ pids, serials = parseKindleString(kindleprefs['pids'])
+ for pid in pids:
+ dedrmprefs.addvaluetoprefs('pids',pid)
+ if 'serials' in kindleprefs:
+ pids, serials = parseKindleString(kindleprefs['serials'])
+ for serial in serials:
+ dedrmprefs.addvaluetoprefs('serials',serial)
+ addedpidcount = len(dedrmprefs['pids']) - priorpidcount
+ if addedpidcount > 0:
+ print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs")
+ addedserialcount = len(dedrmprefs['serials']) - priorserialcount
+ if addedserialcount > 0:
+ print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers")
+ try:
+ if kindleprefs['wineprefix'] != "":
+ dedrmprefs.set('adobewineprefix',kindleprefs['wineprefix'])
+ dedrmprefs.set('kindlewineprefix',kindleprefs['wineprefix'])
+ print u"{0} v{1}: WINEPREFIX ‘(2)’ imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, kindleprefs['wineprefix'])
+ except:
+ traceback.print_exc()
+
+
+ # Make the json write all the prefs to disk
+ dedrmprefs.writeprefs()
+ print u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION)
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/wineutils.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/wineutils.py
new file mode 100644
index 0000000..f8d5f7a
--- /dev/null
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/wineutils.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import with_statement
+
+__license__ = 'GPL v3'
+
+# Standard Python modules.
+import os, sys, re, hashlib
+from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
+
+def WineGetKeys(scriptpath, extension, wineprefix=""):
+ import subprocess
+ from subprocess import Popen, PIPE, STDOUT
+
+ import subasyncio
+ from subasyncio import Process
+
+ if extension == u".k4i":
+ import json
+
+ basepath, script = os.path.split(scriptpath)
+ print u"{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script)
+
+ outdirpath = os.path.join(basepath, u"winekeysdir")
+ if not os.path.exists(outdirpath):
+ os.mkdir(outdirpath)
+
+ if wineprefix != "" and os.path.exists(wineprefix):
+ cmdline = u"WINEPREFIX=\"{2}\" wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix)
+ else:
+ cmdline = u"wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath)
+ print u"{0} v{1}: Command line: “{2}”".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline)
+
+ try:
+ cmdline = cmdline.encode(sys.getfilesystemencoding())
+ p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False)
+ result = p2.wait("wait")
+ except Exception, e:
+ print u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0])
+ return []
+
+ winekeys = []
+ # get any files with extension in the output dir
+ files = [f for f in os.listdir(outdirpath) if f.endswith(extension)]
+ for filename in files:
+ try:
+ fpath = os.path.join(outdirpath, filename)
+ with open(fpath, 'rb') as keyfile:
+ if extension == u".k4i":
+ new_key_value = json.loads(keyfile.read())
+ else:
+ new_key_value = keyfile.read()
+ winekeys.append(new_key_value)
+ except:
+ print u"{0} v{1}: Error loading file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename)
+ traceback.print_exc()
+ os.remove(fpath)
+ print u"{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), u"key file" if len(winekeys) == 1 else u"key files")
+ return winekeys