mirror of
				https://github.com/noDRM/DeDRM_tools.git
				synced 2025-10-23 23:07:47 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			1012 lines
		
	
	
	
		
			46 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1012 lines
		
	
	
	
		
			46 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python3
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| __license__ = 'GPL v3'
 | |
| 
 | |
| # Python 3, September 2020
 | |
| 
 | |
| # Standard Python modules.
 | |
| import os, traceback, json
 | |
| 
 | |
| from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
 | |
|                       QGroupBox, QPushButton, QListWidget, QListWidgetItem,
 | |
|                       QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl)
 | |
| 
 | |
| from PyQt5 import Qt as QtGui
 | |
| from zipfile import ZipFile
 | |
| 
 | |
| # calibre modules and constants.
 | |
| from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url,
 | |
|                             choose_dir, choose_files, choose_save_file)
 | |
| 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
 | |
| from calibre_plugins.dedrm.utilities import uStrCmp
 | |
| 
 | |
| import calibre_plugins.dedrm.prefs as prefs
 | |
| import calibre_plugins.dedrm.androidkindlekey as androidkindlekey
 | |
| 
 | |
| class ConfigWidget(QWidget):
 | |
|     def __init__(self, plugin_path, alfdir):
 | |
|         QWidget.__init__(self)
 | |
| 
 | |
|         self.plugin_path = plugin_path
 | |
|         self.alfdir = alfdir
 | |
| 
 | |
|         # 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()
 | |
|         self.tempdedrmprefs['ereaderkeys'] = self.dedrmprefs['ereaderkeys'].copy()
 | |
|         self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy()
 | |
|         self.tempdedrmprefs['androidkeys'] = self.dedrmprefs['androidkeys'].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)
 | |
|         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)
 | |
|         self.bandn_button.setToolTip(_("Click to manage keys for Barnes and Noble ebooks"))
 | |
|         self.bandn_button.setText("Barnes and Noble ebooks")
 | |
|         self.bandn_button.clicked.connect(self.bandn_keys)
 | |
|         self.kindle_android_button = QtGui.QPushButton(self)
 | |
|         self.kindle_android_button.setToolTip(_("Click to manage keys for Kindle for Android ebooks"))
 | |
|         self.kindle_android_button.setText("Kindle for Android ebooks")
 | |
|         self.kindle_android_button.clicked.connect(self.kindle_android)
 | |
|         self.kindle_serial_button = QtGui.QPushButton(self)
 | |
|         self.kindle_serial_button.setToolTip(_("Click to manage eInk Kindle serial numbers for Kindle ebooks"))
 | |
|         self.kindle_serial_button.setText("eInk Kindle ebooks")
 | |
|         self.kindle_serial_button.clicked.connect(self.kindle_serials)
 | |
|         self.kindle_key_button = QtGui.QPushButton(self)
 | |
|         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")
 | |
|         self.kindle_key_button.clicked.connect(self.kindle_keys)
 | |
|         self.adept_button = QtGui.QPushButton(self)
 | |
|         self.adept_button.setToolTip(_("Click to manage keys for Adobe Digital Editions ebooks"))
 | |
|         self.adept_button.setText("Adobe Digital Editions ebooks")
 | |
|         self.adept_button.clicked.connect(self.adept_keys)
 | |
|         self.mobi_button = QtGui.QPushButton(self)
 | |
|         self.mobi_button.setToolTip(_("Click to manage PIDs for Mobipocket ebooks"))
 | |
|         self.mobi_button.setText("Mobipocket ebooks")
 | |
|         self.mobi_button.clicked.connect(self.mobi_keys)
 | |
|         self.ereader_button = QtGui.QPushButton(self)
 | |
|         self.ereader_button.setToolTip(_("Click to manage keys for eReader ebooks"))
 | |
|         self.ereader_button.setText("eReader ebooks")
 | |
|         self.ereader_button.clicked.connect(self.ereader_keys)
 | |
|         button_layout.addWidget(self.kindle_serial_button)
 | |
|         button_layout.addWidget(self.kindle_android_button)
 | |
