#(c) 2004-2008 Thunderstone Media, LLC
#Creative Commons Attribution-Noncommercial 3.0 United States License
#
#Python Developyment By:
#
#Ray Slakinski
#August Trometer

import iPXSettings
import sys, difflib
from types import *
from time import *

if sys.platform == 'darwin':
	from objc import *
	from Foundation import *

class SM (difflib.SequenceMatcher):
	def __helper(self, alo, ahi, blo, bhi, answer):
		# slightly modified from difflib to ignore blocks of one elt
		# this prevents weird ones like <del>Whe</><ins>Ocasio</>n<ins>ally</>
		i, j, k = x = self.find_longest_match(alo, ahi, blo, bhi)
		# a[alo:i] vs b[blo:j] unknown
		# a[i:i+k] same as b[j:j+k]
		# a[i+k:ahi] vs b[j+k:bhi] unknown
		if k:
			if alo < i and blo < j:
				self.__helper(alo, i, blo, j, answer)
			if k > 1: answer.append(x)
			if i+k < ahi and j+k < bhi:
				self.__helper(i+k, ahi, j+k, bhi, answer)
	
	_SequenceMatcher__helper = _SM__helper # python name mangling funniness
	

class HTTPHead:
	import urllib2, iPXSettings
	def __init__(self, url, username=None, password=None):
		self.reply = 302
		self.headers = []
		self.msg = ''
		setOpener()
		url = url.strip()
		url = url.replace(' ', '%20')
		req = urllib2.Request(url)
		req.add_header('User-Agent', iPXSettings.USER_AGENT)
		
		try:
			h = urllib2.urlopen(req)
			self.headers = h.info()
		except Exception, e:
			logIt(e)
	
	def getType(self):
		if self.headers.has_key('Content-Type') and self.reply == 200:
			return self.headers['Content-Type']
		else:
			return None
	
	def getLength(self):
		if self.headers.has_key('Content-Length') and self.reply == 200:
			return self.headers['Content-Length']
		else:
			return None
	
	def getName(self):
		import re
		from string import split
		
		newName = ''
		if self.headers.has_key('Content-Disposition') and self.reply == 200:
			if re.search('filename=', self.headers['Content-Disposition'], re.IGNORECASE):
				textSplit = self.headers['Content-Disposition'].split(';')
				for text in textSplit:
					if re.search('filename=', text, re.IGNORECASE):
						newNameSplit = text.split('=')
						newName = newNameSplit[len(newNameSplit) -1]
						newName = newName.replace('"', '')
		
		return newName

def stringCleaning(text):
	import re
	
	text = re.sub('[\\\\/?*:<>|;"\']','', text)
	text = text.strip()
	
	return text

def isTag(x): return x[0] == "<" and x[-1] == ">"

def stringDiff(a, b):
	from string import join
	"""@@@"""
	out = ''
	chars = 0
	a, b = ' '.join(html2list(a)), ' '.join(html2list(b))
	s = SM(None, a, b)
	a = ' '.join(html2list(a, b=1))
	for e in s.get_opcodes():
		if e[0] == "replace":
			out += "<del>" + a[e[1]:e[2]] + "</del>"
			out += "<ins>" + b[e[3]:e[4]] + "</ins>"
		elif e[0] == "delete":
			out += "<del>"+ a[e[1]:e[2]] +"</del>"
		elif e[0] == "insert":
			out += "<ins>"+b[e[3]:e[4]] +"</ins>"
		elif e[0] == "equal":
			chunk = b[e[3]:e[4]]
			if len(chunk) > chars: chars = len(chunk)
			out += chunk
		else:
			raise "Um, something's broken. I didn't expect a '" + `e[0]` + "'."
	return out

def textDiff(a, b):
	"""Takes in strings a and b and returns a human-readable HTML diff."""
	from string import join
	
	out = []
	a, b = html2list(a), html2list(b)
	s = difflib.SequenceMatcher(isTag, a, b)
	for e in s.get_opcodes():
		if e[0] == "replace":
			# @@ need to do something more complicated here
			# call textDiff but not for html, but for some html... ugh
			# gonna cop-out for now
			out.append("<span class='modified diff'>"+' '.join(b[e[3]:e[4]])+"</span>")
		elif e[0] == "delete":
			out.append("<del class='diff'>"+ ' '.join(a[e[1]:e[2]]) + "</del>")
		elif e[0] == "insert":
			out.append("<ins class='diff'>"+' '.join(b[e[3]:e[4]]) + "</ins>")
		elif e[0] == "equal":
			out.append(' '.join(b[e[3]:e[4]]))
		else:
			raise "Um, something's broken. I didn't expect a '" + `e[0]` + "'."
	return ' '.join(out)

