2020-09-27 10:54:49 +00:00
#!/usr/bin/env python3
2013-03-20 10:23:54 +00:00
# -*- coding: utf-8 -*-
__license__ = ' GPL v3 '
2020-09-27 10:54:49 +00:00
# Python 3, September 2020
2020-09-26 20:22:47 +00:00
2013-03-20 10:23:54 +00:00
# Standard Python modules.
2020-11-22 15:03:45 +00:00
import os , traceback , json , codecs
2013-03-20 10:23:54 +00:00
2020-09-27 10:54:49 +00:00
from PyQt5 . Qt import ( Qt , QWidget , QHBoxLayout , QVBoxLayout , QLabel , QLineEdit ,
2021-11-15 16:59:48 +00:00
QGroupBox , QPushButton , QListWidget , QListWidgetItem , QCheckBox ,
2021-11-15 13:30:32 +00:00
QAbstractItemView , QIcon , QDialog , QDialogButtonBox , QUrl ,
QCheckBox )
2020-09-26 20:22:47 +00:00
2020-09-27 10:54:49 +00:00
from PyQt5 import Qt as QtGui
2013-03-20 10:23:54 +00:00
from zipfile import ZipFile
# calibre modules and constants.
from calibre . gui2 import ( error_dialog , question_dialog , info_dialog , open_url ,
2015-03-07 21:18:50 +00:00
choose_dir , choose_files , choose_save_file )
2013-03-20 10:23:54 +00:00
from calibre . utils . config import dynamic , config_dir , JSONConfig
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
2013-04-05 16:44:48 +00:00
from calibre_plugins . dedrm . utilities import uStrCmp
2013-03-20 10:23:54 +00:00
2013-04-05 16:44:48 +00:00
import calibre_plugins . dedrm . prefs as prefs
2015-07-29 17:11:19 +00:00
import calibre_plugins . dedrm . androidkindlekey as androidkindlekey
2013-03-20 10:23:54 +00:00
class ConfigWidget ( QWidget ) :
2013-04-05 16:44:48 +00:00
def __init__ ( self , plugin_path , alfdir ) :
2013-03-20 10:23:54 +00:00
QWidget . __init__ ( self )
self . plugin_path = plugin_path
2013-04-05 16:44:48 +00:00
self . alfdir = alfdir
2013-03-20 10:23:54 +00:00
2013-04-05 16:44:48 +00:00
# get the prefs
self . dedrmprefs = prefs . DeDRM_Prefs ( )
2013-03-20 10:23:54 +00:00
2013-04-05 16:44:48 +00:00
# make a local copy
2013-03-20 10:23:54 +00:00
self . tempdedrmprefs = { }
self . tempdedrmprefs [ ' bandnkeys ' ] = self . dedrmprefs [ ' bandnkeys ' ] . copy ( )
self . tempdedrmprefs [ ' adeptkeys ' ] = self . dedrmprefs [ ' adeptkeys ' ] . copy ( )
self . tempdedrmprefs [ ' ereaderkeys ' ] = self . dedrmprefs [ ' ereaderkeys ' ] . copy ( )
self . tempdedrmprefs [ ' kindlekeys ' ] = self . dedrmprefs [ ' kindlekeys ' ] . copy ( )
2015-07-29 17:11:19 +00:00
self . tempdedrmprefs [ ' androidkeys ' ] = self . dedrmprefs [ ' androidkeys ' ] . copy ( )
2013-03-20 10:23:54 +00:00
self . tempdedrmprefs [ ' pids ' ] = list ( self . dedrmprefs [ ' pids ' ] )
self . tempdedrmprefs [ ' serials ' ] = list ( self . dedrmprefs [ ' serials ' ] )
2013-04-05 16:44:48 +00:00
self . tempdedrmprefs [ ' adobewineprefix ' ] = self . dedrmprefs [ ' adobewineprefix ' ]
self . tempdedrmprefs [ ' kindlewineprefix ' ] = self . dedrmprefs [ ' kindlewineprefix ' ]
2021-11-15 16:59:48 +00:00
self . tempdedrmprefs [ ' deobfuscate_fonts ' ] = self . dedrmprefs [ ' deobfuscate_fonts ' ]
2013-03-20 10:23:54 +00:00
# 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/ " >Plugin 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 ( _ ( ' Configuration: ' ) , self )
layout . addWidget ( keys_group_box )
keys_group_box_layout = QHBoxLayout ( )
keys_group_box . setLayout ( keys_group_box_layout )
button_layout = QVBoxLayout ( )
keys_group_box_layout . addLayout ( button_layout )
self . bandn_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . bandn_button . setToolTip ( _ ( " Click to manage keys for Barnes and Noble ebooks " ) )
self . bandn_button . setText ( " Barnes and Noble ebooks " )
2013-03-20 10:23:54 +00:00
self . bandn_button . clicked . connect ( self . bandn_keys )
2015-03-17 17:49:30 +00:00
self . kindle_android_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . kindle_android_button . setToolTip ( _ ( " Click to manage keys for Kindle for Android ebooks " ) )
self . kindle_android_button . setText ( " Kindle for Android ebooks " )
2015-07-29 17:11:19 +00:00
self . kindle_android_button . clicked . connect ( self . kindle_android )
2013-03-20 10:23:54 +00:00
self . kindle_serial_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . kindle_serial_button . setToolTip ( _ ( " Click to manage eInk Kindle serial numbers for Kindle ebooks " ) )
self . kindle_serial_button . setText ( " eInk Kindle ebooks " )
2013-03-20 10:23:54 +00:00
self . kindle_serial_button . clicked . connect ( self . kindle_serials )
self . kindle_key_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . kindle_key_button . setToolTip ( _ ( " Click to manage keys for Kindle for Mac/PC ebooks " ) )
self . kindle_key_button . setText ( " Kindle for Mac/PC ebooks " )
2013-03-20 10:23:54 +00:00
self . kindle_key_button . clicked . connect ( self . kindle_keys )
self . adept_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . adept_button . setToolTip ( _ ( " Click to manage keys for Adobe Digital Editions ebooks " ) )
self . adept_button . setText ( " Adobe Digital Editions ebooks " )
2013-03-20 10:23:54 +00:00
self . adept_button . clicked . connect ( self . adept_keys )
self . mobi_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . mobi_button . setToolTip ( _ ( " Click to manage PIDs for Mobipocket ebooks " ) )
self . mobi_button . setText ( " Mobipocket ebooks " )
2013-03-20 10:23:54 +00:00
self . mobi_button . clicked . connect ( self . mobi_keys )
self . ereader_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . ereader_button . setToolTip ( _ ( " Click to manage keys for eReader ebooks " ) )
self . ereader_button . setText ( " eReader ebooks " )
2013-03-20 10:23:54 +00:00
self . ereader_button . clicked . connect ( self . ereader_keys )
button_layout . addWidget ( self . kindle_serial_button )
2015-03-17 17:49:30 +00:00
button_layout . addWidget ( self . kindle_android_button )
2013-03-20 10:23:54 +00:00
button_layout . addWidget ( self . bandn_button )
button_layout . addWidget ( self . mobi_button )
button_layout . addWidget ( self . ereader_button )
button_layout . addWidget ( self . adept_button )
button_layout . addWidget ( self . kindle_key_button )
2021-11-15 16:59:48 +00:00
self . chkFontObfuscation = QtGui . QCheckBox ( _ ( " Deobfuscate EPUB fonts " ) )
self . chkFontObfuscation . setToolTip ( " Deobfuscates fonts in EPUB files after DRM removal " )
self . chkFontObfuscation . setChecked ( self . tempdedrmprefs [ " deobfuscate_fonts " ] )
button_layout . addWidget ( self . chkFontObfuscation )
2013-03-20 10:23:54 +00:00
self . resize ( self . sizeHint ( ) )
def kindle_serials ( self ) :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " EInk Kindle Serial Number " , self . tempdedrmprefs [ ' serials ' ] , AddSerialDialog )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
2020-09-26 20:22:47 +00:00
2015-07-29 17:11:19 +00:00
def kindle_android ( self ) :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Kindle for Android Key " , self . tempdedrmprefs [ ' androidkeys ' ] , AddAndroidDialog , ' k4a ' )
2015-03-17 17:49:30 +00:00
d . exec_ ( )
2013-03-20 10:23:54 +00:00
def kindle_keys ( self ) :
2013-04-05 16:44:48 +00:00
if isosx or iswindows :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Kindle for Mac and PC Key " , self . tempdedrmprefs [ ' kindlekeys ' ] , AddKindleDialog , ' k4i ' )
2013-04-05 16:44:48 +00:00
else :
# linux
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Kindle for Mac and PC Key " , self . tempdedrmprefs [ ' kindlekeys ' ] , AddKindleDialog , ' k4i ' , self . tempdedrmprefs [ ' kindlewineprefix ' ] )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
2013-04-05 16:44:48 +00:00
self . tempdedrmprefs [ ' kindlewineprefix ' ] = d . getwineprefix ( )
2013-03-20 10:23:54 +00:00
def adept_keys ( self ) :
2013-04-05 16:44:48 +00:00
if isosx or iswindows :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Adobe Digital Editions Key " , self . tempdedrmprefs [ ' adeptkeys ' ] , AddAdeptDialog , ' der ' )
2013-04-05 16:44:48 +00:00
else :
# linux
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Adobe Digital Editions Key " , self . tempdedrmprefs [ ' adeptkeys ' ] , AddAdeptDialog , ' der ' , self . tempdedrmprefs [ ' adobewineprefix ' ] )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
2013-04-05 16:44:48 +00:00
self . tempdedrmprefs [ ' adobewineprefix ' ] = d . getwineprefix ( )
2013-03-20 10:23:54 +00:00
def mobi_keys ( self ) :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Mobipocket PID " , self . tempdedrmprefs [ ' pids ' ] , AddPIDDialog )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
def bandn_keys ( self ) :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " Barnes and Noble Key " , self . tempdedrmprefs [ ' bandnkeys ' ] , AddBandNKeyDialog , ' b64 ' )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
def ereader_keys ( self ) :
2020-09-27 10:54:49 +00:00
d = ManageKeysDialog ( self , " eReader Key " , self . tempdedrmprefs [ ' ereaderkeys ' ] , AddEReaderDialog , ' b63 ' )
2013-03-20 10:23:54 +00:00
d . exec_ ( )
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.
2020-09-27 10:54:49 +00:00
file_path = os . path . join ( config_dir , " plugins " , " DeDRM " , " help " , help_file_name )
2020-10-14 15:23:49 +00:00
with open ( file_path , ' w ' ) as f :
2013-03-20 10:23:54 +00:00
f . write ( self . load_resource ( help_file_name ) )
return file_path
url = ' file:/// ' + get_help_file_resource ( )
open_url ( QUrl ( url ) )
def save_settings ( self ) :
2013-04-05 16:44:48 +00:00
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 ' ] )
2015-07-29 17:11:19 +00:00
self . dedrmprefs . set ( ' androidkeys ' , self . tempdedrmprefs [ ' androidkeys ' ] )
2013-04-05 16:44:48 +00:00
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 )
2021-11-15 16:59:48 +00:00
self . dedrmprefs . set ( ' deobfuscate_fonts ' , self . chkFontObfuscation . isChecked ( ) )
2013-04-05 16:44:48 +00:00
self . dedrmprefs . writeprefs ( )
2013-03-20 10:23:54 +00:00
def load_resource ( self , name ) :
with ZipFile ( self . plugin_path , ' r ' ) as zf :
if name in zf . namelist ( ) :
2020-12-03 11:02:09 +00:00
return zf . read ( name ) . decode ( ' utf-8 ' )
2013-03-20 10:23:54 +00:00
return " "
2013-04-05 16:44:48 +00:00
class ManageKeysDialog ( QDialog ) :
2020-10-14 15:23:49 +00:00
def __init__ ( self , parent , key_type_name , plugin_keys , create_key , keyfile_ext = " " , wineprefix = None ) :
2013-04-05 16:44:48 +00:00
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
2020-10-14 15:23:49 +00:00
self . import_key = ( keyfile_ext != " " )
2020-09-27 10:54:49 +00:00
self . binary_file = ( keyfile_ext == " der " )
self . json_file = ( keyfile_ext == " k4i " )
self . android_file = ( keyfile_ext == " k4a " )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
keys_group_box = QGroupBox ( _ ( " {0} s " . format ( self . key_type_name ) ) , self )
2013-04-05 16:44:48 +00:00
layout . addWidget ( keys_group_box )
keys_group_box_layout = QHBoxLayout ( )
keys_group_box . setLayout ( keys_group_box_layout )
self . listy = QListWidget ( self )
2020-09-27 10:54:49 +00:00
self . listy . setToolTip ( " {0} s that will be used to decrypt ebooks " . format ( self . key_type_name ) )
2013-04-05 16:44:48 +00:00
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 . setIcon ( QIcon ( I ( ' plus.png ' ) ) )
2020-09-27 10:54:49 +00:00
self . _add_key_button . setToolTip ( " Create new {0} " . format ( self . key_type_name ) )
2013-04-05 16:44:48 +00:00
self . _add_key_button . clicked . connect ( self . add_key )
button_layout . addWidget ( self . _add_key_button )
self . _delete_key_button = QtGui . QToolButton ( self )
2020-09-27 10:54:49 +00:00
self . _delete_key_button . setToolTip ( _ ( " Delete highlighted key " ) )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
self . _rename_key_button . setToolTip ( _ ( " Rename highlighted key " ) )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
self . export_key_button . setToolTip ( " Save highlighted key to a . {0} file " . format ( self . keyfile_ext ) )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
self . wp_label = QLabel ( " WINEPREFIX: " )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
self . migrate_btn = QPushButton ( " Import Existing Keyfiles " , self )
self . migrate_btn . setToolTip ( " Import *. {0} files (created using other tools). " . format ( self . keyfile_ext ) )
2013-04-05 16:44:48 +00:00
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 :
2020-10-14 15:23:49 +00:00
return str ( self . wp_lineedit . text ( ) ) . strip ( )
return " "
2013-04-05 16:44:48 +00:00
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 ) )
2021-11-15 09:56:26 +00:00
self . listy . setMinimumWidth ( self . listy . sizeHintForColumn ( 0 ) + 20 )
2013-04-05 16:44:48 +00:00
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 ( ) :
2020-10-14 15:23:49 +00:00
old_key_name = [ name for name , value in self . plugin_keys . items ( ) if value == new_key_value ] [ 0 ]
2013-04-05 16:44:48 +00:00
info_dialog ( None , " {0} {1} : Duplicate {2} " . format ( PLUGIN_NAME , PLUGIN_VERSION , self . key_type_name ) ,
2020-09-27 10:54:49 +00:00
" 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 )
2013-04-05 16:44:48 +00:00
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 ) ,
2020-09-27 10:54:49 +00:00
" This {0} is already in the list of {0} s has not been added. " . format ( self . key_type_name ) , show = True )
2013-04-05 16:44:48 +00:00
return
self . plugin_keys . append ( d . key_value )
self . listy . clear ( )
self . populate_list ( )
def rename_key ( self ) :
if not self . listy . currentItem ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " No {0} selected to rename. Highlight a keyfile first. " . format ( self . key_type_name )
2013-04-05 16:44:48 +00:00
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
2020-10-14 15:23:49 +00:00
keyname = str ( self . listy . currentItem ( ) . text ( ) )
2020-09-27 10:54:49 +00:00
if not question_dialog ( self , " {0} {1} : Confirm Rename " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , " 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 ) :
2013-04-05 16:44:48 +00:00
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
2020-10-14 15:23:49 +00:00
keyname = str ( self . listy . currentItem ( ) . text ( ) )
2020-09-27 10:54:49 +00:00
if not question_dialog ( self , " {0} {1} : Confirm Delete " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , " Do you really want to delete the {1} <strong> {0} </strong>? " . format ( keyname , self . key_type_name ) , show_copy_button = False , default_yes = False ) :
2013-04-05 16:44:48 +00:00
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.
2020-09-27 10:54:49 +00:00
help_file_name = " {0} _ {1} _Help.htm " . format ( PLUGIN_NAME , self . key_type_name )
file_path = os . path . join ( config_dir , " plugins " , " DeDRM " , " help " , help_file_name )
2020-10-14 15:23:49 +00:00
with open ( file_path , ' w ' ) as f :
2013-04-05 16:44:48 +00:00
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 ) :
2020-09-27 10:54:49 +00:00
unique_dlg_name = PLUGIN_NAME + " import {0} keys " . format ( self . key_type_name ) . replace ( ' ' , ' _ ' ) #takes care of automatically remembering last directory
caption = " Select {0} files to import " . format ( self . key_type_name )
filters = [ ( " {0} files " . format ( self . key_type_name ) , [ self . keyfile_ext ] ) ]
2015-03-07 21:18:50 +00:00
files = choose_files ( self , unique_dlg_name , caption , filters , all_files = False )
2013-04-05 16:44:48 +00:00
counter = 0
skipped = 0
if files :
2013-03-20 10:23:54 +00:00
for filename in files :
fpath = os . path . join ( config_dir , filename )
2013-04-05 16:44:48 +00:00
filename = os . path . basename ( filename )
2015-07-29 17:11:19 +00:00
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 :
2020-11-22 15:03:45 +00:00
new_key_value = codecs . encode ( new_key_value , ' hex ' )
2015-07-29 17:11:19 +00:00
elif self . json_file :
new_key_value = json . loads ( new_key_value )
elif self . android_file :
# convert to list of the keys in the string
new_key_value = new_key_value . splitlines ( )
match = False
for key in self . plugin_keys . keys ( ) :
if uStrCmp ( new_key_name , key , True ) :
skipped + = 1
2020-09-27 10:54:49 +00:00
msg = " A key with the name <strong> {0} </strong> already exists! \n Skipping key file <strong> {1} </strong>. \n Rename the existing key and import again " . format ( new_key_name , filename )
2015-07-29 17:11:19 +00:00
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 ( ) :
2020-10-14 15:23:49 +00:00
old_key_name = [ name for name , value in self . plugin_keys . items ( ) if value == new_key_value ] [ 0 ]
2015-07-29 17:11:19 +00:00
skipped + = 1
info_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) ,
2020-09-27 10:54:49 +00:00
" 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 )
2015-07-29 17:11:19 +00:00
else :
counter + = 1
self . plugin_keys [ new_key_name ] = new_key_value
2020-09-26 20:22:47 +00:00
2020-10-14 15:23:49 +00:00
msg = " "
2013-04-05 16:44:48 +00:00
if counter + skipped > 1 :
if counter > 0 :
2020-09-27 10:54:49 +00:00
msg + = " Imported <strong> {0:d} </strong> key {1} . " . format ( counter , " file " if counter == 1 else " files " )
2013-04-05 16:44:48 +00:00
if skipped > 0 :
2020-09-27 10:54:49 +00:00
msg + = " Skipped <strong> {0:d} </strong> key {1} . " . format ( skipped , " file " if counter == 1 else " files " )
2013-04-05 16:44:48 +00:00
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 ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " No keyfile selected to export. Highlight a keyfile first. "
2013-04-05 16:44:48 +00:00
r = error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) ,
_ ( errmsg ) , show = True , show_copy_button = False )
return
2020-10-14 15:23:49 +00:00
keyname = str ( self . listy . currentItem ( ) . text ( ) )
2020-09-27 10:54:49 +00:00
unique_dlg_name = PLUGIN_NAME + " export {0} keys " . format ( self . key_type_name ) . replace ( ' ' , ' _ ' ) #takes care of automatically remembering last directory
caption = " Save {0} File as... " . format ( self . key_type_name )
filters = [ ( " {0} Files " . format ( self . key_type_name ) , [ " {0} " . format ( self . keyfile_ext ) ] ) ]
defaultname = " {0} . {1} " . format ( keyname , self . keyfile_ext )
2015-03-07 21:18:50 +00:00
filename = choose_save_file ( self , unique_dlg_name , caption , filters , all_files = False , initial_filename = defaultname )
2013-04-05 16:44:48 +00:00
if filename :
2020-11-06 22:49:18 +00:00
if self . binary_file :
with open ( filename , ' wb ' ) as fname :
2020-11-22 15:03:45 +00:00
fname . write ( codecs . decode ( self . plugin_keys [ keyname ] , ' hex ' ) )
2020-11-06 22:49:18 +00:00
elif self . json_file :
with open ( filename , ' w ' ) as fname :
2020-10-14 15:23:49 +00:00
fname . write ( json . dumps ( self . plugin_keys [ keyname ] ) )
2020-11-06 22:49:18 +00:00
elif self . android_file :
with open ( filename , ' w ' ) as fname :
2015-07-29 17:11:19 +00:00
for key in self . plugin_keys [ keyname ] :
2020-11-22 15:03:45 +00:00
fname . write ( key )
2020-11-06 22:49:18 +00:00
fname . write ( ' \n ' )
else :
with open ( filename , ' w ' ) as fname :
2020-11-22 15:03:45 +00:00
fname . write ( self . plugin_keys [ keyname ] )
2013-04-05 16:44:48 +00:00
class RenameKeyDialog ( QDialog ) :
def __init__ ( self , parent = None , ) :
2019-06-24 16:49:38 +00:00
print ( repr ( self ) , repr ( parent ) )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( " Enter a new name for this existing {0} . " . format ( parent . key_type_name ) )
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
if not str ( self . key_ledit . text ( ) ) or str ( self . key_ledit . text ( ) ) . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " Key name field cannot be empty! "
2013-04-05 16:44:48 +00:00
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 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2013-04-05 16:44:48 +00:00
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 ) ) :
2020-09-27 10:54:49 +00:00
errmsg = " The key name <strong> {0} </strong> is already being used. " . format ( self . key_ledit . text ( ) )
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
class AddBandNKeyDialog ( QDialog ) :
def __init__ ( self , parent = None , ) :
QDialog . __init__ ( self , parent )
self . parent = parent
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Create New Barnes & Noble Key " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Unique Key Name: " , self ) )
2013-04-05 16:44:48 +00:00
self . key_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( _ ( " <p>Enter an identifying name for this new key.</p> " +
" <p>It should be something that will help you remember " +
" what personal information was used to create it. " ) )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
name_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( name_group )
2020-09-27 10:54:49 +00:00
name_group . addWidget ( QLabel ( " B&N/nook account email address: " , self ) )
2020-10-14 15:23:49 +00:00
self . name_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . name_ledit . setToolTip ( _ ( " <p>Enter your email address as it appears in your B&N " +
" account.</p> " +
" <p>It will only be used to generate this " +
" key and won \' t be stored anywhere " +
" in calibre or on your computer.</p> " +
" <p>eg: apprenticeharper@gmail.com</p> " ) )
2013-04-05 16:44:48 +00:00
name_group . addWidget ( self . name_ledit )
2020-09-27 10:54:49 +00:00
name_disclaimer_label = QLabel ( _ ( " (Will not be saved in configuration data) " ) , self )
2013-04-05 16:44:48 +00:00
name_disclaimer_label . setAlignment ( Qt . AlignHCenter )
data_group_box_layout . addWidget ( name_disclaimer_label )
ccn_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( ccn_group )
2020-09-27 10:54:49 +00:00
ccn_group . addWidget ( QLabel ( " B&N/nook account password: " , self ) )
2020-10-14 15:23:49 +00:00
self . cc_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . cc_ledit . setToolTip ( _ ( " <p>Enter the password " +
" for your B&N account.</p> " +
" <p>The password will only be used to generate this " +
" key and won \' t be stored anywhere in " +
" calibre or on your computer. " ) )
2013-04-05 16:44:48 +00:00
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 )
2021-11-15 13:30:32 +00:00
self . chkOldAlgo = QCheckBox ( _ ( " Try to use the old algorithm " ) )
self . chkOldAlgo . setToolTip ( _ ( " Leave this off if you ' re unsure. " ) )
data_group_box_layout . addWidget ( self . chkOldAlgo )
layout . addSpacing ( 10 )
2016-04-25 16:49:06 +00:00
key_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( key_group )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Retrieved key: " , self ) )
2020-10-14 15:23:49 +00:00
self . key_display = QLabel ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_display . setToolTip ( _ ( " Click the Retrieve Key button to fetch your B&N encryption key from the B&N servers " ) )
2016-04-25 16:49:06 +00:00
key_group . addWidget ( self . key_display )
self . retrieve_button = QtGui . QPushButton ( self )
2020-09-27 10:54:49 +00:00
self . retrieve_button . setToolTip ( _ ( " Click to retrieve your B&N encryption key from the B&N servers " ) )
self . retrieve_button . setText ( " Retrieve Key " )
2016-04-25 16:49:06 +00:00
self . retrieve_button . clicked . connect ( self . retrieve_key )
key_group . addWidget ( self . retrieve_button )
layout . addSpacing ( 10 )
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_display . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def user_name ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . name_ledit . text ( ) ) . strip ( ) . lower ( ) . replace ( ' ' , ' ' )
2013-04-05 16:44:48 +00:00
@property
def cc_number ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . cc_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
2016-04-25 16:49:06 +00:00
def retrieve_key ( self ) :
2021-11-15 13:30:32 +00:00
if self . chkOldAlgo . isChecked ( ) :
# old method, try to generate
from calibre_plugins . dedrm . ignoblekeygen import generate_key as generate_bandn_key
generated_key = generate_bandn_key ( self . user_name , self . cc_number )
if generated_key == " " :
errmsg = " Could not generate key. "
error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
else :
self . key_display . setText ( generated_key . decode ( " latin-1 " ) )
else :
# New method, try to connect to server
from calibre_plugins . dedrm . ignoblekeyfetch import fetch_key as fetch_bandn_key
fetched_key = fetch_bandn_key ( self . user_name , self . cc_number )
if fetched_key == " " :
errmsg = " Could not retrieve key. Check username, password and intenet connectivity and try again. "
error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
else :
self . key_display . setText ( fetched_key )
2013-04-05 16:44:48 +00:00
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 ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " All fields are required! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) < 4 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
2016-04-25 16:49:06 +00:00
if len ( self . key_value ) == 0 :
self . retrieve_key ( )
if len ( self . key_value ) == 0 :
return
2013-04-05 16:44:48 +00:00
QDialog . accept ( self )
class AddEReaderDialog ( QDialog ) :
def __init__ ( self , parent = None , ) :
QDialog . __init__ ( self , parent )
self . parent = parent
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Create New eReader Key " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Unique Key Name: " , self ) )
2013-04-05 16:44:48 +00:00
self . key_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( " <p>Enter an identifying name for this new key. \n It should be something that will help you remember what personal information was used to create it. " )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
name_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( name_group )
2020-09-27 10:54:49 +00:00
name_group . addWidget ( QLabel ( " Your Name: " , self ) )
2020-10-14 15:23:49 +00:00
self . name_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . name_ledit . setToolTip ( " Enter the name for this eReader key, usually the name on your credit card. \n It 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) " )
2013-04-05 16:44:48 +00:00
name_group . addWidget ( self . name_ledit )
2020-09-27 10:54:49 +00:00
name_disclaimer_label = QLabel ( _ ( " (Will not be saved in configuration data) " ) , self )
2013-04-05 16:44:48 +00:00
name_disclaimer_label . setAlignment ( Qt . AlignHCenter )
data_group_box_layout . addWidget ( name_disclaimer_label )
ccn_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( ccn_group )
2020-09-27 10:54:49 +00:00
ccn_group . addWidget ( QLabel ( " Credit Card#: " , self ) )
2020-10-14 15:23:49 +00:00
self . cc_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . cc_ledit . setToolTip ( " <p>Enter the last 8 digits of credit card number for this eReader key. \n They will only be used to generate this one-time key and won \' t be stored anywhere in calibre or on your computer. " )
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
from calibre_plugins . dedrm . erdr2pml import getuser_key as generate_ereader_key
2020-11-22 15:03:45 +00:00
return codecs . encode ( generate_ereader_key ( self . user_name , self . cc_number ) , ' hex ' )
2013-04-05 16:44:48 +00:00
@property
def user_name ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . name_ledit . text ( ) ) . strip ( ) . lower ( ) . replace ( ' ' , ' ' )
2013-04-05 16:44:48 +00:00
@property
def cc_number ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . cc_ledit . text ( ) ) . strip ( ) . replace ( ' ' , ' ' ) . replace ( ' - ' , ' ' )
2013-04-05 16:44:48 +00:00
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 ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " All fields are required! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if not self . cc_number . isdigit ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " Numbers only in the credit card number field! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) < 4 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2013-04-05 16:44:48 +00:00
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
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Getting Default Adobe Digital Editions Key " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
try :
if iswindows or isosx :
from calibre_plugins . dedrm . adobekey import adeptkeys
defaultkeys = adeptkeys ( )
2013-04-24 18:28:20 +00:00
else : # linux
2020-10-14 15:23:49 +00:00
from . wineutils import WineGetKeys
2013-04-05 16:44:48 +00:00
2020-09-27 10:54:49 +00:00
scriptpath = os . path . join ( parent . parent . alfdir , " adobekey.py " )
defaultkeys = WineGetKeys ( scriptpath , " .der " , parent . getwineprefix ( ) )
2013-04-05 16:44:48 +00:00
self . default_key = defaultkeys [ 0 ]
except :
traceback . print_exc ( )
2020-10-14 15:23:49 +00:00
self . default_key = " "
2013-04-05 16:44:48 +00:00
self . button_box = QDialogButtonBox ( QDialogButtonBox . Ok | QDialogButtonBox . Cancel )
if len ( self . default_key ) > 0 :
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Unique Key Name: " , self ) )
self . key_ledit = QLineEdit ( " default_key " , self )
self . key_ledit . setToolTip ( " <p>Enter an identifying name for the current default Adobe Digital Editions key. " )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
2015-07-29 17:11:19 +00:00
2013-04-05 16:44:48 +00:00
self . button_box . accepted . connect ( self . accept )
else :
2020-09-27 10:54:49 +00:00
default_key_error = QLabel ( " The default encryption key for Adobe Digital Editions could not be found. " , self )
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
2020-11-22 15:03:45 +00:00
return codecs . encode ( self . default_key , ' hex ' )
2013-04-05 16:44:48 +00:00
def accept ( self ) :
if len ( self . key_name ) == 0 or self . key_name . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " All fields are required! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) < 4 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2013-04-05 16:44:48 +00:00
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
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Getting Default Kindle for Mac/PC Key " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
try :
if iswindows or isosx :
from calibre_plugins . dedrm . kindlekey import kindlekeys
defaultkeys = kindlekeys ( )
else : # linux
2020-10-14 15:23:49 +00:00
from . wineutils import WineGetKeys
2013-04-05 16:44:48 +00:00
2020-09-27 10:54:49 +00:00
scriptpath = os . path . join ( parent . parent . alfdir , " kindlekey.py " )
defaultkeys = WineGetKeys ( scriptpath , " .k4i " , parent . getwineprefix ( ) )
2013-04-05 16:44:48 +00:00
self . default_key = defaultkeys [ 0 ]
except :
traceback . print_exc ( )
2020-10-14 15:23:49 +00:00
self . default_key = " "
2013-04-05 16:44:48 +00:00
self . button_box = QDialogButtonBox ( QDialogButtonBox . Ok | QDialogButtonBox . Cancel )
if len ( self . default_key ) > 0 :
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Unique Key Name: " , self ) )
self . key_ledit = QLineEdit ( " default_key " , self )
self . key_ledit . setToolTip ( " <p>Enter an identifying name for the current default Kindle for Mac/PC key. " )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
2015-07-29 17:11:19 +00:00
2013-04-05 16:44:48 +00:00
self . button_box . accepted . connect ( self . accept )
else :
2020-09-27 10:54:49 +00:00
default_key_error = QLabel ( " The default encryption key for Kindle for Mac/PC could not be found. " , self )
2013-04-05 16:44:48 +00:00
default_key_error . setAlignment ( Qt . AlignHCenter )
layout . addWidget ( default_key_error )
2020-09-26 20:22:47 +00:00
2015-07-29 17:11:19 +00:00
# if no default, both buttons do the same
2013-04-05 16:44:48 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
return self . default_key
def accept ( self ) :
if len ( self . key_name ) == 0 or self . key_name . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " All fields are required! "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) < 4 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2013-04-05 16:44:48 +00:00
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
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Add New EInk Kindle Serial Number " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " EInk Kindle Serial Number: " , self ) )
2013-04-05 16:44:48 +00:00
self . key_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( " 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. " )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . replace ( ' ' , ' ' )
2013-04-05 16:44:48 +00:00
def accept ( self ) :
if len ( self . key_name ) == 0 or self . key_name . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " Please enter an eInk Kindle Serial Number or click Cancel in the dialog. "
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) != 16 :
2020-09-27 10:54:49 +00:00
errmsg = " EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long. " . format ( len ( self . key_name ) )
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
QDialog . accept ( self )
2015-07-29 17:11:19 +00:00
class AddAndroidDialog ( QDialog ) :
2015-03-17 17:49:30 +00:00
def __init__ ( self , parent = None , ) :
2015-07-29 17:11:19 +00:00
2015-03-17 17:49:30 +00:00
QDialog . __init__ ( self , parent )
self . parent = parent
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Add new Kindle for Android Key " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2015-03-17 17:49:30 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
2015-07-29 17:11:19 +00:00
self . button_box = QDialogButtonBox ( QDialogButtonBox . Ok | QDialogButtonBox . Cancel )
2015-03-17 17:49:30 +00:00
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2015-03-17 17:49:30 +00:00
layout . addWidget ( data_group_box )
data_group_box_layout = QVBoxLayout ( )
data_group_box . setLayout ( data_group_box_layout )
2015-07-29 17:11:19 +00:00
file_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( file_group )
2020-09-27 10:54:49 +00:00
add_btn = QPushButton ( " Choose Backup File " , self )
add_btn . setToolTip ( " Import Kindle for Android backup file. " )
2015-07-29 17:11:19 +00:00
add_btn . clicked . connect ( self . get_android_file )
file_group . addWidget ( add_btn )
2020-10-14 15:23:49 +00:00
self . selected_file_name = QLabel ( " " , self )
2015-07-29 17:11:19 +00:00
self . selected_file_name . setAlignment ( Qt . AlignHCenter )
file_group . addWidget ( self . selected_file_name )
2020-09-26 20:22:47 +00:00
2015-03-17 17:49:30 +00:00
key_group = QHBoxLayout ( )
data_group_box_layout . addLayout ( key_group )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " Unique Key Name: " , self ) )
2020-10-14 15:23:49 +00:00
self . key_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( " <p>Enter an identifying name for the Android for Kindle key. " )
2015-03-17 17:49:30 +00:00
key_group . addWidget ( self . key_ledit )
2015-07-29 17:11:19 +00:00
#key_label = QLabel(_(''), self)
#key_label.setAlignment(Qt.AlignHCenter)
#data_group_box_layout.addWidget(key_label)
2020-09-26 20:22:47 +00:00
2015-03-17 17:49:30 +00:00
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2015-03-17 17:49:30 +00:00
2015-07-29 17:11:19 +00:00
@property
def file_name ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . selected_file_name . text ( ) ) . strip ( )
2015-07-29 17:11:19 +00:00
2015-03-17 17:49:30 +00:00
@property
def key_value ( self ) :
2015-07-29 17:11:19 +00:00
return self . serials_from_file
2020-09-26 20:22:47 +00:00
2015-07-29 17:11:19 +00:00
def get_android_file ( self ) :
2020-09-27 10:54:49 +00:00
unique_dlg_name = PLUGIN_NAME + " Import Kindle for Android backup file " #takes care of automatically remembering last directory
caption = " Select Kindle for Android backup file to add "
filters = [ ( " Kindle for Android backup files " , [ ' db ' , ' ab ' , ' xml ' ] ) ]
2015-07-29 17:11:19 +00:00
files = choose_files ( self , unique_dlg_name , caption , filters , all_files = False )
self . serials_from_file = [ ]
2020-10-14 15:23:49 +00:00
file_name = " "
2015-07-29 17:11:19 +00:00
if files :
# find the first selected file that yields some serial numbers
for filename in files :
fpath = os . path . join ( config_dir , filename )
self . filename = os . path . basename ( filename )
file_serials = androidkindlekey . get_serials ( fpath )
if len ( file_serials ) > 0 :
file_name = os . path . basename ( self . filename )
self . serials_from_file . extend ( file_serials )
self . selected_file_name . setText ( file_name )
2020-09-26 20:22:47 +00:00
2015-03-17 17:49:30 +00:00
def accept ( self ) :
2015-07-29 17:11:19 +00:00
if len ( self . file_name ) == 0 or len ( self . key_value ) == 0 :
2020-09-27 10:54:49 +00:00
errmsg = " Please choose a Kindle for Android backup file. "
2015-07-29 17:11:19 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
2015-03-17 17:49:30 +00:00
if len ( self . key_name ) == 0 or self . key_name . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " Please enter a key name. "
2015-07-29 17:11:19 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
if len ( self . key_name ) < 4 :
2020-09-27 10:54:49 +00:00
errmsg = " Key name must be at <i>least</i> 4 characters long! "
2015-03-17 17:49:30 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
QDialog . accept ( self )
2013-04-05 16:44:48 +00:00
class AddPIDDialog ( QDialog ) :
def __init__ ( self , parent = None , ) :
QDialog . __init__ ( self , parent )
self . parent = parent
2020-09-27 10:54:49 +00:00
self . setWindowTitle ( " {0} {1} : Add New Mobipocket PID " . format ( PLUGIN_NAME , PLUGIN_VERSION ) )
2013-04-05 16:44:48 +00:00
layout = QVBoxLayout ( self )
self . setLayout ( layout )
2020-10-14 15:23:49 +00:00
data_group_box = QGroupBox ( " " , self )
2013-04-05 16:44:48 +00:00
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 )
2020-09-27 10:54:49 +00:00
key_group . addWidget ( QLabel ( " PID: " , self ) )
2013-04-05 16:44:48 +00:00
self . key_ledit = QLineEdit ( " " , self )
2020-09-27 10:54:49 +00:00
self . key_ledit . setToolTip ( " 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. " )
2013-04-05 16:44:48 +00:00
key_group . addWidget ( self . key_ledit )
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 ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
@property
def key_value ( self ) :
2020-10-14 15:23:49 +00:00
return str ( self . key_ledit . text ( ) ) . strip ( )
2013-04-05 16:44:48 +00:00
def accept ( self ) :
if len ( self . key_name ) == 0 or self . key_name . isspace ( ) :
2020-09-27 10:54:49 +00:00
errmsg = " Please enter a Mobipocket PID or click Cancel in the dialog. "
2013-04-05 16:44:48 +00:00
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 :
2020-09-27 10:54:49 +00:00
errmsg = " Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long. " . format ( len ( self . key_name ) )
2013-04-05 16:44:48 +00:00
return error_dialog ( None , " {0} {1} " . format ( PLUGIN_NAME , PLUGIN_VERSION ) , errmsg , show = True , show_copy_button = False )
QDialog . accept ( self )