#!/usr/bin/env python
# XPIVersionLimitChanger.py by Pragmatk ayetee gmail dart com, 4/13/2009
# Takes filenames of .xpis on the commandline and changes the required
# version-tag in /install.rdf to a (hardcoded) user-specified value
# using XPath

import zipfile
from StringIO import StringIO	# omglol hacky, eh - trying to avoid saving to disk
from lxml import etree
from urllib2 import urlopen
import re
from sys import argv

files	= argv[1:]

changes	= { #Things to change in install.rdf
	"/*/*/*[name()='em:targetApplication']/*[name()='Description']/*[name()='em:minVersion']"	: '1.0',
	"/*/*/*[name()='em:targetApplication']/*[name()='Description']/*[name()='em:maxVersion']"	: '4.0',
}

def parseext(file):
	if not zipfile.is_zipfile(file): #only works on file names and "buffers" - no StringIO
		return '[-] %s is not a valid zip file!' % file

	print '[+] Opening %s' % file
	try:
		addon	= zipfile.ZipFile(file, 'a')
	except zipfile.BadZipfile:
		return '[-] %s is not a valid zip file!' % file
	except zipfile.LargeZipFile:
		return '[-] %s is too large for me!' % file
	else:
		print '[+] Opened %s!' % file

	filelist	= addon.namelist()
	if not 'install.rdf' in filelist:
		print addon.namelist()
		return '[-] Unable to find "install.rdf" in root of %s' % file

	try:
		rdf	= addon.read('install.rdf')
	except KeyError:
		return '[-] install.rdf not readable - is this really an ff extension?'
	except Error, RuntimeError:
		return '[-] Error exception thrown - was the zip handle closed?'
	else:
		try:
			doc	= etree.parse(StringIO(rdf))	#It's a bird! It's a plane! It's a file descriptor!

			for change in changes:
				apps	= doc.xpath(change)
				for i in apps:
					print '[+] Changing %s from %s to %s' % (doc.getpath(i), i.text, changes[change])
					i.text	= changes[change]
				
			addon.writestr('install.rdf', etree.tostring(doc, pretty_print=True))
		except Error, e:
			return '[-] Fuxxored changing: %s' % e.reason
		
	addon.close()
	return '[+] %s done and saved to disk' % file

for file in files:
	print parseext(file)
	print
print '[+] Done!'