def html2list(x, b=0):
	import string
	
	mode = 'char'
	cur = ''
	out = []
	for c in x:
		if mode == 'tag':
			if c == '>':
				if b: cur += ']'
				else: cur += c
				out.append(cur); cur = ''; mode = 'char'
			else: cur += c
		elif mode == 'char':
			if c == '<':
				out.append(cur)
				if b: cur = '['
				else: cur = c
				mode = 'tag'
			elif c in string.whitespace: out.append(cur); cur = ''
			else: cur += c
	out.append(cur)
	return filter(lambda x: x is not '', out)

def htmlDiff(a, b):
	f1, f2 = a.find('</head>'), a.find('</body>')
	ca = a[f1+len('</head>'):f2]
	
	f1, f2 = b.find('</head>'), b.find('</body>')
	cb = b[f1+len('</head>'):f2]
	
	r = textDiff(ca, cb)
	hdr = '<style type="text/css"><!-- ins{color: green} del{color:red}--></style></head>'
	return b[:f1] + hdr + r + b[f2:]

def getDirSize(dir):
	import os
	
	sizes = []
	os.path.walk(dir, calcDirSize, sizes)
	total = 0
	for size in sizes:
		total = total + size
	
	return (total)

def calcDirSize(arg, dir, files):
	import os
	
	for file in files:
		stats = os.stat(os.path.join(dir, file))
		size = stats[6]
		arg.append(size)

def HTML2Text(text):
	import htmlentitydefs
	flag = [1]
	cleanText = ''
	
	def stripfunc(c):
		if not flag[0]:
			if c == '>':
				flag[0] = 1
				return 0
		elif c == '<':
			flag[0] = 0
		return flag[0]
	
	cleanText = filter(stripfunc,text)
	
	# 039 isn't in the defs table for some reason.
	htmlentitydefs.codepoint2name[39] = 'quot'
	
	for key in htmlentitydefs.name2codepoint:
		if ('&%s;' % key) in cleanText:
			try:
				cleanText = cleanText.replace('&%s;' % key, unichr(htmlentitydefs.name2codepoint[key]))
			except:
				pass
	
		
	for key in htmlentitydefs.codepoint2name:
		if key < 100:
			if ('&#0%d;' % key) in cleanText:
				try:
					cleanText = cleanText.replace('&#0%d;' % key, unichr(key))
				except:
					pass
		if ('&#%d;' % key) in cleanText:
			try:
				cleanText = cleanText.replace('&#%d;' % key, unichr(key))
			except:
				pass
				
	cleanText = cleanText.strip()
	return cleanText

def text2Audio(text, saveDir, saveName):
	import os
	
	printMSG('Converting Text Entry To Audio...')
	logIt('Converting Text Entry To Audio...')
	cleanText = HTML2Text(text)
	cleanText = cleanText.replace('"', '')
	if sys.platform == 'darwin':
		try:
			f = open('/tmp/iPX-textToAudio.applescript', 'w')
			
			f.write('set theText to "%s"\r\n' % cleanText)
			f.write('set theFile to POSIX file "%s/%s\r\n' % (saveDir,saveName))
			f.write('say theText saving to theFile')
			f.close()
			
			os.popen('/usr/bin/osascript /tmp/iPX-textToAudio.applescript')
			return True
		except Exception, msg:
			logIt('text2Audio Error: %s' % msg)
			return False
	elif sys.platform == 'win32':
		try:
			import win32com.client
			import shutil
			
			speech = win32com.client.Dispatch('SAPI.SpVoice')
			file_stream = win32com.client.Dispatch('SAPI.SpFileStream')
		except Exception, msg:
			logIt('text2Audio Error: %s' % msg)
			return False
		
		logIt('Speech Modules Loaded...')
		
		try:
			file_stream.Format.Type = 6
			file_stream.Open(saveName, 3, True)
			speech.AudioOutputStream = file_stream
			if not speech.Speak(cleanText) == 1:
				return False
			file_stream.Close()
			if os.path.isfile('.\\%s' % saveName):
				shutil.move('.\\' + saveName, saveDir + '\\' + saveName)
			else:
				logIt('text2Audio Error: File was not properly created')
				return False
		except Exception, msg:
			logIt('text2Audio Error: %s' % msg)
			return False
		
		return True

def prepURL(url):
	url = url.replace('%3A', ':')
	url = url.replace('%2F', '/')
	
	if (url[:8] != 'https://'):
	    if (url[:7] != 'http://'):
	        url = 'http://%s' % url
	return url

def trimLog():
	import os, iPXSettings
	
	if os.path.isfile(iPXSettings.logFile):
		os.unlink(iPXSettings.logFile)

def genHash(data):
	import md5
	
	try:
		msg = data.encode('utf8')
	except:
		from binascii import hexlify
	
		msg = hexlify(data)
		msg = msg.encode('utf8')
	
	item = md5.new()
	item.update(msg)
	
	return item.hexdigest()

