diff --git a/DeDRM_plugin/_unused_activitybar.py b/DeDRM_plugin/_unused_activitybar.py deleted file mode 100644 index 8ebc10c..0000000 --- a/DeDRM_plugin/_unused_activitybar.py +++ /dev/null @@ -1,77 +0,0 @@ -# I think this file is unused? - -import sys -import tkinter -import tkinter.constants - -class ActivityBar(tkinter.Frame): - - def __init__(self, master, length=300, height=20, barwidth=15, interval=50, bg='white', fillcolor='orchid1',\ - bd=2, relief=tkinter.constants.GROOVE, *args, **kw): - tkinter.Frame.__init__(self, master, bg=bg, width=length, height=height, *args, **kw) - self._master = master - self._interval = interval - self._maximum = length - self._startx = 0 - self._barwidth = barwidth - self._bardiv = length / barwidth - if self._bardiv < 10: - self._bardiv = 10 - stopx = self._startx + self._barwidth - if stopx > self._maximum: - stopx = self._maximum - # self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ - # highlightthickness=0, relief='flat', bd=0) - self._canv = tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ - highlightthickness=0, relief=relief, bd=bd) - self._canv.pack(fill='both', expand=1) - self._rect = self._canv.create_rectangle(0, 0, self._canv.winfo_reqwidth(), self._canv.winfo_reqheight(), fill=fillcolor, width=0) - - self._set() - self.bind('', self._update_coords) - self._running = False - - def _update_coords(self, event): - '''Updates the position of the rectangle inside the canvas when the size of - the widget gets changed.''' - # looks like we have to call update_idletasks() twice to make sure - # to get the results we expect - self._canv.update_idletasks() - self._maximum = self._canv.winfo_width() - self._startx = 0 - self._barwidth = self._maximum / self._bardiv - if self._barwidth < 2: - self._barwidth = 2 - stopx = self._startx + self._barwidth - if stopx > self._maximum: - stopx = self._maximum - self._canv.coords(self._rect, 0, 0, stopx, self._canv.winfo_height()) - self._canv.update_idletasks() - - def _set(self): - if self._startx < 0: - self._startx = 0 - if self._startx > self._maximum: - self._startx = self._startx % self._maximum - stopx = self._startx + self._barwidth - if stopx > self._maximum: - stopx = self._maximum - self._canv.coords(self._rect, self._startx, 0, stopx, self._canv.winfo_height()) - self._canv.update_idletasks() - - def start(self): - self._running = True - self.after(self._interval, self._step) - - def stop(self): - self._running = False - self._set() - - def _step(self): - if self._running: - stepsize = self._barwidth / 4 - if stepsize < 2: - stepsize = 2 - self._startx += stepsize - self._set() - self.after(self._interval, self._step) diff --git a/DeDRM_plugin/_unused_scrolltextwidget.py b/DeDRM_plugin/_unused_scrolltextwidget.py deleted file mode 100644 index 5969ea1..0000000 --- a/DeDRM_plugin/_unused_scrolltextwidget.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -# I think this file is unused? - - -import tkinter -import tkinter.constants - -# basic scrolled text widget -class ScrolledText(tkinter.Text): - def __init__(self, master=None, **kw): - self.frame = tkinter.Frame(master) - self.vbar = tkinter.Scrollbar(self.frame) - self.vbar.pack(side=tkinter.constants.RIGHT, fill=tkinter.constants.Y) - kw.update({'yscrollcommand': self.vbar.set}) - tkinter.Text.__init__(self, self.frame, **kw) - self.pack(side=tkinter.constants.LEFT, fill=tkinter.constants.BOTH, expand=True) - self.vbar['command'] = self.yview - # Copy geometry methods of self.frame without overriding Text - # methods = hack! - text_meths = list(vars(tkinter.Text).keys()) - methods = list(vars(tkinter.Pack).keys()) + list(vars(tkinter.Grid).keys()) + list(vars(tkinter.Place).keys()) - methods = set(methods).difference(text_meths) - for m in methods: - if m[0] != '_' and m != 'config' and m != 'configure': - setattr(self, m, getattr(self.frame, m)) - - def __str__(self): - return str(self.frame) diff --git a/DeDRM_plugin/askfolder_ed.py b/DeDRM_plugin/askfolder_ed.py deleted file mode 100644 index 8c586fe..0000000 --- a/DeDRM_plugin/askfolder_ed.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -# to work around tk_chooseDirectory not properly returning unicode paths on Windows -# need to use a dialog that can be hacked up to actually return full unicode paths -# originally based on AskFolder from EasyDialogs for Windows but modified to fix it -# to actually use unicode for path - -# The original license for EasyDialogs is as follows -# -# Copyright (c) 2003-2005 Jimmy Retzlaff -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -# Adjusted for Python 3, September 2020 - -""" -AskFolder(...) -- Ask the user to select a folder Windows specific -""" - -import os - -import ctypes -from ctypes import POINTER, byref, cdll, c_int, windll -from ctypes.wintypes import LPCWSTR, LPWSTR -import ctypes.wintypes as wintypes - - -__all__ = ['AskFolder'] - -# Load required Windows DLLs -ole32 = ctypes.windll.ole32 -shell32 = ctypes.windll.shell32 -user32 = ctypes.windll.user32 - - -# Windows Constants -BFFM_INITIALIZED = 1 -BFFM_SETOKTEXT = 1129 -BFFM_SETSELECTIONA = 1126 -BFFM_SETSELECTIONW = 1127 -BIF_EDITBOX = 16 -BS_DEFPUSHBUTTON = 1 -CB_ADDSTRING = 323 -CB_GETCURSEL = 327 -CB_SETCURSEL = 334 -CDM_SETCONTROLTEXT = 1128 -EM_GETLINECOUNT = 186 -EM_GETMARGINS = 212 -EM_POSFROMCHAR = 214 -EM_SETSEL = 177 -GWL_STYLE = -16 -IDC_STATIC = -1 -IDCANCEL = 2 -IDNO = 7 -IDOK = 1 -IDYES = 6 -MAX_PATH = 260 -OFN_ALLOWMULTISELECT = 512 -OFN_ENABLEHOOK = 32 -OFN_ENABLESIZING = 8388608 -OFN_ENABLETEMPLATEHANDLE = 128 -OFN_EXPLORER = 524288 -OFN_OVERWRITEPROMPT = 2 -OPENFILENAME_SIZE_VERSION_400 = 76 -PBM_GETPOS = 1032 -PBM_SETMARQUEE = 1034 -PBM_SETPOS = 1026 -PBM_SETRANGE = 1025 -PBM_SETRANGE32 = 1030 -PBS_MARQUEE = 8 -PM_REMOVE = 1 -SW_HIDE = 0 -SW_SHOW = 5 -SW_SHOWNORMAL = 1 -SWP_NOACTIVATE = 16 -SWP_NOMOVE = 2 -SWP_NOSIZE = 1 -SWP_NOZORDER = 4 -VER_PLATFORM_WIN32_NT = 2 -WM_COMMAND = 273 -WM_GETTEXT = 13 -WM_GETTEXTLENGTH = 14 -WM_INITDIALOG = 272 -WM_NOTIFY = 78 - -# Windows function prototypes -BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, wintypes.HWND, ctypes.c_uint, wintypes.LPARAM, wintypes.LPARAM) - -# Windows types -LPCTSTR = ctypes.c_char_p -LPTSTR = ctypes.c_char_p -LPVOID = ctypes.c_voidp -TCHAR = ctypes.c_char - -class BROWSEINFO(ctypes.Structure): - _fields_ = [ - ("hwndOwner", wintypes.HWND), - ("pidlRoot", LPVOID), - ("pszDisplayName", LPTSTR), - ("lpszTitle", LPCTSTR), - ("ulFlags", ctypes.c_uint), - ("lpfn", BrowseCallbackProc), - ("lParam", wintypes.LPARAM), - ("iImage", ctypes.c_int) - ] - - -# Utilities -def CenterWindow(hwnd): - desktopRect = GetWindowRect(user32.GetDesktopWindow()) - myRect = GetWindowRect(hwnd) - x = width(desktopRect) // 2 - width(myRect) // 2 - y = height(desktopRect) // 2 - height(myRect) // 2 - user32.SetWindowPos(hwnd, 0, - desktopRect.left + x, - desktopRect.top + y, - 0, 0, - SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER - ) - - -def GetWindowRect(hwnd): - rect = wintypes.RECT() - user32.GetWindowRect(hwnd, ctypes.byref(rect)) - return rect - -def width(rect): - return rect.right-rect.left - -def height(rect): - return rect.bottom-rect.top - - -def AskFolder( - message=None, - version=None, - defaultLocation=None, - location=None, - windowTitle=None, - actionButtonLabel=None, - cancelButtonLabel=None, - multiple=None): - """Display a dialog asking the user for select a folder. - modified to use unicode strings as much as possible - returns unicode path - """ - - def BrowseCallback(hwnd, uMsg, lParam, lpData): - if uMsg == BFFM_INITIALIZED: - if actionButtonLabel: - label = str(actionButtonLabel, errors='replace') - user32.SendMessageW(hwnd, BFFM_SETOKTEXT, 0, label) - if cancelButtonLabel: - label = str(cancelButtonLabel, errors='replace') - cancelButton = user32.GetDlgItem(hwnd, IDCANCEL) - if cancelButton: - user32.SetWindowTextW(cancelButton, label) - if windowTitle: - title = str(windowTitle, errors='replace') - user32.SetWindowTextW(hwnd, title) - if defaultLocation: - user32.SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, defaultLocation.replace('/', '\\')) - if location: - x, y = location - desktopRect = wintypes.RECT() - user32.GetWindowRect(0, ctypes.byref(desktopRect)) - user32.SetWindowPos(hwnd, 0, - desktopRect.left + x, - desktopRect.top + y, 0, 0, - SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER) - else: - CenterWindow(hwnd) - return 0 - - # This next line is needed to prevent gc of the callback - callback = BrowseCallbackProc(BrowseCallback) - - browseInfo = BROWSEINFO() - browseInfo.pszDisplayName = ctypes.c_char_p('\0' * (MAX_PATH+1)) - browseInfo.lpszTitle = message - browseInfo.lpfn = callback - - pidl = shell32.SHBrowseForFolder(ctypes.byref(browseInfo)) - if not pidl: - result = None - else: - path = LPCWSTR(" " * (MAX_PATH+1)) - shell32.SHGetPathFromIDListW(pidl, path) - ole32.CoTaskMemFree(pidl) - result = path.value - return result - - - - diff --git a/DeDRM_plugin/ignoblekeyfetch.py b/DeDRM_plugin/ignoblekeyfetch.py deleted file mode 100644 index 278879b..0000000 --- a/DeDRM_plugin/ignoblekeyfetch.py +++ /dev/null @@ -1,265 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# ignoblekeyfetch.py -# Copyright © 2015-2020 Apprentice Harper et al. - -# Released under the terms of the GNU General Public Licence, version 3 -# - -# Based on discoveries by "Nobody You Know" -# Code partly based on ignoblekeygen.py by several people. - -# Windows users: Before running this program, you must first install Python. -# We recommend ActiveState Python 2.7.X for Windows from -# http://www.activestate.com/activepython/downloads. -# Then save this script file as ignoblekeyfetch.pyw and double-click on it to run it. -# -# Mac OS X users: Save this script file as ignoblekeyfetch.pyw. You can run this -# program from the command line (python ignoblekeyfetch.pyw) or by double-clicking -# it when it has been associated with PythonLauncher. - -# Revision history: -# 1.0 - Initial version -# 1.1 - Try second URL if first one fails -# 2.0 - Python 3 for calibre 5.0 - -""" -Fetch Barnes & Noble EPUB user key from B&N servers using email and password. - -NOTE: This script used to work in the past, but the server it uses is long gone. -It can no longer be used to download keys from B&N servers, it is no longer -supported by the Calibre plugin, and it will be removed in the future. - -""" - -__license__ = 'GPL v3' -__version__ = "2.0" - -import sys -import os - -# Wrap a stream so that output gets flushed immediately -# and also make sure that any unicode strings get -# encoded using "replace" before writing them. -class SafeUnbuffered: - def __init__(self, stream): - self.stream = stream - self.encoding = stream.encoding - if self.encoding == None: - self.encoding = "utf-8" - def write(self, data): - if isinstance(data,str) or isinstance(data,unicode): - # str for Python3, unicode for Python2 - data = data.encode(self.encoding,"replace") - try: - buffer = getattr(self.stream, 'buffer', self.stream) - # self.stream.buffer for Python3, self.stream for Python2 - buffer.write(data) - buffer.flush() - except: - # We can do nothing if a write fails - raise - def __getattr__(self, attr): - return getattr(self.stream, attr) - -try: - from calibre.constants import iswindows, isosx -except: - iswindows = sys.platform.startswith('win') - isosx = sys.platform.startswith('darwin') - -def unicode_argv(): - if iswindows: - # Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode - # strings. - - # Versions 2.x of Python don't support Unicode in sys.argv on - # Windows, with the underlying Windows API instead replacing multi-byte - # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv - # as a list of Unicode strings and encode them as utf-8 - - from ctypes import POINTER, byref, cdll, c_int, windll - from ctypes.wintypes import LPCWSTR, LPWSTR - - GetCommandLineW = cdll.kernel32.GetCommandLineW - GetCommandLineW.argtypes = [] - GetCommandLineW.restype = LPCWSTR - - CommandLineToArgvW = windll.shell32.CommandLineToArgvW - CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)] - CommandLineToArgvW.restype = POINTER(LPWSTR) - - cmd = GetCommandLineW() - argc = c_int(0) - argv = CommandLineToArgvW(cmd, byref(argc)) - if argc.value > 0: - # Remove Python executable and commands if present - start = argc.value - len(sys.argv) - return [argv[i] for i in - range(start, argc.value)] - # if we don't have any arguments at all, just pass back script name - # this should never happen - return ["ignoblekeyfetch.py"] - else: - argvencoding = sys.stdin.encoding or "utf-8" - return [arg if (isinstance(arg, str) or isinstance(arg,unicode)) else str(arg, argvencoding) for arg in sys.argv] - - -class IGNOBLEError(Exception): - pass - -def fetch_key(email, password): - # change email and password to utf-8 if unicode - if type(email)==str: - email = email.encode('utf-8') - if type(password)==str: - password = password.encode('utf-8') - - import random - random = "%030x" % random.randrange(16**30) - - import urllib.parse, urllib.request, re - - # try the URL from nook for PC - fetch_url = "https://cart4.barnesandnoble.com/services/service.aspx?Version=2&acctPassword=" - fetch_url += urllib.parse.quote(password,'')+"&devID=PC_BN_2.5.6.9575_"+random+"&emailAddress=" - fetch_url += urllib.parse.quote(email,"")+"&outFormat=5&schema=1&service=1&stage=deviceHashB" - #print fetch_url - - found = '' - try: - response = urllib.request.urlopen(fetch_url) - the_page = response.read() - #print the_page - found = re.search('ccHash>(.+?)(.+?) ".format(progname)) - return 1 - email, password, keypath = argv[1:] - userkey = fetch_key(email, password) - if len(userkey) == 28: - open(keypath,'wb').write(userkey) - return 0 - print("Failed to fetch key.") - return 1 - - -def gui_main(): - try: - import tkinter - import tkinter.filedialog - import tkinter.constants - import tkinter.messagebox - import traceback - except: - return cli_main() - - class DecryptionDialog(tkinter.Frame): - def __init__(self, root): - tkinter.Frame.__init__(self, root, border=5) - self.status = tkinter.Label(self, text="Enter parameters") - self.status.pack(fill=tkinter.constants.X, expand=1) - body = tkinter.Frame(self) - body.pack(fill=tkinter.constants.X, expand=1) - sticky = tkinter.constants.E + tkinter.constants.W - body.grid_columnconfigure(1, weight=2) - tkinter.Label(body, text="Account email address").grid(row=0) - self.name = tkinter.Entry(body, width=40) - self.name.grid(row=0, column=1, sticky=sticky) - tkinter.Label(body, text="Account password").grid(row=1) - self.ccn = tkinter.Entry(body, width=40) - self.ccn.grid(row=1, column=1, sticky=sticky) - tkinter.Label(body, text="Output file").grid(row=2) - self.keypath = tkinter.Entry(body, width=40) - self.keypath.grid(row=2, column=1, sticky=sticky) - self.keypath.insert(2, "bnepubkey.b64") - button = tkinter.Button(body, text="...", command=self.get_keypath) - button.grid(row=2, column=2) - buttons = tkinter.Frame(self) - buttons.pack() - botton = tkinter.Button( - buttons, text="Fetch", width=10, command=self.generate) - botton.pack(side=tkinter.constants.LEFT) - tkinter.Frame(buttons, width=10).pack(side=tkinter.constants.LEFT) - button = tkinter.Button( - buttons, text="Quit", width=10, command=self.quit) - button.pack(side=tkinter.constants.RIGHT) - - def get_keypath(self): - keypath = tkinter.filedialog.asksaveasfilename( - parent=None, title="Select B&N ePub key file to produce", - defaultextension=".b64", - filetypes=[('base64-encoded files', '.b64'), - ('All Files', '.*')]) - if keypath: - keypath = os.path.normpath(keypath) - self.keypath.delete(0, tkinter.constants.END) - self.keypath.insert(0, keypath) - return - - def generate(self): - email = self.name.get() - password = self.ccn.get() - keypath = self.keypath.get() - if not email: - self.status['text'] = "Email address not given" - return - if not password: - self.status['text'] = "Account password not given" - return - if not keypath: - self.status['text'] = "Output keyfile path not set" - return - self.status['text'] = "Fetching..." - try: - userkey = fetch_key(email, password) - except Exception as e: - self.status['text'] = "Error: {0}".format(e.args[0]) - return - if len(userkey) == 28: - open(keypath,'wb').write(userkey) - self.status['text'] = "Keyfile fetched successfully" - else: - self.status['text'] = "Keyfile fetch failed." - - root = tkinter.Tk() - root.title("Barnes & Noble ePub Keyfile Fetch v.{0}".format(__version__)) - root.resizable(True, False) - root.minsize(300, 0) - DecryptionDialog(root).pack(fill=tkinter.constants.X, expand=1) - root.mainloop() - return 0 - -if __name__ == '__main__': - if len(sys.argv) > 1: - sys.exit(cli_main()) - sys.exit(gui_main()) diff --git a/DeDRM_plugin/simpleprefs.py b/DeDRM_plugin/simpleprefs.py deleted file mode 100644 index bf8c5d4..0000000 --- a/DeDRM_plugin/simpleprefs.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -import sys -import os, os.path -import shutil - -class SimplePrefsError(Exception): - pass - -class SimplePrefs(object): - def __init__(self, target, description): - self.prefs = {} - self.key2file={} - self.file2key={} - for keyfilemap in description: - [key, filename] = keyfilemap - self.key2file[key] = filename - self.file2key[filename] = key - self.target = target + 'Prefs' - if sys.platform.startswith('win'): - try: - import winreg - except ImportError: - import _winreg as winreg - regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") - path = winreg.QueryValueEx(regkey, 'Local AppData')[0] - prefdir = path + os.sep + self.target - elif sys.platform.startswith('darwin'): - home = os.getenv('HOME') - prefdir = os.path.join(home,'Library','Preferences','org.' + self.target) - else: - # linux and various flavors of unix - home = os.getenv('HOME') - prefdir = os.path.join(home,'.' + self.target) - if not os.path.exists(prefdir): - os.makedirs(prefdir) - self.prefdir = prefdir - self.prefs['dir'] = self.prefdir - self._loadPreferences() - - def _loadPreferences(self): - filenames = os.listdir(self.prefdir) - for filename in filenames: - if filename in self.file2key: - key = self.file2key[filename] - filepath = os.path.join(self.prefdir,filename) - if os.path.isfile(filepath): - try : - data = file(filepath,'rb').read() - self.prefs[key] = data - except Exception as e: - pass - - def getPreferences(self): - return self.prefs - - def setPreferences(self, newprefs={}): - if 'dir' not in newprefs: - raise SimplePrefsError('Error: Attempt to Set Preferences in unspecified directory') - if newprefs['dir'] != self.prefs['dir']: - raise SimplePrefsError('Error: Attempt to Set Preferences in unspecified directory') - for key in newprefs: - if key != 'dir': - if key in self.key2file: - filename = self.key2file[key] - filepath = os.path.join(self.prefdir,filename) - data = newprefs[key] - if data != None: - data = str(data) - if data == None or data == '': - if os.path.exists(filepath): - os.remove(filepath) - else: - try: - file(filepath,'wb').write(data) - except Exception as e: - pass - self.prefs = newprefs - return