--- /dev/null
+#! /usr/bin/env python
+
+# ineptkeymac.py, version 1
+
+# This program runs on Mac OS X, version 10.6.2 and probably several other
+# versions. It uses Python 2.6, but it probably also runs on all versions
+# 2.x with x >= 5.
+
+# This program extracts the private RSA key for your ADE account in a
+# standard binary form (DER format) in a file of your choosing. Its purpose
+# is to make a backup of that key so that your legally bought ADE encoded
+# ebooks can be salvaged in case they would no longer be supported by ADE
+# software. No other usages are intended.
+
+# It has been tested with the key storage structure of ADE 1.7.1 and 1.7.2
+# and Sony Reader Library.
+
+# This software does not contain any encryption code. Its only use of
+# external encryption software is the use of openssl for the conversion of
+# the private key from pem to der format. It doesn't use encryption or
+# decryption, however.
+
+# You can run this program from the command line (python ineptkeymac.py
+# filename), or by doubleclicking when it has been associated with
+# Pythonlauncher. When no filename is given it will show a dialog to obtain one.
+
+from __future__ import with_statement
+
+__license__ = 'GPL v3'
+
+import sys
+import os
+import xml.etree.ElementTree as etree
+from contextlib import closing
+import Tkinter
+import Tkconstants
+import tkFileDialog
+from tkMessageBox import showerror
+from subprocess import Popen, PIPE
+import textwrap
+
+NS = 'http://ns.adobe.com/adept'
+ACTFILE = '~/Library/Application Support/Adobe/Digital Editions/activation.dat'
+HEADER = '-----BEGIN PRIVATE KEY-----\n'
+FOOTER = '\n-----END PRIVATE KEY-----\n'
+
+Gui = False
+
+def get_key():
+ '''Returns the private key as a binary string (DER format)'''
+ try:
+ filename = os.path.expanduser(ACTFILE)
+ tree = etree.parse(filename)
+ xpath = '//{%s}credentials/{%s}privateLicenseKey' % (NS, NS)
+ b64key = tree.findtext(xpath)
+ pemkey = HEADER + textwrap.fill(b64key, 64) + FOOTER
+
+ cmd = ['openssl', 'rsa', '-outform', 'der']
+ proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ stdout, stderr = proc.communicate(pemkey)
+
+ if proc.returncode != 0:
+ error("openssl error: " + stderr)
+ return None
+ return stdout
+
+ except IOError:
+ error("Can find keyfile. Maybe you should activate your Adobe ID.")
+ sys.exit(1)
+
+def store_key(key, keypath):
+ '''Store the key in the file given as keypath. If no keypath is given a
+ dialog will ask for one.'''
+
+ try:
+ if keypath is None:
+ keypath = get_keypath()
+ if not keypath: # Cancelled
+ return
+
+ with closing(open(keypath, 'wb')) as outf:
+ outf.write(key)
+
+ except IOError, e:
+ error("Can write keyfile: " + str(e))
+
+def get_keypath():
+ keypath = tkFileDialog.asksaveasfilename(
+ parent = None, title = 'Select file to store ADEPT key',
+ initialdir = os.path.expanduser('~/Desktop'),
+ initialfile = 'adeptkey.der',
+ defaultextension = '.der', filetypes = [('DER-encoded files', '.der'),
+ ('All Files', '.*')])
+ if keypath:
+ keypath = os.path.normpath(keypath)
+ return keypath
+
+def error(text):
+ print text
+ if Gui: showerror('Error!', text)
+
+def gui_main():
+ root = Tkinter.Tk()
+ root.iconify()
+ global Gui
+ Gui = True
+ store_key(get_key(), None)
+
+ return 0
+
+def main(argv=sys.argv):
+ progname = os.path.basename(argv[0])
+
+ if len(argv) == 1: # assume GUI if no argument given
+ return gui_main()
+ if len(argv) != 2:
+ print "usage: %s KEYFILE" % (progname,)
+ return 1
+
+ store_key(get_key(), argv[1])
+
+if __name__ == '__main__':
+ sys.exit(main())
#! /usr/bin/python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
-# For use with Topaz Scripts Version 2.3
+# For use with Topaz Scripts Version 2.4
class Unbuffered:
def __init__(self, stream):
'region.h' : (1, 'scalar_number', 0, 0),
'region.w' : (1, 'scalar_number', 0, 0),
+ 'empty_text_region' : (1, 'snippets', 1, 0),
+
'img' : (1, 'snippets', 1, 0),
'img.x' : (1, 'scalar_number', 0, 0),
'img.y' : (1, 'scalar_number', 0, 0),
self.gh = self.getData('info.glyph.h')
self.gw = self.getData('info.glyph.w')
self.guse = self.getData('info.glyph.use')
- self.count = len(self.guse)
+ if self.guse :
+ self.count = len(self.guse)
+ else :
+ self.count = 0
self.gvtx = self.getData('info.glyph.vtx')
self.glen = self.getData('info.glyph.len')
self.gdpi = self.getData('info.glyph.dpi')
self.vx = self.getData('info.vtx.x')
self.vy = self.getData('info.vtx.y')
self.vlen = self.getData('info.len.n')
- self.glen.append(len(self.vlen))
- self.gvtx.append(len(self.vx))
+ if self.vlen :
+ self.glen.append(len(self.vlen))
+ elif self.glen:
+ self.glen.append(0)
+ if self.vx :
+ self.gvtx.append(len(self.vx))
+ elif self.gvtx :
+ self.gvtx.append(0)
def getData(self, path):
result = None
--- /dev/null
+#!/usr/bin/env python
+# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
+
+import sys
+sys.path.append('lib')
+
+import os, os.path, urllib
+import subprocess
+from subprocess import Popen, PIPE, STDOUT
+import Tkinter
+import Tkconstants
+import tkFileDialog
+import tkMessageBox
+import subasyncio
+from subasyncio import Process
+from scrolltextwidget import ScrolledText
+
+class MainDialog(Tkinter.Frame):
+ def __init__(self, root):
+ Tkinter.Frame.__init__(self, root, border=5)
+ self.root = root
+ self.interval = 2000
+ self.p2 = None
+ self.status = Tkinter.Label(self, text='eReader eBook Conversion to PMLZ')
+ self.status.pack(fill=Tkconstants.X, expand=1)
+ body = Tkinter.Frame(self)
+ body.pack(fill=Tkconstants.X, expand=1)
+ sticky = Tkconstants.E + Tkconstants.W
+ body.grid_columnconfigure(1, weight=2)
+
+ Tkinter.Label(body, text='eBook PDB input file').grid(row=0, sticky=Tkconstants.E)
+ self.pdbpath = Tkinter.Entry(body, width=50)
+ self.pdbpath.grid(row=0, column=1, sticky=sticky)
+ cwd = os.getcwdu()
+ cwd = cwd.encode('utf-8')
+ self.pdbpath.insert(0, cwd)
+ button = Tkinter.Button(body, text="...", command=self.get_pdbpath)
+ button.grid(row=0, column=2)
+
+ Tkinter.Label(body, text='Name on CC').grid(row=1, sticky=Tkconstants.E)
+ self.name = Tkinter.StringVar()
+ self.nameinfo = Tkinter.Entry(body, width=40, textvariable=self.name)
+ self.nameinfo.grid(row=1, column=1, sticky=sticky)
+
+ Tkinter.Label(body, text='Last 8 digits of CC Number').grid(row=2, sticky=Tkconstants.E)
+ self.ccnum = Tkinter.StringVar()
+ self.ccinfo = Tkinter.Entry(body, width=10, textvariable=self.ccnum)
+ self.ccinfo.grid(row=2, column=1, sticky=sticky)
+
+ msg1 = 'Conversion Log \n\n'
+ self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=15, width=60, wrap=Tkconstants.WORD)
+ self.stext.grid(row=3, column=0, columnspan=2,sticky=sticky)
+ self.stext.insert(Tkconstants.END,msg1)
+
+ buttons = Tkinter.Frame(self)
+ buttons.pack()
+ self.sbotton = Tkinter.Button(
+ buttons, text="Start", width=10, command=self.convertit)
+ self.sbotton.pack(side=Tkconstants.LEFT)
+
+ Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
+ self.qbutton = Tkinter.Button(
+ buttons, text="Quit", width=10, command=self.quitting)
+ self.qbutton.pack(side=Tkconstants.RIGHT)
+
+ # read from subprocess pipe without blocking
+ # invoked every interval via the widget "after"
+ # option being used, so need to reset it for the next time
+ def processPipe(self):
+ poll = self.p2.wait('nowait')
+ if poll != None:
+ text = self.p2.readerr()
+ text += self.p2.read()
+ msg = text + '\n\n' + 'File successfully converted\n'
+ if poll != 0:
+ msg = text + '\n\n' + 'Error: Conversion Failed\n'
+ self.showCmdOutput(msg)
+ self.p2 = None
+ self.sbotton.configure(state='normal')
+ return
+ text = self.p2.readerr()
+ text += self.p2.read()
+ self.showCmdOutput(text)
+ # make sure we get invoked again by event loop after interval
+ self.stext.after(self.interval,self.processPipe)
+ return
+
+ # post output from subprocess in scrolled text widget
+ def showCmdOutput(self, msg):
+ if msg and msg !='':
+ msg = msg.encode('utf-8')
+ self.stext.insert(Tkconstants.END,msg)
+ self.stext.yview_pickplace(Tkconstants.END)
+ return
+
+ # run erdr2pml.py as a subprocess via pipes and collect stdout
+ def erdr(self, infile, name, ccnum):
+ # os.putenv('PYTHONUNBUFFERED', '1')
+ cmdline = 'python ./lib/erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum
+ if sys.platform[0:3] == 'win':
+ search_path = os.environ['PATH']
+ search_path = search_path.lower()
+ if search_path.find('python') >= 0:
+ cmdline = 'python lib\erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum
+ else :
+ cmdline = 'lib\erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum
+
+ cmdline = cmdline.encode(sys.getfilesystemencoding())
+ p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
+ return p2
+
+
+ def get_pdbpath(self):
+ pdbpath = tkFileDialog.askopenfilename(
+ parent=None, title='Select eReader PDB File',
+ defaultextension='.pdb', filetypes=[('eReader eBooks', '.pdb'),
+ ('All Files', '.*')])
+ if pdbpath:
+ pdbpath = os.path.normpath(pdbpath)
+ self.pdbpath.delete(0, Tkconstants.END)
+ self.pdbpath.insert(0, pdbpath)
+ return
+
+ def quitting(self):
+ # kill any still running subprocess
+ if self.p2 != None:
+ if (self.p2.wait('nowait') == None):
+ self.p2.terminate()
+ self.root.destroy()
+
+ # actually ready to run the subprocess and get its output
+ def convertit(self):
+ # now disable the button to prevent multiple launches
+ self.sbotton.configure(state='disabled')
+ pdbpath = self.pdbpath.get()
+ if not pdbpath or not os.path.exists(pdbpath):
+ self.status['text'] = 'Specified eBook file does not exist'
+ self.sbotton.configure(state='normal')
+ return
+ name = self.name.get()
+ if not name or name == '':
+ self.status['text'] = 'Your forgot to enter the Name on the CC'
+ self.sbotton.configure(state='normal')
+ return
+ ccnum = self.ccnum.get()
+ if not ccnum or ccnum == '':
+ self.status['text'] = 'Your forgot to enter the last 8 digits on the CC'
+ self.sbotton.configure(state='normal')
+ return
+
+ log = 'Command = "python erdr2pml.py --make-pmlz "\n'
+ log += 'PDB Path = "'+ pdbpath + '"\n'
+ log += 'Name = "' + name + '"\n'
+ log += 'Last 8 of CC = "' + ccnum + '"\n'
+ log += '\n\n'
+ log += 'Please Wait ...\n'
+ log = log.encode('utf-8')
+ self.stext.insert(Tkconstants.END,log)
+ self.p2 = self.erdr(pdbpath, name, ccnum)
+
+ # python does not seem to allow you to create
+ # your own eventloop which every other gui does - strange
+ # so need to use the widget "after" command to force
+ # event loop to run non-gui events every interval
+ self.stext.after(self.interval,self.processPipe)
+ return
+
+
+def main(argv=None):
+ root = Tkinter.Tk()
+ root.title('eReader PDB to PMLZ Conversion')
+ root.resizable(True, False)
+ root.minsize(300, 0)
+ MainDialog(root).pack(fill=Tkconstants.X, expand=1)
+ root.mainloop()
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
# 0.11 - fixups for using correct xml for footnotes and sidebars for use with Dropbook
# 0.12 - Fix added to prevent lowercasing of image names when the pml code itself uses a different case in the link name.
# 0.13 - change to unbuffered stdout for use with gui front ends
+# 0.14 - contributed enhancement to support --make-pmlz switch
-__version__='0.13'
+__version__='0.14'
# Import Psyco if available
try:
import sys
sys.stdout=Unbuffered(sys.stdout)
-import struct, binascii, zlib, os, os.path, urllib
+import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile
try:
from hashlib import sha1
# file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo)
+def usage():
+ print "Converts DRMed eReader books to PML Source"
+ print "Usage:"
+ print " erdr2pml [options] infile.pdb [outdir] \"your name\" credit_card_number "
+ print " "
+ print "Options: "
+ print " -h prints this message"
+ print " --make-pmlz create PMLZ instead of using output directory"
+ print " "
+ print "Note:"
+ print " if ommitted, outdir defaults based on 'infile.pdb'"
+ print " It's enough to enter the last 8 digits of the credit card number"
+ return
+
def main(argv=None):
global bookname
- if argv is None:
- argv = sys.argv
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"])
+ except getopt.GetoptError, err:
+ print str(err)
+ usage()
+ return 1
+ make_pmlz = False
+ zipname = None
+ for o, a in opts:
+ if o == "-h":
+ usage()
+ return 0
+ elif o == "--make-pmlz":
+ make_pmlz = True
+ zipname = ''
print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__
- if len(argv)!=4 and len(argv)!=5:
- print "Converts DRMed eReader books to PML Source"
- print "Usage:"
- print " erdr2pml infile.pdb [outdir] \"your name\" credit_card_number "
- print "Note:"
- print " if ommitted, outdir defaults based on 'infile.pdb'"
- print " It's enough to enter the last 8 digits of the credit card number"
+ if len(args)!=3 and len(args)!=4:
+ usage()
return 1
else:
- if len(argv)==4:
- infile, name, cc = argv[1], argv[2], argv[3]
+ if len(args)==3:
+ infile, name, cc = args[0], args[1], args[2]
outdir = infile[:-4] + '_Source'
- elif len(argv)==5:
- infile, outdir, name, cc = argv[1], argv[2], argv[3], argv[4]
+ elif len(args)==4:
+ infile, outdir, name, cc = args[0], args[1], args[2], args[3]
+
+ if make_pmlz :
+ # ignore specified outdir, use tempdir instead
+ outdir = tempfile.mkdtemp()
+
bookname = os.path.splitext(os.path.basename(infile))[0]
try:
import time
start_time = time.time()
convertEreaderToPml(infile, name, cc, outdir)
+
+ if make_pmlz :
+ import zipfile
+ import shutil
+ print " Creating PMLZ file"
+ zipname = infile[:-4] + '.pmlz'
+ myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False)
+ list = os.listdir(outdir)
+ for file in list:
+ localname = file
+ filePath = os.path.join(outdir,file)
+ if os.path.isfile(filePath):
+ myZipFile.write(filePath, localname)
+ elif os.path.isdir(filePath):
+ imageList = os.listdir(filePath)
+ localimgdir = os.path.basename(filePath)
+ for image in imageList:
+ localname = os.path.join(localimgdir,image)
+ imagePath = os.path.join(filePath,image)
+ if os.path.isfile(imagePath):
+ myZipFile.write(imagePath, localname)
+ myZipFile.close()
+ # remove temporary directory
+ shutil.rmtree(outdir)
+
end_time = time.time()
search_time = end_time - start_time
print 'elapsed time: %.2f seconds' % (search_time, )
- print 'output in %s' % outdir
+ if make_pmlz :
+ print 'output in %s' % zipname
+ else :
+ print 'output in %s' % outdir
print "done"
except ValueError, e:
print "Error: %s" % e