def logIt(incomingMsg):
	import os, iPXSettings
	
	try:
		if type(incomingMsg) is UnicodeType:
			incomingMsg = incomingMsg.encode('utf8')
		else:
			incomingMsg = str(incomingMsg)
		
		msg = '%s %s' % (strftime('[%H:%M:%S]',localtime()), incomingMsg)
		
		if iPXSettings.DEBUG:
			printMSG(msg)
		
		if os.path.isfile(iPXSettings.logFile):
			f = open(iPXSettings.logFile, 'a')
			f.write(msg + '\r\n')
			f.close()
		else:
			f = open(iPXSettings.logFile, 'w')
			f.write(msg + '\r\n')
			f.close()
	except Exception, msg:
		if iPXSettings.DEBUG:
			printMSG('Error Saving Log: %s' % msg)
		if os.path.isfile(iPXSettings.logFile):
			if iPXSettings.DEBUG:
				printMSG('Attempting to deleting old log file...')
			try:
				os.unlink(iPXSettings.logFile)
			except Exception, msg:
				if iPXSettings.DEBUG:
					printMSG('Error Deleting Log: ' + msg)

def latin1_to_ascii(unicrap):
    """This takes a UNICODE string and replaces Latin-1 characters with
        something equivalent in 7-bit ASCII. It returns a plain ASCII string.
        This function makes a best effort to convert Latin-1 characters into
        ASCII equivalents. It does not just strip out the Latin-1 characters.
        All characters in the standard 7-bit ASCII range are preserved.
        In the 8th bit range all the Latin-1 accented letters are converted
        to unaccented equivalents. Most symbol characters are converted to
        something meaningful. Anything not converted is deleted.
    """
    xlate={0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
        0xc6:'Ae', 0xc7:'C',
        0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E',
        0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
        0xd0:'Th', 0xd1:'N',
        0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
        0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
        0xdd:'Y', 0xde:'th', 0xdf:'ss',
        0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
        0xe6:'ae', 0xe7:'c',
        0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e',
        0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
        0xf0:'th', 0xf1:'n',
        0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
        0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
        0xfd:'y', 0xfe:'th', 0xff:'y',
        0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
        0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
        0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
        0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
        0xb1:'{+/-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
        0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
        0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>',
        0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
        0xd7:'*', 0xf7:'/'
        }
    
    r = ''
    for i in unicrap:
        if xlate.has_key(ord(i)):
            r += xlate[ord(i)]
        elif ord(i) >= 0x80:
            pass
        else:
            r += str(i)
    return r