|         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)
 | |
| 
 | |
|         self.resize(self.sizeHint())
 | |
| 
 | |
|     def kindle_serials(self):
 | |
|         d = ManageKeysDialog(self,"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], AddSerialDialog)
 | |
|         d.exec_()
 | |
| 
 | |
|     def kindle_android(self):
 | |
|         d = ManageKeysDialog(self,"Kindle for Android Key",self.tempdedrmprefs['androidkeys'], AddAndroidDialog, 'k4a')
 | |
|         d.exec_()
 | |
| 
 | |
|     def kindle_keys(self):
 | |
|         if isosx or iswindows:
 | |
|             d = ManageKeysDialog(self,"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], AddKindleDialog, 'k4i')
 | |
|         else:
 | |
|             # linux
 | |
|             d = ManageKeysDialog(self,"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):
 | |
|         if isosx or iswindows:
 | |
|             d = ManageKeysDialog(self,"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der')
 | |
|         else:
 | |
|             # linux
 | |
|             d = ManageKeysDialog(self,"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], AddAdeptDialog, 'der', self.tempdedrmprefs['adobewineprefix'])
 | |
|         d.exec_()
 | |
|         self.tempdedrmprefs['adobewineprefix'] = d.getwineprefix()
 | |
| 
 | |
|     def mobi_keys(self):
 | |
|         d = ManageKeysDialog(self,"Mobipocket PID",self.tempdedrmprefs['pids'], AddPIDDialog)
 | |
|         d.exec_()
 | |
| 
 | |
|     def bandn_keys(self):
 | |
|         d = ManageKeysDialog(self,"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], AddBandNKeyDialog, 'b64')
 | |
|         d.exec_()
 | |
| 
 | |
|     def ereader_keys(self):
 | |
|         d = ManageKeysDialog(self,"eReader Key",self.tempdedrmprefs['ereaderkeys'], AddEReaderDialog, 'b63')
 | |
|         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.
 | |
|             file_path = os.path.join(config_dir, "plugins", "DeDRM", "help", help_file_name)
 | |
|             with open(file_path,'w') as f:
 | |
|                 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):
 | |
|         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('androidkeys', self.tempdedrmprefs['androidkeys'])
 | |
|         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:
 | |
|             if name in zf.namelist():
 | |
|                 return zf.read(name)
 | |
|         return ""
 | |
| 
 | |
| 
 | |
| 
 | |
| class ManageKeysDialog(QDialog):
 | |
|     def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = "", 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 != "")
 | |
|         self.binary_file = (keyfile_ext == "der")
 | |
|         self.json_file = (keyfile_ext == "k4i")
 | |
|         self.android_file = (keyfile_ext == "k4a")
 | |
|         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(_("{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("{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.setIcon(QIcon(I('plus.png')))
 | |
|         self._add_key_button.setToolTip("Create new {0}".format(self.key_type_name))
 | |
|         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(_("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(_("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("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("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("Import Existing Keyfiles", self)
 | |
|             self.migrate_btn.setToolTip("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 str(self.wp_lineedit.text()).strip()
 | |
|         return ""
 | |
| 
 | |
|     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.items() if value == new_key_value][0]
 | |
|                 info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
 | |
|                                     "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),
 | |
|                                     "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 = "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 = str(self.listy.currentItem().text())
 | |
|         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):
 | |
|             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 = str(self.listy.currentItem().text())
 | |
|         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):
 | |
|             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 = "{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name)
 | |
|             file_path = os.path.join(config_dir, "plugins", "DeDRM", "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):
 | |
|         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])]
 | |
|         files = choose_files(self, unique_dlg_name, caption, filters, all_files=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)
 | |
|                 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
 | |
|                         msg = "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.items() if value == new_key_value][0]
 | |
|                         skipped += 1
 | |
|                         info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
 | |
|                                             "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 = ""
 | |
|             if counter+skipped > 1:
 | |
|                 if counter > 0:
 | |
|                     msg += "Imported <strong>{0:d}</strong> key {1}. ".format(counter, "file" if counter == 1 else "files")
 | |
|                 if skipped > 0:
 | |
|                     msg += "Skipped <strong>{0:d}</strong> key {1}.".format(skipped, "file" if counter == 1 else "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 = "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
 | |
|         keyname = str(self.listy.currentItem().text())
 | |
|         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)
 | |
|         filename = choose_save_file(self, unique_dlg_name,  caption, filters, all_files=False, initial_filename=defaultname)
 | |
|         if filename:
 | |
|             with file(filename, 'wb') 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]))
 | |
|                 elif self.android_file:
 | |
|                     for key in self.plugin_keys[keyname]:
 | |
|                         fname.write(key)
 | |
|                         fname.write("\n")
 | |
|                 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("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 not str(self.key_ledit.text()) or str(self.key_ledit.text()).isspace():
 | |
|             errmsg = "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 = "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 = "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 str(self.key_ledit.text()).strip()
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| class AddBandNKeyDialog(QDialog):
 | |
|     def __init__(self, parent=None,):
 | |
|         QDialog.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.setWindowTitle("{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION))
 | |
|         layout = QVBoxLayout(self)
 | |
|         self.setLayout(layout)
 | |
| 
 | |
|         data_group_box = QGroupBox("", self)
 | |
|         layout.addWidget(data_group_box)
 | |
|         data_group_box_layout = QVBoxLayout()
 | |
|         data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("Unique Key Name:", self))
 | |
|         self.key_ledit = QLineEdit("", self)
 | |
|         self.key_ledit.setToolTip(_("<p>Enter an identifying name for this new key.</p>" +
 | |
|                                 "<p>It should be something that will help you remember " +
 | |
|                                 "what personal information was used to create it."))
 | |
|         key_group.addWidget(self.key_ledit)
 | |
| 
 | |
|         name_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(name_group)
 | |
|         name_group.addWidget(QLabel("B&N/nook account email address:", self))
 | |
|         self.name_ledit = QLineEdit("", self)
 | |
|         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>"))
 | |
|         name_group.addWidget(self.name_ledit)
 | |
|         name_disclaimer_label = QLabel(_("(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("B&N/nook account password:", self))
 | |
|         self.cc_ledit = QLineEdit("", self)
 | |
|         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."))
 | |
|         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)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("Retrieved key:", self))
 | |
|         self.key_display = QLabel("", self)
 | |
|         self.key_display.setToolTip(_("Click the Retrieve Key button to fetch your B&N encryption key from the B&N servers"))
 | |
|         key_group.addWidget(self.key_display)
 | |
|         self.retrieve_button = QtGui.QPushButton(self)
 | |
|         self.retrieve_button.setToolTip(_("Click to retrieve your B&N encryption key from the B&N servers"))
 | |
|         self.retrieve_button.setText("Retrieve Key")
 | |
|         self.retrieve_button.clicked.connect(self.retrieve_key)
 | |
|         key_group.addWidget(self.retrieve_button)
 | |
|         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 str(self.key_ledit.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def key_value(self):
 | |
|         return str(self.key_display.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def user_name(self):
 | |
|         return str(self.name_ledit.text()).strip().lower().replace(' ','')
 | |
| 
 | |
|     @property
 | |
|     def cc_number(self):
 | |
|         return str(self.cc_ledit.text()).strip()
 | |
| 
 | |
|     def retrieve_key(self):
 | |
|         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)
 | |
| 
 | |
|     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 = "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 = "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 len(self.key_value) == 0:
 | |
|             self.retrieve_key()
 | |
|             if len(self.key_value) == 0:
 | |
|                 return
 | |
|         QDialog.accept(self)
 | |
| 
 | |
| class AddEReaderDialog(QDialog):
 | |
|     def __init__(self, parent=None,):
 | |
|         QDialog.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.setWindowTitle("{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION))
 | |
|         layout = QVBoxLayout(self)
 | |
|         self.setLayout(layout)
 | |
| 
 | |
|         data_group_box = QGroupBox("", self)
 | |
|         layout.addWidget(data_group_box)
 | |
|         data_group_box_layout = QVBoxLayout()
 | |
|         data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("Unique Key Name:", self))
 | |
|         self.key_ledit = QLineEdit("", self)
 | |
|         self.key_ledit.setToolTip("<p>Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.")
 | |
|         key_group.addWidget(self.key_ledit)
 | |
| 
 | |
|         name_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(name_group)
 | |
|         name_group.addWidget(QLabel("Your Name:", self))
 | |
|         self.name_ledit = QLineEdit("", self)
 | |
|         self.name_ledit.setToolTip("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(_("(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("Credit Card#:", self))
 | |
|         self.cc_ledit = QLineEdit("", self)
 | |
|         self.cc_ledit.setToolTip("<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 str(self.key_ledit.text()).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 str(self.name_ledit.text()).strip().lower().replace(' ','')
 | |
| 
 | |
|     @property
 | |
|     def cc_number(self):
 | |
|         return str(self.cc_ledit.text()).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 = "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 = "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 = "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("{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,"adobekey.py")
 | |
|                 defaultkeys = WineGetKeys(scriptpath, ".der",parent.getwineprefix())
 | |
| 
 | |
|             self.default_key = defaultkeys[0]
 | |
|         except:
 | |
|             traceback.print_exc()
 | |
|             self.default_key = ""
 | |
| 
 | |
|         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
 | |
| 
 | |
|         if len(self.default_key)>0:
 | |
|             data_group_box = QGroupBox("", self)
 | |
|             layout.addWidget(data_group_box)
 | |
|             data_group_box_layout = QVBoxLayout()
 | |
|             data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|             key_group = QHBoxLayout()
 | |
|             data_group_box_layout.addLayout(key_group)
 | |
|             key_group.addWidget(QLabel("Unique Key Name:", self))
 | |
|             self.key_ledit = QLineEdit("default_key", self)
 | |
|             self.key_ledit.setToolTip("<p>Enter an identifying name for the current default Adobe Digital Editions key.")
 | |
|             key_group.addWidget(self.key_ledit)
 | |
| 
 | |
|             self.button_box.accepted.connect(self.accept)
 | |
|         else:
 | |
|             default_key_error = QLabel("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 str(self.key_ledit.text()).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 = "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 = "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("{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,"kindlekey.py")
 | |
|                 defaultkeys = WineGetKeys(scriptpath, ".k4i",parent.getwineprefix())
 | |
| 
 | |
|             self.default_key = defaultkeys[0]
 | |
|         except:
 | |
|             traceback.print_exc()
 | |
|             self.default_key = ""
 | |
| 
 | |
|         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
 | |
| 
 | |
|         if len(self.default_key)>0:
 | |
|             data_group_box = QGroupBox("", self)
 | |
|             layout.addWidget(data_group_box)
 | |
|             data_group_box_layout = QVBoxLayout()
 | |
|             data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|             key_group = QHBoxLayout()
 | |
|             data_group_box_layout.addLayout(key_group)
 | |
|             key_group.addWidget(QLabel("Unique Key Name:", self))
 | |
|             self.key_ledit = QLineEdit("default_key", self)
 | |
|             self.key_ledit.setToolTip("<p>Enter an identifying name for the current default Kindle for Mac/PC key.")
 | |
|             key_group.addWidget(self.key_ledit)
 | |
| 
 | |
|             self.button_box.accepted.connect(self.accept)
 | |
|         else:
 | |
|             default_key_error = QLabel("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, both 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 str(self.key_ledit.text()).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 = "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 = "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("{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
 | |
|         layout = QVBoxLayout(self)
 | |
|         self.setLayout(layout)
 | |
| 
 | |
|         data_group_box = QGroupBox("", self)
 | |
|         layout.addWidget(data_group_box)
 | |
|         data_group_box_layout = QVBoxLayout()
 | |
|         data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("EInk Kindle Serial Number:", self))
 | |
|         self.key_ledit = QLineEdit("", self)
 | |
|         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.")
 | |
|         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):
 | |
|         return str(self.key_ledit.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def key_value(self):
 | |
|         return str(self.key_ledit.text()).replace(' ', '')
 | |
| 
 | |
|     def accept(self):
 | |
|         if len(self.key_name) == 0 or self.key_name.isspace():
 | |
|             errmsg = "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 = "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 AddAndroidDialog(QDialog):
 | |
|     def __init__(self, parent=None,):
 | |
| 
 | |
|         QDialog.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.setWindowTitle("{0} {1}: Add new Kindle for Android Key".format(PLUGIN_NAME, PLUGIN_VERSION))
 | |
|         layout = QVBoxLayout(self)
 | |
|         self.setLayout(layout)
 | |
|         self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
 | |
| 
 | |
|         data_group_box = QGroupBox("", self)
 | |
|         layout.addWidget(data_group_box)
 | |
|         data_group_box_layout = QVBoxLayout()
 | |
|         data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|         file_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(file_group)
 | |
|         add_btn = QPushButton("Choose Backup File", self)
 | |
|         add_btn.setToolTip("Import Kindle for Android backup file.")
 | |
|         add_btn.clicked.connect(self.get_android_file)
 | |
|         file_group.addWidget(add_btn)
 | |
|         self.selected_file_name = QLabel("",self)
 | |
|         self.selected_file_name.setAlignment(Qt.AlignHCenter)
 | |
|         file_group.addWidget(self.selected_file_name)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("Unique Key Name:", self))
 | |
|         self.key_ledit = QLineEdit("", self)
 | |
|         self.key_ledit.setToolTip("<p>Enter an identifying name for the Android for Kindle 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)
 | |
|         self.button_box.rejected.connect(self.reject)
 | |
|         layout.addWidget(self.button_box)
 | |
|         self.resize(self.sizeHint())
 | |
| 
 | |
|     @property
 | |
|     def key_name(self):
 | |
|         return str(self.key_ledit.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def file_name(self):
 | |
|         return str(self.selected_file_name.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def key_value(self):
 | |
|         return self.serials_from_file
 | |
| 
 | |
|     def get_android_file(self):
 | |
|         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'])]
 | |
|         files = choose_files(self, unique_dlg_name, caption, filters, all_files=False)
 | |
|         self.serials_from_file = []
 | |
|         file_name = ""
 | |
|         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)
 | |
| 
 | |
| 
 | |
|     def accept(self):
 | |
|         if len(self.file_name) == 0 or len(self.key_value) == 0:
 | |
|             errmsg = "Please choose a Kindle for Android backup file."
 | |
|             return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
 | |
|         if len(self.key_name) == 0 or self.key_name.isspace():
 | |
|             errmsg = "Please enter a key name."
 | |
|             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 = "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 AddPIDDialog(QDialog):
 | |
|     def __init__(self, parent=None,):
 | |
|         QDialog.__init__(self, parent)
 | |
|         self.parent = parent
 | |
|         self.setWindowTitle("{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION))
 | |
|         layout = QVBoxLayout(self)
 | |
|         self.setLayout(layout)
 | |
| 
 | |
|         data_group_box = QGroupBox("", self)
 | |
|         layout.addWidget(data_group_box)
 | |
|         data_group_box_layout = QVBoxLayout()
 | |
|         data_group_box.setLayout(data_group_box_layout)
 | |
| 
 | |
|         key_group = QHBoxLayout()
 | |
|         data_group_box_layout.addLayout(key_group)
 | |
|         key_group.addWidget(QLabel("PID:", self))
 | |
|         self.key_ledit = QLineEdit("", self)
 | |
|         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.")
 | |
|         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):
 | |
|         return str(self.key_ledit.text()).strip()
 | |
| 
 | |
|     @property
 | |
|     def key_value(self):
 | |
|         return str(self.key_ledit.text()).strip()
 | |
| 
 | |
|     def accept(self):
 | |
|         if len(self.key_name) == 0 or self.key_name.isspace():
 | |
|             errmsg = "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 = "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)
 | |
| 
 | |
| 
 | 