def updatePlaylist(saveLocation, saveName, playList, customGenre, convertToAAC, makeBookmarkable):
	import os, iPXSettings, random
	
	location = ''
	iPXID = ''
	
	if sys.platform == 'darwin':
		if (convertToAAC):
			printMSG('Exporting to iTunes and converting to AAC...')
			logIt('Exporting to iTunes and converting to AAC...')
		else:
			printMSG('Exporting to iTunes...')
			logIt('Exporting to iTunes...')
		trackID = 0
		fullPath = saveLocation + '/' + saveName
		song = os.path.abspath(fullPath)
		while True:
			scriptName = '/tmp/iPX-iTunes-%d.scpt' % random.randint(1,90000)
			
			if not os.path.isfile(scriptName):
				break
		
		f = open(scriptName, 'w')
		
		# initial settings
		f.write('set thePlaylist to "%s"\r\n' % playList)
		f.write('set theFile to "%s"\r\n' % song)
		f.write('set theGenre to "%s"\r\n' % customGenre)
		f.write('set theTrackID to 0\r\n')
		f.write('property required_version : "4.0"\r\n')
		
		# if iTunes isn't open, open it in the background
		f.write('tell application "System Events"\r\n')
		f.write('if (not (exists process "iTunes")) then\r\n')
		f.write('tell application "iTunes"\r\n')
		f.write('set visible of front window to false\r\n')
		f.write('end tell\r\n')
		f.write('end if\r\n')
		f.write('end tell\r\n')
		
		f.write('set theFile to the POSIX file theFile\r\n')
		
		f.write('tell application "iTunes"\r\n')
		
		#
		# IMPORT TO ITUNES LIBRARY
		#
		f.write('with timeout of 1800 seconds\r\n')
		
		# move track to Library and get track object
		f.write('try\r\n')
		f.write('set theTrack to add theFile to library playlist 1 of source 1\r\n')
		f.write('on error theError\r\n')
		f.write('set theTrack to add theFile to library playlist 1\r\n')
		f.write('end try\r\n')
		f.write('end timeout\r\n')
		
		#
		# SET CUSTOM GENRE
		#
		if len(customGenre) > 0:
			f.write('try\r\n')
			f.write('set genre of theTrack to theGenre\r\n')
			f.write('end try\r\n')
		
		#
		# SET IPXID IN THE COMMENTS FIELD
		#
		iPXID = strftime('%M%Y%m%H%d%S',gmtime())
		
		f.write('set theComment to the comment of theTrack\r\n')
		
		f.write('set theCharacters to every character in theComment\r\n')
		f.write('set commentString to ""\r\n')
		f.write('repeat with aCharacter in theCharacters\r\n')
		f.write('if (count commentString) is less than 160 then\r\n')
		f.write('set commentString to commentString & aCharacter\r\n')
		f.write('end if\r\n')
		f.write('end repeat\r\n')
		f.write('set the comment of theTrack to commentString & "\r\r" & "[iPXID:%s]"\r\n' % iPXID)
		
		#
		# MAKE BOOKMARKABLE
		#
		f.write('with timeout of 1800 seconds\r\n')
		f.write('try\r\n')
		f.write('set this_version to the version as string\r\n')
		f.write('if this_version is greater than or equal to the required_version then\r\n')
		f.write('set bookmarkable of theTrack to true\r\n')
		f.write('end if\r\n')
		f.write('end try\r\n')
		f.write('end timeout\r\n')
		
		#
		# MOVE TO PLAYLIST
		#
		# Create playlist if it doesn't exist
		f.write('try\r\n')
		f.write('if (not (exists user playlist thePlaylist)) then\r\n')
		f.write('make new playlist with properties {name:thePlaylist}\r\n')
		f.write('end if\r\n')
		
		# move to the playlist
		f.write('duplicate theTrack to the playlist thePlaylist\r\n')
		f.write('end try\r\n')
		
		"""
		# update connected iPod
		f.write('try\r\n')
		f.write('set myPod to (name of some source whose kind is iPod)\r\n')
		f.write('update myPod\r\n')
		f.write('end try\r\n')
		"""
		
		f.write('return theTrack\r\n')
		f.write('end tell\r\n')
		
		f.close()
		
		ret_pipe = os.popen('/usr/bin/osascript %s' % scriptName)
		returnValue = ''
		returnValue = ret_pipe.readline()
		if len(returnValue) > 0:
			location = "iTunes"
			
			if (iPXSettings.deleteAudio > 0):
				logIt('Deleting: %s...' % fullPath)
				if os.path.isfile(fullPath):
					os.unlink(fullPath)
		else:
			printMSG('iTunes failed to update. Track left in Library')
			logIt('iTunes failed to update. Track left in Library')
			iPXID = ''
		if not iPXSettings.DEBUG:
			if os.path.isfile(scriptName):
				os.unlink(scriptName)
		else:
			logIt('Keeping script: %s' % scriptName)
	elif sys.platform == 'win32':
			import win32com.client
			import shutil
			if iPXSettings.Prefs['exportApp'] == 1:
				try:
					printMSG('Exporting to Windows Media Player...')
					logIt('Exporting to Windows Media Player...')
					
					wmp = win32com.client.Dispatch('WMPlayer.OCX.7')
					playlists = wmp.playlistCollection.getByName(playList)
					if playlists.count == 0:
						pl = wmp.playlistCollection.newPlaylist(playList)
					else:
						pl = playlists.item(0)
					media = wmp.newMedia('%s\\%s' % (saveLocation, saveName))
					if len(customGenre) > 0:
						# Can not set Genre on some media files
						try:
							media.setItemInfo('WM/Genre', customGenre)
						except:
							pass
					logIt('Adding Media File...')
					pl.appendItem(media)
					wmp.close()
					location = "WMP"
				except Exception, msg:
					logIt('Failed to export to Windows Media Player')
					logIt('ERRMSG: %s' % msg)
			else:
				try:
					if (convertToAAC):
						printMSG('Exporting to iTunes and converting to AAC...')
						logIt('Exporting to iTunes and converting to AAC...')
					else:
						printMSG('Exporting to iTunes...')
						logIt('Exporting to iTunes...')
					
					itunes = win32com.client.Dispatch('iTunes.Application')
					playlists = itunes.LibrarySource.Playlists
					pl = playlists.ItemByName(playList)
					if not pl:
						pl = itunes.CreatePlaylist(playList)
					
					if (convertToAAC):
						oldEncoder = itunes.CurrentEncoder
						itunes.CurrentEncoder = itunes.Encoders.ItemByName('AAC Encoder')
						handle = itunes.ConvertFile2('%s\\%s' % (saveLocation, saveName))
						while handle.InProgress:
							sleep(3)
						itunes.CurrentEncoder = oldEncoder
						for track in handle.Tracks:
							aacLocation = str(track.Location)
							if os.path.isfile(aacLocation):
								newAacLocation = aacLocation.replace('.m4a', '.m4b')
								shutil.copy(aacLocation, newAacLocation)
								track.Delete()
								os.unlink(aacLocation)
								handle = pl.AddFile(newAacLocation)
								try:
									while handle.InProgress:
										sleep(3)
								except:
									pass
					else:
						handle = pl.AddFile('%s\\%s' % (saveLocation, saveName))
						try:
							while handle.InProgress:
								sleep(3)
						except:
							pass
					for track in handle.Tracks:
						#
						# SET IPXID IN THE COMMENTS FIELD
						#
						iPXID = strftime('\r\n[iPXID:%M%Y%m%H%d%S]\r\n',gmtime())
						track.Comment = track.Comment + iPXID
						if len(customGenre) > 0:
							track.Genre = customGenre
					
					location = 'iTunes'
				except Exception, msg:
					logIt('Failed to export to iTunes')
					logIt('ERRMSG: %s' % msg)
	
	return iPXID, location


def updateiPhoto(saveLocation, saveName, photoAlbum, type):
	import os, iPXSettings, random
	
	printMSG( 'Exporting to iPhoto...')
	
	location = ''
	iPhotoID = 0
	iPXID = ''
	
	if sys.platform == 'darwin':
		fullPath = saveLocation + '/' + saveName
		
		while True:
			scriptName = '/tmp/iPX-iPhoto-%d.scpt' % random.randint(1,90000)
			
			if not os.path.isfile(scriptName):
				break
		
		f = open(scriptName, 'w')
		
		# base values
		f.write('set theAlbum to "%s"\r\n' % photoAlbum)
		f.write('set thePath to "%s"\r\n' % fullPath)
		
		f.write('tell application "iPhoto"\r\n')
		
		#create album if it doesn't exist
		f.write('if not (exists album theAlbum) then\r\n')
		f.write('new album name theAlbum\r\n')
		f.write('end if\r\n')
		
		#import the photo
		f.write('set thePhoto to thePath\r\n')
		f.write('import from thePhoto to album theAlbum\r\n')
		
		#get the photo location
		f.write('set importedPhoto to the last item in (every photo in the last import album)\r\n')
		
		#
		# SET IPXID IN THE COMMENTS FIELD
		#
		iPXID = strftime('%m%M%Y%H%d%S',gmtime())
		
		f.write('set theComment to the comment of importedPhoto\r\n')
		f.write('set the comment of importedPhoto to theComment & "\r\r" & "[iPXID:%s]"\r\n' % iPXID)
		
		# return the final Track Location
		f.write('return the (id of importedPhoto) mod (8 ^ 8) as integer\r\n')
		f.write('end tell\r\n')
		
		f.close()
		
		try:
			ret_pipe = os.popen('/usr/bin/osascript %s' % scriptName)
			iPhotoID = int(ret_pipe.readline())
		except:
			pass
		
		if (iPhotoID > 3):
			location = "iPhoto"
			
			if type == 0:
				if (iPXSettings.deleteImages > 0):
					logIt('Deleting: %s...' % fullPath)
					if os.path.isfile(fullPath):
						os.unlink(fullPath)
			elif type == 1:
				if (iPXSettings.deleteVideo > 0):
					logIt('Deleting: %s...' % fullPath)
					if os.path.isfile(fullPath):
						os.unlink(fullPath)
		
		else:
			printMSG('iPhoto failed to update. Image left in iPodderX Library')
			iPXID = ''
		if not iPXSettings.DEBUG:
			if os.path.isfile(scriptName):
				os.unlink(scriptName)
	
	# return the photoID of the file just added
	return iPXID, location

def detectFileType(fileName):
	import typeFile, re

	logIt('Detecting file type...')
	try:
	    fileType = typeFile.file(fileName)
	except Exception, msg:
	    logIt('Failed to detect type, using data')
	    logIt(msg)
	    fileType = 'data'
    
	if re.search('ascii', fileType, re.IGNORECASE):
	    f = open(fileName, 'r')
	    for line in f.readlines():
	        if re.search('<html>', line, re.IGNORECASE):
	            type = 'html'
	            break
	if re.search('xml', fileType, re.IGNORECASE):
	    f = open(fileName, 'r')
	    for line in f.readlines():
	        if re.search('<rss', line, re.IGNORECASE):
	            type = 'rss'
	            break
	        elif re.search('<opml', line, re.IGNORECASE):
	            type = 'opml'
	            break
    
	logIt('File type is %s' % fileType)
	return fileType

def readplist(pList):
	if sys.platform == 'darwin':
		try:
			plistObj = NSMutableDictionary.dictionary()
			plistObj = NSMutableDictionary.dictionaryWithContentsOfFile_(pList)
		except Exception, msg:
			logIt('Error reading plist: %s' % msg)
			plistObj = {}
	elif sys.platform == 'win32':
		import plistlib
		
		try:
			plistObj = plistlib.Plist.fromFile(file(pList))
		except:
			plistObj = plistlib.Plist()
	
	return plistObj

def writeplist(dictObj, plist):
	import os
	
	if sys.platform == 'darwin':
		try:
			dictObj.writeToFile_atomically_(plist, True)
		except Exception, msg:
			logIt('Error saving %s file' % plist)
			logIt('ERRMSG: %s' % msg)
			if os.path.isfile(plist):
				os.unlink(plist)
	elif sys.platform == 'win32':
		import plistlib
		
		dictObj.write(plist)

def checkReg():
	return 1

def checkDir(dir):
	import os
	
	if not os.path.isdir(dir):
		os.mkdir(dir)

def delTree(dir):
	import os
	
	for root, dirs, files in os.walk(dir, topdown=False):
		for name in files:
			os.remove(os.path.join(root, name))
		for name in dirs:
			os.rmdir(os.path.join(root, name))

def getHistory():
	import os, iPXSettings
	
	logIt('Getting history from history.dat...')
	guids = []
	
	if os.path.isfile(iPXSettings.historyFile):
		logIt('Found history.plist, converting to history.dat...')
		try:
			import plistlib
			
			tempHist = plistlib.Plist.fromFile(file(iPXSettings.historyFile))
		except Exception, msg:
			logIt('History file could not be read')
			logIt('ERRORMSG: %s' % msg)
			tempHist['downloadHistory'] = list('')
		
		try:
			if (len(tempHist['downloadHistory']) > 0):
				for historyItem in tempHist['downloadHistory']:
					if historyItem.has_key('encGUID'):
						guids.append(historyItem['encGUID'])
			
			try:
				os.unlink(iPXSettings.historyFile)
			except:
				pass
			
			for guid in guids:
				saveHistory(guid)
		except Exception, msg:
			logIt('ERRMSG: %s' % msg)
	else:
		import pickle
		
		try:
			if os.path.isfile(iPXSettings.newHistoryFile):	
				guids = pickle.load(open(iPXSettings.newHistoryFile))
		except:
			pass
	
	return guids

def saveHistory(encGUID):
	import pickle, iPXSettings
	
	if iPXSettings.ranHistCheck == False:
		iPXSettings.histGUIDs = getHistory()
		iPXSettings.ranHistCheck = True
	
	if not encGUID in iPXSettings.histGUIDs:
		logIt('Adding to history.dat: %s' % encGUID)
		iPXSettings.histGUIDs.append(encGUID)
		pickle.dump(iPXSettings.histGUIDs, open(iPXSettings.newHistoryFile,'w'))
	else:
		logIt('Entry already found in history.dat: %s' % encGUID)

def doPing(encURL, feedURL):
	import urllib, iPXSettings
	
	logIt('Sending Anonymous download feedback...')
	pingURL = 'http://directory.iPodderX.com/feedData/survey/files?url=%s&feed=%s' % (encURL, feedURL)
	
	try:
		class AppURLopener(urllib.FancyURLopener):
		    version = iPXSettings.USER_AGENT

		urllib._urlopener = AppURLopener()
		handle = urllib.urlopen(pingURL)
	except Exception, msg:
		logIt('ERRMSG: %s' % msg)

def printMSG(msg):
	import os
	try:
		print msg.encode('utf8')
		sys.stdout.flush()
	except Exception, msg:
		logIt('Failed to print console message')
		logIt('ERRMSG: %s' % msg)

def checkForScript():
	import iPXSettings, os
	
	if sys.platform == 'darwin':
		if not iPXSettings.progName  == 'iPodderX':
			if (int(os.popen('ps auxww | grep -i iPodderX.py | grep -i "progName==' + iPXSettings.progName +'" |grep -v /bin/sh | grep -w -v ps | wc -l','r').readline().strip()) > 1):
				printMSG('CHECK_ALREADY_RUNNING')
				for line in os.popen('ps auxww | grep -i iPodderX.py | grep -v /bin/sh | grep -w -v ps','r').readlines():
					logIt(line)
				return True
			else:
				return False
		else:
			if (int(os.popen('ps auxww | grep -i iPodderX.py |grep -v /bin/sh | grep -w -v ps | wc -l','r').readline().strip()) > 2):
				printMSG('CHECK_ALREADY_RUNNING')
				for line in os.popen('ps auxww | grep -i iPodderX.py | grep -v /bin/sh | grep -w -v ps','r').readlines():
					logIt(line)
				return True
			else:
				return False
	
	elif sys.platform == 'win32':
		pass

def getOpmlFeeds(url):
	import opmlparser, urllib, re
	 
	ompl_parser = opmlparser.OPMLParser()
	
	try:
		data =  urllib.urlopen(url).read()
		ompl_parser.feed(data)
	except Exception, msg:
		logIt('OPML Connect Error: %s' % msg)
	
	opmlFeeds = {}
	
	for node in ompl_parser:
		try:
			if re.search('rss', str(node.get('type')), re.IGNORECASE) or re.search('atom', str(node.get('type')), re.IGNORECASE):
				title = 'Unknown'
				if not str(node.get('title')) == 'None':
					title = str(node.get('title'))
				elif not str(node.get('text')) == 'None':
					title = str(node.get('text'))
				
				if not str(node.get('xmlUrl')) == 'None':
					opmlFeeds[title] = str(node.get('xmlUrl'))
				elif not str(node.get('url')) == 'None':
					opmlFeeds[title] = str(node.get('url'))
		
		except Exception, msg:
			logIt('OPML Error: %s' % msg)
	
	return opmlFeeds

def checkForUI():
	import os, iPXSettings
	
	if sys.platform == 'darwin':
		if (int(os.popen('ps auxww | grep -i /Contents/MacOS/%s | grep -w -v ps | wc -l' % iPXSettings.progName,'r').readline().strip()) > 1):
			return True
		else:
			return False
	
	elif sys.platform == 'win32':
		pass

def encrypt(plain):
	import pyDes, iPXSettings
	from binascii import hexlify
	
	key = iPXSettings.getVar('3DESKey')
	key = key.decode('rot-13')
	
	k = pyDes.triple_des(key)
	d = k.encrypt(plain.strip(), ' ')
	
	return hexlify(d)

def decrypt(ciph):
	import pyDes, iPXSettings
	from binascii import unhexlify
	
	ciph = unhexlify(ciph)
	key = iPXSettings.getVar('3DESKey')
	key = key.decode('rot-13')
	
	k = pyDes.triple_des(key)
	d = k.decrypt(ciph, ' ')
	
	return d

def isWhole(x):
	return x == math.floor(x)

def setProxy():
	import os, iPXSettings
	from string import split
	
	proxy = ''
	if sys.platform == 'darwin':
		import ic
		try:
			inetConfig = ic.IC()
			if 'UseHTTPProxy' in inetConfig and inetConfig['UseHTTPProxy']:
				if inetConfig.has_key('HTTPProxyHost'):
					proxy = 'http://%s' % inetConfig['HTTPProxyHost']
					iPXSettings.useProxyServer = inetConfig['HTTPProxyHost']
		except Exception, msg:
			logIt('Failed to detect OSX Proxy: %s' % msg)
	elif sys.platform == 'win32':
		if iPXSettings.useProxyServer:
			if iPXSettings.useProxyIE:
				try:
					import _winreg as winreg
					
					host_port = None
					
					# Try to grab current proxy settings from the registry
					regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
					'Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings')
					regval = winreg.QueryValueEx(regkey, 'ProxyServer')
					proxyEnabled = winreg.QueryValueEx(regkey, 'ProxyEnable')
					regkey.Close()
					regval = str(regval[0])
					proxyEnabled = proxyEnabled[0]
					if proxyEnabled:
						# Regval can be of two types:
						# - 'myproxy:3128' if one proxy for all protocols
						# - 'ftp=myftpproxy:3128;http=myhttpproxy:3128;...' if several different proxies
						values = regval.split(';')
						if len(values) > 1:
							for s in values:
								scheme, p = s.split('=')
								if scheme == 'http':
									host_port = p
									break
						else:
							host_port = values[0]
					
					# Split host and port
					if host_port is not None:
						t = host_port.split(':')
						host = t[0].strip()
						if host:
							try:
								port = int(t[1])
							except:
								port = 80
							
							proxy = '%s:%d' % (host, port)
							iPXSettings.proxyServer = host
							iPXSettings.proxyPort = str(port)
				
				except Exception, e:
					logIt('Proxy Detection Error: %s' % e)
			else:
				if iPXSettings.useProxyAuth:
					proxy = iPXSettings.proxyUsername + ':' + decrypt(iPXSettings.proxyPassword) + '@' + iPXSettings.proxyServer
					
					if len(iPXSettings.proxyPort) > 0:
						proxy = proxy + ':' + iPXSettings.proxyPort
				else:
					proxy = iPXSettings.proxyServer
					if len(iPXSettings.proxyPort) > 0:
						proxy = proxy + ':' + iPXSettings.proxyPort
			if len(proxy) > 0:
				proxy = 'http://' + proxy
	
	if len(proxy) > 0:
		os.environ["http_proxy"] = proxy
		os.environ["https_proxy"] = proxy
	else:
		iPXSettings.proxyServer = ''
		iPXSettings.proxyPort	= ''
	
	return proxy

def setOpener(url='', uName=None, pWord=''):
	import urlparse, base64, socket, urllib2, iPXSettings
	
	socket.setdefaulttimeout(30)
	
	headers = []
	host = urlparse.urlparse(url)[1]
	path = urlparse.urlparse(url)[2]
	
	headers.append(('User-Agent', iPXSettings.USER_AGENT))
	if iPXSettings.useProxyServer:
		if iPXSettings.useProxyAuth:
			user_pass = base64.encodestring('%s:%s' %(iPXSettings.proxyUsername,decrypt(iPXSettings.proxyPassword)))
			headers.append(('Proxy-authorization', 'Basic %s' % user_pass))
	
	opener = urllib2.build_opener()
	
	if not uName == None:
		webAuth = base64.encodestring('%s:%s' % (uName, pWord))
		headers.append(('Authorization', 'Basic ' + webAuth))
	
	opener.addheaders = headers
	urllib2.install_opener(opener)
	
	return opener

def getFileViaProxySSL(url, uName, pWord, justHead=False, dlProgress=False):
	import urlparse, base64, socket, httplib, urllib, os, iPXSettings, re
	from string import split
	
	host = urlparse.urlparse(url)[1]
	port=443
	filePath = urlparse.urlparse(url)[2]
	
	phost=iPXSettings.proxyServer
	pport=int(iPXSettings.proxyPort)
	
	if iPXSettings.SUPERDEBUG:
		logIt('Using Proxy: %s:%d' % (phost, pport))
	
	webAuth = base64.encodestring('%s:%s' % (uName, pWord))
	
	proxy_authorization = ''
	if iPXSettings.useProxyAuth:
		user=iPXSettings.proxyUsername
		passwd=decrypt(iPXSettings.proxyPassword)
		user_pass=base64.encodestring(user + ':' + passwd)
		proxy_authorization='Proxy-authorization: Basic '+user_pass+'\r\n'
	
	proxy_connect='CONNECT %s:%s HTTP/1.0\r\n'%(host,port)
	proxy_pieces=proxy_connect+proxy_authorization+'\r\n'
	if iPXSettings.SUPERDEBUG:
		print proxy_pieces
	
	try:
		#now connect, very simple recv and error checking
		proxy=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		proxy.settimeout(60)
		proxy.connect((phost,pport))
		proxy.sendall(proxy_pieces+'\r\n')
		response=proxy.recv(8192)
		status=response.split()[1]
		if status!='200':  raise Exception, 'Recieved HTTP Status Code: %d' % status
		
		#trivial setup for ssl socket
		ssl = socket.ssl(proxy, None, None)
		sock = httplib.FakeSocket(proxy, ssl)
		
		#initalize httplib and replace with your socket
		params = urllib.urlencode({})
		headers = {'Authorization':'Basic ' + webAuth, 'User-Agent':iPXSettings.USER_AGENT}
		h=httplib.HTTPConnection('localhost')
		h.sock=sock
		
		if justHead:
			saveName = None
			h.request("HEAD", url,headers=headers)
			respObj = h.getresponse()
			url = urlparse.urljoin(url, respObj.getheader('location', ''))
			saveName = url.split('/')[len(url.split('/'))-1]
			logIt(saveName)
			if respObj.status in (301,302,):
				url = urlparse.urljoin(url, respObj.getheader('location', ''))
				#filePath = urlparse.urlparse(url)[2]
				logIt('Redirecting to url: %s' % url)
			try:
				if not respObj.getheader('Content-Disposition') == None:
					if re.search('filename=', respObj.getheader('Content-Disposition'), re.IGNORECASE):
						textSplit = respObj.getheader('Content-Disposition')
						textSplit = textSplit.split(';')
						for text in textSplit:
							if re.search('filename=', text, re.IGNORECASE):
								logIt('Detected New Filename To Use:')
								newSaveNameSplit = text.split('=')
								newSaveName = newSaveNameSplit[len(newSaveNameSplit) -1]
								newSaveName = newSaveName.replace('"', '')
								logIt(newSaveName)
								saveName = newSaveName
			except Exception, msg:
				logIt('Content-Disposition Error: %s' % msg)
			
			return respObj.status, url, saveName
		else:
			h.request('GET', url, headers=headers)
	except Exception, msg:
		logIt('Connection Failed')
		logIt('ERRMSG: %s' % msg)
		return 0, None, None
	
	if dlProgress:
		import tempfile
		try:
			count = 0
			lastPercentDone = 0
			n = 1024   # number of bytes to read at a time
			fileSize = 0
			r=h.getresponse()
			if r.status == 200:
				fileSize = float(r.getheader('Content-Length', 0.00)) / 1024
				printMSG(';;1;;1;;100.00;;0.00')
				tmpFile = tempfile.mkstemp()
				tmpFileName = tmpFile[1]
				f = open(tmpFileName, 'ab')
				while True:
					a = r.read(n)
					f.write(a)
					if not a: break
					count += len(a)  # len(a) may not be same as n for final read
					
					percentDone = ((float(count) /1024) / fileSize) * 100
					if percentDone >= lastPercentDone + 1:
						lastPercentDone = percentDone
						printMSG(';;1;;1;;100.00;;%.2f' % percentDone)
				
				printMSG(';;1;;1;;100.00;;100.00')
				f.close()
				os.close(tmpFile[0])
				
				return 200, tmpFileName, r
			else:
				logIt('Recieved HTTP Code: %s' % r.status)
				return 0, None, None
		
		except Exception, msg:
			logIt('Connection Failed')
			logIt('ERRMSG: %s' % msg)
			return 0, None, None
	else:
		try:
			r=h.getresponse()
			data = r.read()
			if iPXSettings.SUPERDEBUG:
				print data
			return 200, data, None
		except Exception, msg:
			logIt('Connection Failed')
			logIt('ERRMSG: %s' % msg)
			return 0, '', None