import sqlite3
import sys, os, re
import glob
import ccl_bplist
import datetime
import plistlib
from parse3 import ParseProto
import codecs
import json
import sqlite3
import io
import sys
import csv
import pathlib
import shutil
import textwrap
import base64
from time import process_time

nl = '\n'
now = datetime.datetime.now()
currenttime = str(now.strftime('%Y-%m-%d_%A_%H%M%S'))
reportfolderbase = './ILEAPP_Reports_'+currenttime+'/'
base = '/ILEAPP_Reports_'+currenttime+'/'
temp = reportfolderbase+'temp/'

def logfunc(message=""):
	if pathlib.Path(reportfolderbase+'Script Logs/Screen Output.html').is_file():
		with open(reportfolderbase+'Script Logs/Screen Output.html', 'a', encoding='utf8') as a:
			print(message)
			a.write(message+'
')
	else:
		with open(reportfolderbase+'Script Logs/Screen Output.html', 'a', encoding='utf8') as a:
			print(message)
			a.write(message+'
')

def datark(filefound):
	logfunc(f'Data_ark.plist function executing.')
	try:
		os.makedirs(reportfolderbase+'Data_Ark/')
		with open(reportfolderbase+'Data_Ark/Data Ark.html','w') as f:
			f.write('')
			f.write('
Mobile Activation Report
')
			f.write(f'Data_ark.plist located at {filefound[0]}
')
			f.write('')
			f.write('
')
			f.write('')
			f.write(f'
')
			f.write(f'
Key	Values
')
			with open(filefound[0], 'rb') as fp:
				pl = plistlib.load(fp)
				for key, val in pl.items():
					f.write(f'
{key}	{val}
')
			f.write(f'
')
			logfunc(f'Data_ark.plist function completed')
	except:
		logfunc('Error in Sys Diagnose Network Preferences function.')

def mobilact(filefound):
	logfunc(f'Mobile Activation function executing.')
	try:
		linecount = 0
		hitcount = 0
		activationcount = 0
		filescounter = 0

		if os.path.exists(reportfolderbase+'SysDiagnose/'):
			pass
		else:
			os.makedirs(reportfolderbase+'SysDiagnose/')

		f =open(reportfolderbase+'SysDiagnose/Mobile Activation Logs.html','w')
		f.write('')
		f.write('
Mobile Activation Report
')
		f.write('Logs in private/var/mobile/Library/Logs/mobileactivationd/mobileactivationd.log.*
')

		for filename in filefound:
			file = open(filename, 'r', encoding='utf8' )
			filescounter = filescounter + 1

			for line in file:
				linecount += 1
				if 'perform_data_migration' in line:
					hitcount += 1
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					frombuild = txts[12]
					tobuild = txts[14]
					f.write("

" + day + " " + month + " " + year + " " + time + " Upgraded from " + frombuild + " to " + tobuild + " [line " + str(linecount) + "]")

				if 'MA: main: ____________________ Mobile Activation Startup _____________________' in line:
					activationcount += 1
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					f.write("

" + day + " " + month + " " + year + " " + time + " Mobile Activation Startup " + " [line " + str(linecount) + "]")

				if 'MA: main: build_version:' in line:
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					buildver = txts[11]
					f.write("
"+ day + " " + month + " " + year + " " + time + " Mobile Activation Build Version = " + buildver)

				if 'MA: main: hardware_model:' in line:
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					hwmodel = txts[11]
					f.write("
" + day + " " + month + " " + year + " " + time + " Mobile Activation Hardware Model = " + hwmodel)

				if 'MA: main: product_type:' in line:
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					prod = txts[11]
					f.write("
" + day + " " + month + " " + year + " " + time + " Mobile Activation Product Type = " + prod)

				if 'MA: main: device_class:' in line:
					#print("\n" + line)
					txts = line.split()
					#print(txts, linecount)
					#print(len(txts))
					dayofweek = txts[0]
					month = txts[1]
					day = txts[2]
					time = txts[3]
					year = txts[4]
					devclass = txts[11]
					f.write("
"+ day + " " + month + " " + year + " " + time + " Mobile Activation Device Class = " + devclass)
			file.close()
		f.write("

Found " + str(hitcount) + " Upgrade entries")
		f.write("
 Found " + str(activationcount) + " Mobile Activation Startup entries")
		f.write('')
		f.close()

		logfunc(f'Mobile Activation completed executing.')
	except:
		logfunc('Error in MobileActivation Logs section')

def bkupstate(filefound):
	logfunc(f'BackupStateInfo function executing.')
	try:
		if os.path.exists(reportfolderbase+'SysDiagnose/'):
			pass
		else:
			os.makedirs(reportfolderbase+'SysDiagnose/')

		f =open(reportfolderbase+'SysDiagnose/BackupStateInfo.txt','w')
		p = open(filefound[0], 'rb')
		plist = plistlib.load(p)
		#create html headers
		filedatahtml = open(reportfolderbase+'SysDiagnose/BackupStateInfo.html', mode='a+')
		filedatahtml.write('')
		filedatahtml.write('
BackupStateInfo Report
')
		filedatahtml.write ('')

		filedatahtml.write('
')
		filedatahtml.write(f'
BackupStateInfo Items
')

		pl = plist # This code taken from https://github.com/cheeky4n6monkey/iOS_sysdiagnose_forensic_scripts/blob/master/sysdiagnose-mobilebackup.py

		if 'BackupStateInfo' in pl.keys():
				for key, val in pl["BackupStateInfo"].items():
					#print("key = " + str(key) + ", val = " + str(val))
					if key == 'date':
						filedatahtml.write(f'
BackupStateInfo Date	{str(val)}
')
					if key == 'isCloud':
						filedatahtml.write(f'
BackupStateInfo isCloud	{str(val)}
')

		if 'RestoreInfo' in pl.keys():
			for key, val in pl["RestoreInfo"].items():
				if key == 'RestoreDate':
					filedatahtml.write(f'
RestoreInfo Date	{str(val)}
')
				if key == 'BackupBuildVersion':
					filedatahtml.write(f'
RestoreInfo BackupBuildVersion	{str(val)}
')
				if key == 'DeviceBuildVersion':
					filedatahtml.write(f'
RestoreInfo DeviceBuildVersion	{str(val)}
')
				if key == 'WasCloudRestore':
					filedatahtml.write(f'
RestoreInfo WasCloudRestore	{str(val)}
')
		filedatahtml.write('
')
		filedatahtml.write('
')

		filedatahtml.write('
')
		filedatahtml.write(f'
{filefound[0]}
')
		filedatahtml.write('
Key	Value
')

		for key, val in plist.items():
			f.write(f'{key}	{val}{nl}')
			filedatahtml.write(f'
{key}	{val}
')

		f.close()

		#close html footer
		filedatahtml.write('
')
		filedatahtml.close()
	except:
		logfunc('Error in BackupStateInfo function section')
	logfunc(f'BackupStateInfo function completed.')

def datausage(filefound):
	os.makedirs(reportfolderbase+'Data Usage/')
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
				DATETIME(ZPROCESS.ZTIMESTAMP + 978307200, 'unixepoch') AS "PROCESS TIMESTAMP",
				DATETIME(ZPROCESS.ZFIRSTTIMESTAMP + 978307200, 'unixepoch') AS "PROCESS FIRST TIMESTAMP",
				DATETIME(ZLIVEUSAGE.ZTIMESTAMP + 978307200, 'unixepoch') AS "LIVE USAGE TIMESTAMP",
				ZBUNDLENAME AS "BUNDLE ID",
				ZPROCNAME AS "PROCESS NAME",
				ZWIFIIN AS "WIFI IN",
				ZWIFIOUT AS "WIFI OUT",
				ZWWANIN AS "WWAN IN",
				ZWWANOUT AS "WWAN OUT",
				ZLIVEUSAGE.Z_PK AS "ZLIVEUSAGE TABLE ID"
			FROM ZLIVEUSAGE
			LEFT JOIN ZPROCESS ON ZPROCESS.Z_PK = ZLIVEUSAGE.ZHASPROCESS
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Data Usage - Zliveusage function executing')
			with open(reportfolderbase+'Data Usage/Zliveusage.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Zliveusage report
')
				f.write(f'Zliveusage entries: {usageentries}
')
				f.write(f'Zliveusage located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Process Timestamp	Process First Timestamp	Live Usage Timestamp	Bundle ID	Process Name	WIFI In	WIFI Out	WWAN IN	WWAN Out	Table ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}
')
				f.write(f'
')
				logfunc(f'Data Usage - Zliveusage function completed')
		else:
				logfunc('No Data Usage - Zliveusage available')
	except:
		logfunc('Error in Data Usage - Zliveusage section.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
				DATETIME(ZPROCESS.ZTIMESTAMP+ 978307200, 'unixepoch') AS "TIMESTAMP",
				DATETIME(ZPROCESS.ZFIRSTTIMESTAMP + 978307200, 'unixepoch') AS "PROCESS FIRST TIMESTAMP",
				ZPROCESS.ZPROCNAME AS "PROCESS NAME",
				ZPROCESS.ZBUNDLENAME AS "BUNDLE ID",
				ZPROCESS.Z_PK AS "ZPROCESS TABLE ID"
			FROM ZPROCESS
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Data Usage - Zprocess function executing')
			with open(reportfolderbase+'Data Usage/Zprocess.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Zprocess report
')
				f.write(f'Zprocess entries: {usageentries}
')
				f.write(f'Zprocess located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'

Process Timestamp	Process First Timestamp	Live Usage Timestamp	Bundle ID	Table ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}
')
				f.write(f'
')
				logfunc(f'Data Usage - Zprocess function completed')
		else:
				logfunc('No Data Usage - Zprocess available')
	except:
		logfunc('Error in Data Usage - Zprocess Section.')

def medlib(filefound):
	os.makedirs(reportfolderbase+'Media Library/')
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		select
		ext.title AS "Title",
		ext.media_kind AS "Media Type",
		itep.format AS "File format",
		ext.location AS "File",
		ext.total_time_ms AS "Total time (ms)",
		ext.file_size AS "File size",
		ext.year AS "Year",
		alb.album AS "Album Name",
		alba.album_artist AS "Artist",
		com.composer AS "Composer",
		gen.genre AS "Genre",
		art.artwork_token AS "Artwork",
		itev.extended_content_rating AS "Content rating",
		itev.movie_info AS "Movie information",
		ext.description_long AS "Description",
		ite.track_number AS "Track number",
		sto.account_id AS "Account ID",
		strftime('%d/%m/%Y %H:%M:%S', datetime(sto.date_purchased + 978397200,'unixepoch'))date_purchased,
		sto.store_item_id AS "Item ID",
		sto.purchase_history_id AS "Purchase History ID",
		ext.copyright AS "Copyright"
		from
		item_extra ext
		join item_store sto using (item_pid)
		join item ite using (item_pid)
		join item_stats ites using (item_pid)
		join item_playback itep using (item_pid)
		join item_video itev using (item_pid)
		left join album alb on sto.item_pid=alb.representative_item_pid
		left join album_artist alba on sto.item_pid=alba.representative_item_pid
		left join composer com on sto.item_pid=com.representative_item_pid
		left join genre gen on sto.item_pid=gen.representative_item_pid
		left join item_artist itea on sto.item_pid=itea.representative_item_pid
		left join artwork_token art on sto.item_pid=art.entity_pid
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Media Library function executing')
			with open(reportfolderbase+'Media Library/Media Library.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Media Library report
')
				f.write(f'Media Library entries: {usageentries}
')
				f.write(f'Media Library located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Title	Media Type	File Format	File	Total Time (ms)	File Size	Year	Album Name	Artist	Composer	Genre	Artwork	Content Rating	Movie Information	Description	Track Number	Account ID	Date Purchased	Item ID	Purchase History ID	Copyright
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}	{row[13]}	{row[14]}	{row[15]}	{row[16]}	{row[17]}	{row[18]}	{row[19]}	{row[20]}
')
				f.write(f'
')
				logfunc(f'Media Library function completed')
		else:
				logfunc('No Media Library available')
	except:
		logfunc('Error in Media Library Section.')

def accs(filefound):
	os.makedirs(reportfolderbase+'Accounts/')
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
		ZACCOUNTTYPEDESCRIPTION,
		ZUSERNAME,
		DATETIME(ZDATE+978307200,'UNIXEPOCH','UTC' ) AS 'ZDATE TIMESTAMP',
		ZACCOUNTDESCRIPTION,
		ZACCOUNT.ZIDENTIFIER,
		ZACCOUNT.ZOWNINGBUNDLEID
		FROM ZACCOUNT
		JOIN ZACCOUNTTYPE ON ZACCOUNTTYPE.Z_PK=ZACCOUNT.ZACCOUNTTYPE
		ORDER BY ZACCOUNTTYPEDESCRIPTION
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Account Data function executing')
			with open(reportfolderbase+'Accounts/Accounts.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Account Data report
')
				f.write(f'Account Data entries: {usageentries}
')
				f.write(f'Account Data located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Account Desc	Usermane	Timestamp	Description	Identifier	Bundle ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}
')
				f.write(f'
')
				logfunc(f'Account Data function completed')
		else:
				logfunc('No Account Data available')
	except:
		logfunc('Error in Account Data Section.')

def conndevices(filefound):
	with open(filefound[0], "rb") as f:
		data = f.read()

	logfunc(f'Connected devices function executing.')
	outpath = reportfolderbase +'Devices Connected/'
	os.mkdir(outpath)
	nl = '\n'

	userComps = ""

	logfunc("Data being interpreted for FRPD is of type: " + str(type(data)))
	x = type(data)
	byteArr = bytearray(data)
	userByteArr = bytearray()

	magicOffset = byteArr.find(b'\x01\x01\x80\x00\x00')
	magic = byteArr[magicOffset:magicOffset + 5]

	flag = 0

	if magic == b'\x01\x01\x80\x00\x00':
		logfunc("Found magic bytes in iTunes Prefs FRPD... Finding Usernames and Desktop names now")
		f = open(outpath+'DevicesConnected.html', 'w')
		f.write('')
		f.write(f'Artifact name and path: {filefound[0]}
')
		f.write(f'Usernames and Computer names:

')
		for x in range (int(magicOffset + 92), len(data)):
			if (data[x]) == 0:
				x = int(magicOffset) + 157
				if userByteArr.decode() == "":
					continue
				else:
					if flag == 0:
						userComps += userByteArr.decode() + " - "
						flag = 1
					else:
						userComps += userByteArr.decode() + "\n"
						flag = 0
					userByteArr = bytearray()
					continue
			else:
				char =  (data[x])
				userByteArr.append(char)

		logfunc(f'{userComps}{nl}')
		f.write(f'{userComps}
')
	f.write(f'')
	f.close()
	logfunc(f'Connected devices function completed. ')

def applicationstate(filefound):
	#iOSversion = versionf
	logfunc(f'ApplicationState.db queries executing.')
	outpath = reportfolderbase +'Application State/'

	try:
		os.mkdir(outpath)
		os.mkdir(outpath+"exported-dirty/")
		os.mkdir(outpath+"exported-clean/")
	except OSError:
		logfunc("Error making directories")

	freepath = 1

	for pathfile in filefound:
		if isinstance(pathfile, pathlib.PurePath):
			freepath = os.path.abspath(pathfile)
			if freepath.endswith('.db'):
				apstatefiledb = freepath
		elif pathfile.endswith('.db'):
			apstatefiledb = pathfile

	#connect sqlite databases
	db = sqlite3.connect(apstatefiledb)
	cursor = db.cursor()

	cursor.execute('''
		select
		application_identifier_tab.[application_identifier],
		kvs.[value]
		from kvs, key_tab,application_identifier_tab
		where
		key_tab.[key]='compatibilityInfo' and kvs.[key] = key_tab.[id]
		and application_identifier_tab.[id] = kvs.[application_identifier]
		order by application_identifier_tab.[id]
		''')

	all_rows = cursor.fetchall()

	#poner un try except por si acaso
	extension = '.bplist'
	count = 0

	for row in all_rows:
		bundleid = str(row[0])
		bundleidplist = bundleid+'.bplist'
		f = row[1]
		output_file = open(outpath+'/exported-dirty/'+bundleidplist, 'wb') #export dirty from DB
		output_file.write(f)
		output_file.close()

		g = open(outpath+'/exported-dirty/'+bundleidplist, 'rb')
		#plist = plistlib.load(g)

		plist = ccl_bplist.load(g)

		output_file = open(outpath+'exported-clean/'+bundleidplist, 'wb')
		output_file.write(plist)
		output_file.close()

	#create html headers
	filedatahtml = open(outpath+'Application State.html', mode='a+')
	filedatahtml.write('')
	filedatahtml.write('
iOS ApplicationState.db Report
')
	filedatahtml.write ('')
	filedatahtml.write('
')
	filedatahtml.write('
')
	filedatahtml.write(f'
{apstatefiledb}
')
	filedatahtml.write('
Bundle ID	Bundle Path	Sandbox Path
')

	for filename in glob.glob(outpath+'exported-clean/*.bplist'):
		p = open(filename, 'rb')
		#cfilename = os.path.basename(filename)
		plist = ccl_bplist.load(p)
		ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=False)#deserialize clean
		#logfunc(ns_keyed_archiver_obj)
		bid = (ns_keyed_archiver_obj['bundleIdentifier'])
		bpath = (ns_keyed_archiver_obj['bundlePath'])
		bcontainer = (ns_keyed_archiver_obj['bundleContainerPath'])
		bsandbox = (ns_keyed_archiver_obj['sandboxPath'])

		if bsandbox == '$null':
			bsandbox = ''
		if bcontainer == '$null':
			bcontainer = ''

		#csv report
		filedata = open(outpath+'ApplicationState_InstalledAppInfo.csv', mode='a+')
		filewrite = csv.writer(filedata, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
		filewrite.writerow([bid, bpath, bcontainer, bsandbox])
		count = count + 1
		filedata.close()

		#html report
		filedatahtml.write(f'
{bid}	{bpath}	{bsandbox}
')

		filemetadata = open(outpath+'ApplicationState_InstalledAppInfo_Path.txt', mode='w')
		filemetadata.write(f'Artifact name and file path: {apstatefiledb} ')
		filemetadata.close()

	#close html footer
	filedatahtml.write('
')
	filedatahtml.close()

	logfunc(f'Installed app GUIDs and app locations processed: {count}')
	logfunc(f'ApplicationState.db queries completed.')

def knowledgec(filefound):
	logfunc(f'Incepted bplist extractions in knowlwdgeC.db executing.')

	iOSversion = versionf
	supportediOS = ['11', '12', '13']

	if iOSversion not in supportediOS:
		logfunc ("Unsupported version"+iOSversion)
		return()

	extension = '.bplist'
	dump = True
	#create directories
	outpath = reportfolderbase+'KnowledgeC/'

	try:
		os.mkdir(outpath)
		os.mkdir(outpath+"clean/")
		os.mkdir(outpath+"/dirty")
	except OSError:
		logfunc("Error making directories")

	#connect sqlite databases
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()

	#variable initializations
	dirtcount = 0
	cleancount = 0
	intentc = {}
	intentv = {}

	cursor.execute('''
	SELECT
	Z_PK,
	Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION,
	Z_DKINTENTMETADATAKEY__INTENTCLASS,
	Z_DKINTENTMETADATAKEY__INTENTVERB
	FROM ZSTRUCTUREDMETADATA
	WHERE Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION is not null
	''')

	all_rows = cursor.fetchall()

	for row in all_rows:
		pkv = str(row[0])
		pkvplist = pkv+extension
		f = row[1]
		intentclass = str(row[2])
		intententverb = str(row[3])
		output_file = open(outpath+'/dirty/D_Z_PK'+pkvplist, 'wb') #export dirty from DB
		output_file.write(f)
		output_file.close()

		g = open(outpath+'/dirty/D_Z_PK'+pkvplist, 'rb')
		plistg = ccl_bplist.load(g)

		if (iOSversion == '11'):
			ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
			newbytearray = ns_keyed_archiver_obj
		if (iOSversion == '12'):
			ns_keyed_archiver_objg = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
			newbytearray = (ns_keyed_archiver_objg["NS.data"])
		if (iOSversion == '13'):
			ns_keyed_archiver_objg = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
			newbytearray = (ns_keyed_archiver_objg["NS.data"])

		dirtcount = dirtcount+1

		binfile = open(outpath+'/clean/C_Z_PK'+pkvplist, 'wb')
		binfile.write(newbytearray)
		binfile.close()

		#add to dictionaries
		intentc['C_Z_PK'+pkvplist] = intentclass
		intentv['C_Z_PK'+pkvplist] = intententverb

		cleancount = cleancount+1

	h = open(outpath+'/StrucMetadata.html', 'w')
	h.write('')
	h.write('
iOS ' + iOSversion + ' - KnowledgeC ZSTRUCTUREDMETADATA bplist report
')
	h.write ('')
	h.write('
')

	for filename in glob.glob(outpath+'/clean/*'+extension):
		p = open(filename, 'rb')
		cfilename = os.path.basename(filename)
		plist = ccl_bplist.load(p)
		ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)#deserialize clean
		#Get dictionary values
		A = intentc.get(cfilename)
		B = intentv.get(cfilename)

		if A is None:
			A = 'No value'
		if B is None:
			A = 'No value'

		#logfunc some values from clean bplist
		if iOSversion == '13':
			NSdata = (ns_keyed_archiver_obj['root']['intent']['backingStore']['bytes'])
		else:
			NSdata = (ns_keyed_archiver_obj["root"]["intent"]["backingStore"]["data"]["NS.data"])

		parsedNSData = ""
		#Default true
		if dump == True:
			nsdata_file = outpath+'/clean/'+cfilename+'_nsdata.bin'
			binfile = open(nsdata_file, 'wb')
			if iOSversion == '13':
				binfile.write(ns_keyed_archiver_obj['root']['intent']['backingStore']['bytes'])
			else:
				binfile.write(ns_keyed_archiver_obj["root"]["intent"]["backingStore"]["data"]["NS.data"])
			binfile.close()
			messages = ParseProto(nsdata_file)
			messages_json_dump = json.dumps(messages, indent=4, sort_keys=True, ensure_ascii=False)
			parsedNSData = str(messages_json_dump).encode(encoding='UTF-8',errors='ignore')

		NSstartDate = ccl_bplist.convert_NSDate((ns_keyed_archiver_obj["root"]["dateInterval"]["NS.startDate"]))
		NSendDate = ccl_bplist.convert_NSDate((ns_keyed_archiver_obj["root"]["dateInterval"]["NS.endDate"]))
		NSduration = ns_keyed_archiver_obj["root"]["dateInterval"]["NS.duration"]
		Siri = ns_keyed_archiver_obj["root"]["_donatedBySiri"]

		h.write(cfilename)
		h.write('
')
		h.write('Intent Class: '+str(A))
		h.write('
')
		h.write('Intent Verb: '+str(B))
		h.write('
')
		h.write('
')

		h.write('
')
		h.write('Data type	')
		h.write('Value	')
		h.write('
')

		#Donated by Siri
		h.write('
')
		h.write('Siri	')
		h.write(''+str(Siri)+'	')
		h.write('
')

		#NSstartDate
		h.write('
')
		h.write('NSstartDate	')
		h.write(''+str(NSstartDate)+' Z	')
		h.write('
')

		#NSsendDate
		h.write('
')
		h.write('NSendDate	')
		h.write(''+str(NSendDate)+' Z	')
		h.write('
')

		#NSduration
		h.write('
')
		h.write('NSduration	')
		h.write(''+str(NSduration)+'	')
		h.write('
')

		#NSdata
		h.write('
')
		h.write('NSdata	')
		h.write(''+str(NSdata)+'	')
		h.write('
')

		#NSdata better formatting
		if parsedNSData:
			h.write('
')
			h.write('NSdata - Protobuf Decoded	')
			h.write('
'+str(parsedNSData).replace('\\n', '
')+'
	')
			h.write('
')
		else:
			#This will only run if -nd is used
			h.write('
')
			h.write('NSdata - Protobuf	')
			h.write(''+str(NSdata).replace('\\n', '
')+'	')
			h.write('
')

		h.write('
')
		h.write('
')

		#logfunc(NSstartDate)
		#logfunc(NSendDate)
		#logfunc(NSduration)
		#logfunc(NSdata)
		#logfunc('')

	logfunc("")
	logfunc("iOS - KnowledgeC ZSTRUCTUREDMETADATA bplist extractor")
	logfunc("By: @phillmoore & @AlexisBrignoni")
	logfunc("thinkdfir.com & abrignoni.com")
	logfunc("")
	logfunc("Bplists from the Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION field.")
	logfunc("Exported bplists (dirty): "+str(dirtcount))
	logfunc("Exported bplists (clean): "+str(cleancount))
	logfunc("")
	logfunc(f'Triage report completed.')
	logfunc('Incepted bplist extractions in knowlwdgeC.db completed')

	logfunc(f'KnowledgeC.db App Usage executing')

	#outpath = reportfolderbase+'KnowledgeC App Use/'

	#connect sqlite databases
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()

	cursor.execute('''
	SELECT
	datetime(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "ENTRY CREATION",
	CASE ZOBJECT.ZSTARTDAYOFWEEK
		WHEN "1" THEN "Sunday"
		WHEN "2" THEN "Monday"
		WHEN "3" THEN "Tuesday"
		WHEN "4" THEN "Wednesday"
		WHEN "5" THEN "Thursday"
		WHEN "6" THEN "Friday"
		WHEN "7" THEN "Saturday"
	END "DAY OF WEEK",
	ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
	datetime(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "START",
	datetime(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "END",
	(ZOBJECT.ZENDDATE-ZOBJECT.ZSTARTDATE) as "USAGE IN SECONDS",
	ZOBJECT.ZSTREAMNAME,
	ZOBJECT.ZVALUESTRING
	FROM ZOBJECT
	WHERE ZSTREAMNAME IS "/app/inFocus"
	ORDER BY "START"	''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/App Usage.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
iOS ' + iOSversion + ' - KnowledgeC App Usage report
')
		f.write(f'KnowledgeC App Usage entries: {usageentries}
')
		f.write(f'KnowledgeC located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Entry Creation	Day of Week	GMT Offset	Start	End	Usage in Seconds	ZSTREAMNAME	ZVALUESTRING
')
		for row in all_rows:
			ec = row[0]
			dw = row[1]
			go = row[2]
			st = row[3]
			en = row[4]
			us = row[5]
			zs = row[6]
			zv = row[7]
			f.write(f'
{ec}	{dw}	{go}	{st}	{en}	{us}	{zs}	{zv}
')
		f.write(f'
')
	logfunc(f'KnowledgeC App Usage completed')
	logfunc(f'KnowledgeC App Activity Executing')
	#connect sqlite databases
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()

	cursor.execute('''
	SELECT
	datetime(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "ENTRY CREATION",
		CASE ZOBJECT.ZSTARTDAYOFWEEK
		WHEN "1" THEN "Sunday"
		WHEN "2" THEN "Monday"
		WHEN "3" THEN "Tuesday"
		WHEN "4" THEN "Wednesday"
		WHEN "5" THEN "Thursday"
		WHEN "6" THEN "Friday"
		WHEN "7" THEN "Saturday"
	END "DAY OF WEEK",
	datetime(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "START",
	datetime(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "END",
	ZOBJECT.ZSTREAMNAME,
	ZOBJECT.ZVALUESTRING,
	ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__ACTIVITYTYPE AS "ACTIVITY TYPE",
	ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__TITLE as "TITLE",
	datetime(ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__EXPIRATIONDATE+978307200,'UNIXEPOCH', 'LOCALTIME') as "EXPIRATION DATE",
	ZSTRUCTUREDMETADATA.Z_DKAPPLICATIONACTIVITYMETADATAKEY__ITEMRELATEDCONTENTURL as "CONTENT URL",
	datetime(ZSTRUCTUREDMETADATA.ZCOM_APPLE_CALENDARUIKIT_USERACTIVITY_DATE+978307200,'UNIXEPOCH', 'LOCALTIME')  as "CALENDAR DATE",
	datetime(ZSTRUCTUREDMETADATA.ZCOM_APPLE_CALENDARUIKIT_USERACTIVITY_ENDDATE+978307200,'UNIXEPOCH', 'LOCALTIME')  as "CALENDAR END DATE"
	FROM ZOBJECT
	left join ZSTRUCTUREDMETADATA on ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
	left join ZSOURCE on ZOBJECT.ZSOURCE = ZSOURCE.Z_PK
	WHERE ZSTREAMNAME is "/app/activity"
	ORDER BY "ENTRY CREATION"''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/App Activity.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
iOS ' + iOSversion + ' - KnowledgeC App Activity report
')
		f.write(f'KnowledgeC App Activity entries: {usageentries}
')
		f.write(f'KnowledgeC located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Entry Creation	Day of Week	Start	End	ZSTREAMNAME	ZVALUESTRING	Activity Type	Title	Expiration Date	Content URL	Calendar Date	Calendar End Date
')
		for row in all_rows:
			ec = row[0]
			dw = row[1]
			st = row[2]
			en = row[3]
			zs = row[4]
			zv = row[5]
			tl = row[6]
			ed = row[7]
			cu = row[8]
			cd = row[9]
			ce = row[10]
			ced = row[11]
			f.write(f'
{ec}	{dw}	{st}	{en}	{zs}	{zv}	{tl}	{ed}	{cu}	{cd}	{ce}	{ced}
')
		f.write(f'
')
	logfunc(f'KnowledgeC App Activity completed')

	logfunc(f'KnowledgeC App in Focus executing')
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()

	cursor.execute('''
	SELECT
	ZOBJECT.ZVALUESTRING AS "BUNDLE ID",
	(ZOBJECT.ZENDDATE-ZOBJECT.ZSTARTDATE) as "USAGE IN SECONDS",
	CASE ZOBJECT.ZSTARTDAYOFWEEK
	    WHEN "1" THEN "Sunday"
	    WHEN "2" THEN "Monday"
	    WHEN "3" THEN "Tuesday"
	    WHEN "4" THEN "Wednesday"
	    WHEN "5" THEN "Thursday"
	    WHEN "6" THEN "Friday"
	    WHEN "7" THEN "Saturday"
	END "DAY OF WEEK",
	ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
	DATETIME(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH') as "START",
	DATETIME(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH') as "END",
	DATETIME(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH') as "ENTRY CREATION",
	ZOBJECT.Z_PK AS "ZOBJECT TABLE ID"
	FROM ZOBJECT
	WHERE ZSTREAMNAME IS "/app/inFocus"''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/App in Focus.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
iOS ' + iOSversion + ' - KnowledgeC App App in Focus report
')
		f.write(f'KnowledgeC App in Focus entries: {usageentries}
')
		f.write(f'KnowledgeC located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Bundle ID	Usage in Seconds	Day of the Week	GMT Offset	Start	End	Entry Creation	ZOBJECT Table ID
')
		for row in all_rows:
			f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}
')
		f.write(f'
')
		logfunc(f'KnowledgeC App in Focus completed')

	logfunc(f'KnowledgeC App Battery Level executing')
	cursor.execute('''
	SELECT
			ZOBJECT.ZVALUEDOUBLE as "BATTERY LEVEL",
			(ZOBJECT.ZENDDATE - ZOBJECT.ZSTARTDATE) AS "USAGE IN SECONDS",
			CASE ZOBJECT.ZSTARTDAYOFWEEK
				WHEN "1" THEN "Sunday"
				WHEN "2" THEN "Monday"
				WHEN "3" THEN "Tuesday"
				WHEN "4" THEN "Wednesday"
				WHEN "5" THEN "Thursday"
				WHEN "6" THEN "Friday"
				WHEN "7" THEN "Saturday"
			END "DAY OF WEEK",
			ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
			DATETIME(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH') as "START",
			DATETIME(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH') as "END",
			DATETIME(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH') as "ENTRY CREATION",
			ZOBJECT.Z_PK AS "ZOBJECT TABLE ID"
		FROM
			ZOBJECT
			LEFT JOIN
				ZSTRUCTUREDMETADATA
				ON ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
			LEFT JOIN
				ZSOURCE
				ON ZOBJECT.ZSOURCE = ZSOURCE.Z_PK
		WHERE
			ZSTREAMNAME LIKE "/device/BatteryPercentage"
	''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/Battery Level.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
KnowledgeC Battery Level report
')
		f.write(f'KnowledgeC Battery Level entries: {usageentries}
')
		f.write(f'KnowledgeC Battery Level located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Battery Level	Usage in Seconds	Day of the Week	GMT Offset	Start	End	Entry Creation	ZOBJECT Table ID
')
		for row in all_rows:
			f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}
')
		f.write(f'
')
		logfunc(f'KnowledgeC App Battery Level completed')

	logfunc(f'KnowledgeC Apps Installed executing')
	cursor.execute('''
	SELECT
			ZOBJECT.ZVALUESTRING AS "BUNDLE ID",
			CASE ZOBJECT.ZSTARTDAYOFWEEK
				WHEN "1" THEN "Sunday"
				WHEN "2" THEN "Monday"
				WHEN "3" THEN "Tuesday"
				WHEN "4" THEN "Wednesday"
				WHEN "5" THEN "Thursday"
				WHEN "6" THEN "Friday"
				WHEN "7" THEN "Saturday"
			END "DAY OF WEEK",
			ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
			DATETIME(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH') as "START",
			DATETIME(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH') as "END",
			DATETIME(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH') as "ENTRY CREATION",
			ZOBJECT.Z_PK AS "ZOBJECT TABLE ID"
		FROM
		   ZOBJECT
		   LEFT JOIN
		      ZSTRUCTUREDMETADATA
		      ON ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
		   LEFT JOIN
		      ZSOURCE
		      ON ZOBJECT.ZSOURCE = ZSOURCE.Z_PK
		WHERE ZSTREAMNAME is "/app/install"
	''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/Apps Installed.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
KnowledgeC Apps Installed report
')
		f.write(f'KnowledgeC Apps Installed : {usageentries}
')
		f.write(f'KnowledgeC Apps Installed located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Bundle ID	Day of the Week	GMT Offset	Start	End	Entry Creation
')
		for row in all_rows:
			f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}
')
		f.write(f'
')
		logfunc(f'KnowledgeC Apps Installed completed')

	logfunc(f'KnowledgeC Device Locked executing')
	cursor.execute('''
	SELECT
			CASE ZOBJECT.ZVALUEINTEGER
				WHEN '0' THEN 'UNLOCKED'
				WHEN '1' THEN 'LOCKED'
			END "IS LOCKED",
			(ZOBJECT.ZENDDATE - ZOBJECT.ZSTARTDATE) AS "USAGE IN SECONDS",
			CASE ZOBJECT.ZSTARTDAYOFWEEK
				WHEN "1" THEN "Sunday"
				WHEN "2" THEN "Monday"
				WHEN "3" THEN "Tuesday"
				WHEN "4" THEN "Wednesday"
				WHEN "5" THEN "Thursday"
				WHEN "6" THEN "Friday"
				WHEN "7" THEN "Saturday"
			END "DAY OF WEEK",
			ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
			DATETIME(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH') as "START",
			DATETIME(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH') as "END",
			DATETIME(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH') as "ENTRY CREATION",
			ZOBJECT.Z_PK AS "ZOBJECT TABLE ID"
		FROM
			ZOBJECT
			LEFT JOIN
				ZSTRUCTUREDMETADATA
				ON ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
			LEFT JOIN
				ZSOURCE
				ON ZOBJECT.ZSOURCE = ZSOURCE.Z_PK
		WHERE
			ZSTREAMNAME LIKE "/device/isLocked"
	''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/Device Locked.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
KnowledgeC Device Locked report
')
		f.write(f'KnowledgeC Device Locked: {usageentries}
')
		f.write(f'KnowledgeC Device Locked located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Is Locked?	Usage in Seconds	Day of the Week	GMT Offset	Start	End	Entry Creation
')
		for row in all_rows:
			f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}
')
		f.write(f'
')
		logfunc(f'KnowledgeC Device Locked completed')

	logfunc(f'KnowledgeC Plugged In executing')
	cursor.execute('''
	SELECT
			CASE
			ZOBJECT.ZVALUEINTEGER
				WHEN '0' THEN 'UNPLUGGED'
				WHEN '1' THEN 'PLUGGED IN'
			END "IS PLUGGED IN",
			(ZOBJECT.ZENDDATE - ZOBJECT.ZSTARTDATE) AS "USAGE IN SECONDS",
			CASE ZOBJECT.ZSTARTDAYOFWEEK
				WHEN "1" THEN "Sunday"
				WHEN "2" THEN "Monday"
				WHEN "3" THEN "Tuesday"
				WHEN "4" THEN "Wednesday"
				WHEN "5" THEN "Thursday"
				WHEN "6" THEN "Friday"
				WHEN "7" THEN "Saturday"
			END "DAY OF WEEK",
			ZOBJECT.ZSECONDSFROMGMT/3600 AS "GMT OFFSET",
			DATETIME(ZOBJECT.ZSTARTDATE+978307200,'UNIXEPOCH') as "START",
			DATETIME(ZOBJECT.ZENDDATE+978307200,'UNIXEPOCH') as "END",
			DATETIME(ZOBJECT.ZCREATIONDATE+978307200,'UNIXEPOCH') as "ENTRY CREATION",
			ZOBJECT.Z_PK AS "ZOBJECT TABLE ID"
		FROM
			ZOBJECT
			LEFT JOIN
				ZSTRUCTUREDMETADATA
				ON ZOBJECT.ZSTRUCTUREDMETADATA = ZSTRUCTUREDMETADATA.Z_PK
			LEFT JOIN
				ZSOURCE
				ON ZOBJECT.ZSOURCE = ZSOURCE.Z_PK
		WHERE
			ZSTREAMNAME LIKE "/device/isPluggedIn"
	''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)

	with open(reportfolderbase+'KnowledgeC/Plugged In.html', 'w', encoding='utf8') as f:
		f.write('')
		f.write('
KnowledgeC Plugged In report
')
		f.write(f'KnowledgeC Device Plugged In entries: {usageentries}
')
		f.write(f'KnowledgeC Device Plugged In located at: {filefound[0]}
')
		f.write('')
		f.write('
')
		f.write('')
		f.write(f'
')
		f.write(f'
Is Plugged In?	Usage in Seconds	Day of the Week	GMT Offset	Start	End	Entry Creation
')
		for row in all_rows:
			f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}
')
		f.write(f'
')
		logfunc(f'KnowledgeC Plugged In completed')

def mib(filefound):
	logfunc(f'Mobile Installation Logs function executing.')
	#initialize counters
	counter = 0
	filescounter = 0

	#Month to numeric with leading zero when month < 10 function
	#Function call: month = month_converter(month)
	def month_converter(month):
		months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
		month = months.index(month) + 1
		if (month < 10):
			month = f"{month:02d}"
		return month

	#Day with leading zero if day < 10 function
	#Functtion call: day = day_converter(day)
	def day_converter(day):
		day = int(day)
		if (day < 10):
			day = f"{day:02d}"
		return day

	#Create folders for this function
	os.makedirs(reportfolderbase+'Mobile_Installation_Logs/')
	#Create sqlite databases
	db = sqlite3.connect(reportfolderbase+'Mobile_Installation_Logs/mib.db')

	cursor = db.cursor()

	#Create table fileds for destroyed, installed, moved and made identifiers.

	cursor.execute('''

		CREATE TABLE dimm(time_stamp TEXT, action TEXT, bundle_id TEXT,

						  path TEXT)

	''')

	db.commit()

	for filename in filefound:
		file = open(filename, 'r', encoding='utf8' )
		filescounter = filescounter + 1
		for line in file:
			counter = counter+1
			matchObj = re.search( r"(Install Successful for)", line) #Regex for installed applications
			if matchObj:
				actiondesc = "Install successful"
				matchObj1 = re.search( r"(?<= for \(Placeholder:)(.*)(?=\))", line) #Regex for bundle id
				matchObj2 = re.search( r"(?<= for \(Customer:)(.*)(?=\))", line) #Regex for bundle id
				matchObj3 = re.search( r"(?<= for \(System:)(.*)(?=\))", line) #Regex for bundle id
				matchObj4 = re.search( r"(?<= for \()(.*)(?=\))", line) #Regex for bundle id
				if matchObj1:
					bundleid = matchObj1.group(1)
				elif matchObj2:
					bundleid = matchObj2.group(1)
				elif matchObj3:
					bundleid = matchObj3.group(1)
				elif matchObj4:
					bundleid = matchObj4.group(1)

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				#logfunc(inserttime, actiondesc, bundleid)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, '' ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

				#logfunc()

			matchObj = re.search( r"(Destroying container with identifier)", line) #Regex for destroyed containers
			if matchObj:
				actiondesc = "Destroying container"
				#logfunc(actiondesc)
				#logfunc("Destroyed containers:")
				matchObj = re.search( r"(?<=identifier )(.*)(?= at )", line) #Regex for bundle id
				if matchObj:
					bundleid = matchObj.group(1)
					#logfunc ("Bundle ID: ", bundleid )

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				matchObj = re.search( r"(?<= at )(.*)(?=$)", line) #Regex for path
				if matchObj:
					path = matchObj.group(1)
					#logfunc ("Path: ", matchObj.group(1))

				#logfunc(inserttime, actiondesc, bundleid, path)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, path ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

				#logfunc()

			matchObj = re.search( r"(Data container for)", line) #Regex Moved data containers
			if matchObj:
				actiondesc = "Data container moved"
				#logfunc(actiondesc)
				#logfunc("Data container moved:")
				matchObj = re.search( r"(?<=for )(.*)(?= is now )", line) #Regex for bundle id
				if matchObj:
					bundleid = matchObj.group(1)
					#logfunc ("Bundle ID: ", bundleid )

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				matchObj = re.search( r"(?<= at )(.*)(?=$)", line) #Regex for path
				if matchObj:
					path = matchObj.group(1)
					#logfunc ("Path: ", matchObj.group(1))

				#logfunc(inserttime, actiondesc, bundleid, path)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, path ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

				#logfunc()

			matchObj = re.search( r"(Made container live for)", line) #Regex for made container
			if matchObj:
				actiondesc = "Made container live"
				#logfunc(actiondesc)
				#logfunc("Made container:")
				matchObj = re.search( r"(?<=for )(.*)(?= at)", line) #Regex for bundle id
				if matchObj:
					bundleid = matchObj.group(1)
					#logfunc ("Bundle ID: ", bundleid )

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				matchObj = re.search( r"(?<= at )(.*)(?=$)", line) #Regex for path
				if matchObj:
					path = matchObj.group(1)
					#logfunc ("Path: ", matchObj.group(1))
				#logfunc(inserttime, actiondesc, bundleid, path)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, path ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

			matchObj = re.search( r"(Uninstalling identifier )", line) #Regex for made container
			if matchObj:
				actiondesc = "Uninstalling identifier"
				#logfunc(actiondesc)
				#logfunc("Uninstalling identifier")
				matchObj = re.search( r"(?<=Uninstalling identifier )(.*)", line) #Regex for bundle id
				if matchObj:
					bundleid = matchObj.group(1)
					#logfunc ("Bundle ID: ", bundleid )

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, '' ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

			matchObj = re.search( r"(main: Reboot detected)", line) #Regex for reboots
			if matchObj:
				actiondesc = "Reboot detected"
				#logfunc(actiondesc)
				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, '', '' ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

			matchObj = re.search( r"(Attempting Delta patch update of )", line) #Regex for Delta patch
			if matchObj:
				actiondesc = "Attempting Delta patch"
				#logfunc(actiondesc)
				#logfunc("Made container:")
				matchObj = re.search( r"(?<=Attempting Delta patch update of )(.*)(?= from)", line) #Regex for bundle id
				if matchObj:
					bundleid = matchObj.group(1)
					#logfunc ("Bundle ID: ", bundleid )

				matchObj = re.search( r"(?<=^)(.*)(?= \[)", line) #Regex for timestamp
				if matchObj:
					timestamp = matchObj.group(1)
					weekday, month, day, time, year = (str.split(timestamp))
					day = day_converter(day)
					month = month_converter(month)
					inserttime = str(year)+ '-'+ str(month) + '-' + str(day) + ' ' + str(time)
					#logfunc(inserttime)
					#logfunc(month)
					#logfunc(day)
					#logfunc(year)
					#logfunc(time)
					#logfunc ("Timestamp: ", timestamp)

				matchObj = re.search( r"(?<= from )(.*)", line) #Regex for path
				if matchObj:
					path = matchObj.group(1)
					#logfunc ("Path: ", matchObj.group(1))
				#logfunc(inserttime, actiondesc, bundleid, path)

				#insert to database
				cursor = db.cursor()
				datainsert = (inserttime, actiondesc, bundleid, path ,)
				cursor.execute('INSERT INTO dimm (time_stamp, action, bundle_id, path)  VALUES(?,?,?,?)', datainsert)
				db.commit()

				#logfunc()
	try:
		logfunc (f'Logs processed: {filescounter}')
		logfunc (f'Lines processed: {counter}')
		logfunc ('')
		file.close

		#Initialize counters
		totalapps = 0
		installedcount = 0
		uninstallcount = 0
		historicalcount = 0
		sysstatecount = 0

		#created folders for reports and sub folders for App history, App state
		os.makedirs(reportfolderbase+'Mobile_Installation_Logs/Apps_State/')
		os.makedirs(reportfolderbase+'Mobile_Installation_Logs/Apps_Historical/')
		os.makedirs(reportfolderbase+'Mobile_Installation_Logs/System_State/')

		#Initialize text file reports for installed and unistalled apps
		f1=open(reportfolderbase+'Mobile_Installation_Logs/Apps_State/UninstalledApps.txt', 'w+', encoding="utf8")
		f2=open(reportfolderbase+'Mobile_Installation_Logs/Apps_State/InstalledApps.txt', 'w+', encoding="utf8")
		f4=open(reportfolderbase+'Mobile_Installation_Logs/System_State/SystemState.txt', 'w+', encoding="utf8")

		#Initialize database connection
		db = sqlite3.connect(reportfolderbase+'Mobile_Installation_Logs/mib.db')

		cursor = db.cursor()

		#Query to create installed and uninstalled app reports
		cursor.execute('''SELECT distinct bundle_id from dimm''')
		all_rows = cursor.fetchall()
		for row in all_rows:
			#logfunc(row[0])
			distinctbundle = row[0]
			cursor.execute('''SELECT * from dimm where bundle_id=? order by time_stamp desc limit 1''', (distinctbundle,))
			all_rows_iu = cursor.fetchall()
			for row in all_rows_iu:
				#logfunc(row[0], row[1], row[2], row[3])
				if row[2] == '':
					continue
				elif row[1] == 'Destroying container':
					#logfunc(row[0], row[1], row[2], row[3])
					uninstallcount = uninstallcount + 1
					totalapps = totalapps + 1
					#tofile1 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n'
					tofile1 = row[2] +  '\n'
					f1.write(tofile1)
					#logfunc()
				elif row[1] == 'Uninstalling identifier':
					#logfunc(row[0], row[1], row[2], row[3])
					uninstallcount = uninstallcount + 1
					totalapps = totalapps + 1
					#tofile1 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n'
					tofile1 = row[2] +  '\n'
					f1.write(tofile1)
					#logfunc()
				else:
					#logfunc(row[0], row[1], row[2], row[3])
					tofile2 = row[2] + '\n'

					f2.write(tofile2)
					installedcount = installedcount + 1
					totalapps = totalapps + 1

		f1.close()
		f2.close()

		list =[]
		path = reportfolderbase+'/Mobile_Installation_Logs/Apps_State/'
		files = os.listdir(path)
		for name in files:
			list.append(f'{name}')

		filedatahtml = open(path+'/Apps State.html', mode='a+')
		filedatahtml.write('Data from Mobile Installation Logs - App State / Installed and Uninstalled Apps
')
		filedatahtml.write(f'Data location: {filename}

')
		list.sort()
		for items in list:
			filedatahtml.write(items)
			filedatahtml.write('
')
		filedatahtml.close()

		#Query to create historical report per app

		cursor.execute('''SELECT distinct bundle_id from dimm''')
		all_rows = cursor.fetchall()
		for row in all_rows:
			#logfunc(row[0])
			distinctbundle = row[0]
			if row[0] == '':
				continue
			else:
				f3=open(reportfolderbase+'Mobile_Installation_Logs/Apps_Historical/' + distinctbundle + '.txt', 'w+', encoding="utf8") #Create historical app report per app
				cursor.execute('''SELECT * from dimm where bundle_id=? order by time_stamp DESC''', (distinctbundle,)) #Query to create app history per bundle_id
				all_rows_hist = cursor.fetchall()
				for row in all_rows_hist:
					#logfunc(row[0], row[1], row[2], row[3])
					tofile3 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n'
					f3.write(tofile3)
			f3.close()
			historicalcount = historicalcount + 1

		list =[]
		path = reportfolderbase+'/Mobile_Installation_Logs/Apps_Historical/'
		files = os.listdir(path)
		for name in files:
			list.append(f'{name}')

		filedatahtml = open(path+'Apps Historical.html', mode='a+')
		filedatahtml.write('Data from Mobile Installation Logs - Apps Historical
')
		filedatahtml.write(f'Data location: {filename}

')
		list.sort()
		for items in list:
			filedatahtml.write(items)
			filedatahtml.write('
')
		filedatahtml.close()

		#Query to create system events

		path = reportfolderbase+'/Mobile_Installation_Logs/System_State/'
		filedatahtml = open(path+'System State.html', mode='a+')
		filedatahtml.write('Data from Mobile Installation Logs - System State / Reboots
')
		filedatahtml.write(f'Data location: {filename}

')

		cursor.execute('''SELECT * from dimm where action ='Reboot detected' order by time_stamp DESC''')
		all_rows = cursor.fetchall()
		for row in all_rows:
			#logfunc(row[0])
			#logfunc(row[0], row[1], row[2], row[3])
			tofile4 = row[0] + ' ' + row[1] + ' ' + row[2] + ' ' + row[3] + '\n'
			f4.write(tofile4)
			filedatahtml.write(tofile4+'
')
			sysstatecount = sysstatecount + 1

		filedatahtml.close()

		logfunc (f'Total apps: {totalapps}')
		logfunc (f'Total installed apps: {installedcount}')
		logfunc (f'Total uninstalled apps: {uninstallcount}')
		logfunc (f'Total historical app reports: {historicalcount}')
		logfunc (f'Total system state events: {sysstatecount}')
		logfunc (f'Mobile Installation Logs function completed.')
		f1.close()
		f2.close()
		f4.close()

	except:
		logfunc(f'Log files not found in {filefound}')

def wireless(filefound):
	logfunc(f'Cellular Wireless files function executing')
	os.makedirs(reportfolderbase+'Cellular Wireless Info/')
	for filepath in filefound:
		basename = os.path.basename(filepath)
		if basename =='com.apple.commcenter.device_specific_nobackup.plist' or basename =='com.apple.commcenter.plist':
			f =open(reportfolderbase+'Cellular Wireless Info/'+basename+'.html','w')
			#header html mas tabla
			f.write('')
			f.write(f'

')
			f.write('')
			f.write(f'
{basename}
')
			p = open(filepath, 'rb')
			plist = plistlib.load(p)
			for key, val in plist.items():
				f.write(f'
{key}	{val}
')
			f.write(f'
')
			f.close()
	logfunc(f'Cellular Wireless files function completed')

def iconstate(filefound):
	logfunc(f'Iconstate function executing.')
	os.makedirs(reportfolderbase+'Icon Positions/')
	f =open(reportfolderbase+'Icon Positions/Icon Positions.txt','w')
	g =open(reportfolderbase+'Icon Positions/Icon Positons.html','w')
	g.write('')
	p = open(filefound[0], 'rb')
	plist = plistlib.load(p)
	for key, val in plist.items():
		f.write(f'{key} -> {val}{nl}')
		if key == 'buttonBar':
			bbar = val
		elif key == 'iconLists':
			icon = val
	f.close()
	for x in range(0, len(icon)):
		page = icon[x]
		g.write(f'

')
		g.write('')
		g.write(f'
  Icons screen #{x}	')
		for y in range(0, len(page)):
			rows = page[y]
			if (y == 0) or (y % 4 == 0):
				g.write('

')
			g.write(f'{rows}	')
		g.write('

')

	#do bottom bar
	g.write(f'

  Icons bottom bar

')
	for x in range(0, len(bbar)):
		g.write(f'{bbar[x]}	')
	g.write('

')

	g.write('')
	g.close()

	logfunc('Screens: '+str(len(icon)))
	logfunc('Icons in bottom bar: '+str(len(bbar)))
	logfunc(f'Iconstate function completed.')

def lastbuild(filefound):
	global versionf
	versionnum = 0
	logfunc(f'Lastbuild function executing.')
	os.makedirs(reportfolderbase+'Build Info/')
	f =open(reportfolderbase+'Build Info/LastBuildInfo.plist.txt','w')
	p = open(filefound[0], 'rb')
	plist = plistlib.load(p)

	#create html headers
	filedatahtml = open(reportfolderbase+'Build Info/'+'Build_Info.html', mode='a+')
	filedatahtml.write('')
	filedatahtml.write('
Last Build Report
')
	filedatahtml.write ('')
	filedatahtml.write('
')
	filedatahtml.write(f'
{filefound[0]}
')
	filedatahtml.write('
Key	Value
')

	for key, val in plist.items():
		f.write(f'{key} -> {val}{nl}')
		filedatahtml.write(f'
{key}	{val}
')
		if key == ('ProductVersion'):
			versionnum = val[0:2]
			if versionnum in ('11','12','13'):
				versionf = versionnum
				logfunc(f'iOS version is: {versionf}')
			else:
				versionf = 'Unknown'
	f.close()

	#close html footer
	filedatahtml.write('
')
	filedatahtml.close()
	logfunc(f'Lastbuild function completed.')

def iOSNotifications11(filefound):
	logfunc(f'iOSNotifications 11 function executing.')

	count = 0
	notdircount = 0
	exportedbplistcount = 0
	unix = datetime.datetime(1970, 1, 1)  # UTC
	cocoa = datetime.datetime(2001, 1, 1)  # UTC
	delta = cocoa - unix

	with open('NotificationParams.txt', 'r') as f:
		notiparams = [line.strip() for line in f]

	pathfound = 0
	count = 0
	notdircount = 0
	exportedbplistcount = 0

	pathfound = str(filefound[0])

	if pathfound == 0:
		logfunc("No PushStore directory located")
	else:
		folder = (reportfolderbase+'iOS 11 Notifications/') #add the date thing from phill
		os.makedirs( folder )
		#logfunc("Processing:")
		for filename in glob.iglob(pathfound+'\**', recursive=True):
			if os.path.isfile(filename): # filter dirs
				file_name = os.path.splitext(os.path.basename(filename))[0]
					#get extension and iterate on those files
					#file_extension = os.path.splitext(filename)
					#logfunc(file_extension)
					#create directory
				if filename.endswith('pushstore'):
						#create directory where script is running from
					logfunc (filename) #full path
					notdircount = notdircount + 1
						#logfunc (os.path.basename(file_name)) #filename with  no extension
					openplist = (os.path.basename(os.path.normpath(filename))) #filename with extension
						#logfunc (openplist)
						#bundlepath = (os.path.basename(os.path.dirname(filename)))#previous directory
					bundlepath = file_name
					appdirect = (folder + "\\"+ bundlepath)
						#logfunc(appdirect)
					os.makedirs( appdirect )

						#open the plist
					p = open(filename, 'rb')
					plist = ccl_bplist.load(p)
					plist2 = plist["$objects"]

					long = len(plist2)
					#logfunc (long)
					h = open('./'+appdirect+'/DeliveredNotificationsReport.html', 'w') #write report
					h.write('')
					h.write('
iOS Delivered Notifications Triage Report
')
					h.write(filename)
					h.write('
')
					h.write ('')
					h.write('
')

					h.write('<button onclick="hideRows()">Hide rows</button>')
					h.write('<button onclick="showRows()">Show rows</button>')

					f = open("script.txt")
					for line in f:
						h.write(line)
					f.close()

					h.write('
')
					h.write('
')
					h.write('
')
					h.write('Data type	')
					h.write('Value	')
					h.write('
')

					h.write('
')
					h.write('Plist	')
					h.write('Initial Values	')
					h.write('
')

					test = 0
					for i in range (0, long):
						try:
							if (plist2[i]['$classes']):
								h.write('
')
								h.write('$classes	')
								ob6 = str(plist2[i]['$classes'])
								h.write('')
								h.write(str(ob6))
								h.write('	')
								h.write('
')
								test = 1
						except:
							pass
						try:
							if (plist2[i]['$class']):
								h.write('
')
								h.write('$class	')
								ob5 = str(plist2[i]['$class'])
								h.write('')
								h.write(str(ob5))
								h.write('	')
								h.write('
')
								test = 1
						except:
							pass
						try:
							if (plist2[i]['NS.keys']):
								h.write('
')
								h.write('NS.keys	')
								ob0 = str(plist2[i]['NS.keys'])
								h.write('')
								h.write(str(ob0))
								h.write('	')
								h.write('
')
								test = 1
						except:
							pass
						try:
							if (plist2[i]['NS.objects']):
								ob1 = str(plist2[i]['NS.objects'])
								h.write('
')
								h.write('NS.objects	')
								h.write('')
								h.write(str(ob1))
								h.write('	')
								h.write('
')

								test = 1
						except:
							pass
						try:
							if (plist2[i]['NS.time']):
								dia = str(plist2[i]['NS.time'])
								dias = (dia.rsplit('.', 1)[0])
								timestamp = datetime.datetime.fromtimestamp(int(dias)) + delta
								#logfunc (timestamp)

								h.write('
')
								h.write('Time UTC	')
								h.write('')
								h.write(str(timestamp))
								#h.write(str(plist2[i]['NS.time']))
								h.write('	')
								h.write('
')

								test = 1
						except:
							pass
						try:
							if (plist2[i]['NS.base']):
								ob2 = str(plist2[i]['NS.objects'])
								h.write('
')
								h.write('NS.base	')
								h.write('')
								h.write(str(ob2))
								h.write('	')
								h.write('
')

								test = 1
						except:
							pass
						try:
							if (plist2[i]['$classname']):
								ob3 = str(plist2[i]['$classname'])
								h.write('
')
								h.write('$classname	')
								h.write('')
								h.write(str(ob3))
								h.write('	')
								h.write('
')

								test = 1
						except:
							pass

						try:
							if test == 0:
								if (plist2[i]) == "AppNotificationMessage":
									h.write('
')
									h.write('
')
									h.write('
')
									h.write('
')
									h.write('Data type	')
									h.write('Value	')
									h.write('
')

									h.write('
')
									h.write('ASCII	')
									h.write(''+str(plist2[i])+'	')
									h.write('
')

								else:
									if plist2[i] in notiparams:
										h.write('
')
										h.write('ASCII	')
										h.write(''+str(plist2[i])+'	')
										h.write('
')
									elif plist2[i] == " ":
										h.write('
')
										h.write('Null	')
										h.write(''+str(plist2[i])+'	')
										h.write('
')
									else:
										h.write('
')
										h.write('ASCII	')
										h.write(''+str(plist2[i])+'	')
										h.write('
')

						except:
							pass

						test = 0

						#h.write('test')

					for dict in plist2:
						liste = dict
						types = (type(liste))
						#logfunc (types)
						try:
							for k, v in liste.items():
								if k == 'NS.data':
									chk = str(v)
									reduced = (chk[2:8])
									#logfunc (reduced)
									if reduced == "bplist":
										count = count + 1
										binfile = open('./'+appdirect+'/incepted'+str(count)+'.bplist', 'wb')
										binfile.write(v)
										binfile.close()

										procfile = open('./'+appdirect+'/incepted'+str(count)+'.bplist', 'rb')
										secondplist = ccl_bplist.load(procfile)
										secondplistint = secondplist["$objects"]
										logfunc('Bplist processed and exported.')
										exportedbplistcount = exportedbplistcount + 1
										h.write('
')
										h.write('NS.data	')
										h.write('')
										h.write(str(secondplistint))
										h.write('	')
										h.write('
')

										procfile.close()
										count = 0
									else:
										h.write('
')
										h.write('NS.data	')
										h.write('')
										h.write(str(secondplistint))
										h.write('	')
										h.write('
')
						except:
							pass
					h.close()
				elif 'AttachmentsList' in file_name:
					test = 0 #future development

	path = reportfolderbase+'/iOS 11 Notifications/'
	list =[]
	files = os.listdir(path)
	for name in files:
		list.append(f'{name}')

	filedatahtml = open(path+'iOS11_Notifications.html', mode='a+')
	list.sort()
	for items in list:
		filedatahtml.write(items)
		filedatahtml.write('
')

	logfunc("Total notification directories processed:"+str(notdircount))
	logfunc("Total exported bplists from notifications:"+str(exportedbplistcount))
	if notdircount == 0:
			logfunc('No notifications located.')
	logfunc(f'iOS 11 Notifications function completed.')

def iOSNotifications12(filefound):
	logfunc(f'iOS 12+ Notifications function executing')
	os.makedirs(reportfolderbase+'iOS 12 Notifications/')

	count = 0
	notdircount = 0
	exportedbplistcount = 0
	unix = datetime.datetime(1970, 1, 1)  # UTC
	cocoa = datetime.datetime(2001, 1, 1)  # UTC
	delta = cocoa - unix

	#with open('NotificationParams.txt', 'r') as f:
	#	notiparams = [line.strip() for line in f]

	f = open('NotificationParams.txt', 'r')
	notiparams = [line.strip() for line in f]
	f.close()

	folder = (reportfolderbase+'iOS 12 Notifications/')
	#logfunc("Processing:")
	pathfound = str(filefound[0])
	#logfunc(f'Posix to string is: {pathfound}')
	for filename in glob.iglob(pathfound+'/**', recursive=True):
		#create directory where script is running from
		if os.path.isfile(filename): # filter dirs
			file_name = os.path.splitext(os.path.basename(filename))[0]
			#create directory
			if 'DeliveredNotifications' in file_name:
				#create directory where script is running from
				#logfunc (filename) #full path
				notdircount = notdircount + 1
				#logfunc (os.path.basename(file_name)) #filename with  no extension
				openplist = (os.path.basename(os.path.normpath(filename))) #filename with extension
				#logfunc (openplist)
				bundlepath = (os.path.basename(os.path.dirname(filename)))#previous directory
				appdirect = (folder + "/"+ bundlepath)
				#logfunc(appdirect)
				os.makedirs( appdirect )

				#open the plist
				p = open(filename, 'rb')
				plist = ccl_bplist.load(p)
				plist2 = plist["$objects"]

				long = len(plist2)
				#logfunc (long)
				h = open('./'+appdirect+'/DeliveredNotificationsReport.html', 'w') #write report
				h.write('')
				h.write('
iOS Delivered Notifications Triage Report
')
				h.write ('')
				h.write(filename)
				h.write('
')
				h.write('
')

				h.write('<button onclick="hideRows()">Hide rows</button>')
				h.write('<button onclick="showRows()">Show rows</button>')

				f = open("script.txt")
				for line in f:
					h.write(line)
				f.close()

				h.write('
')
				h.write('
')
				h.write('
')
				h.write('Data type	')
				h.write('Value	')
				h.write('
')

				h.write('
')
				h.write('Plist	')
				h.write('Initial Values	')
				h.write('
')

				test = 0
				for i in range (0, long):
					try:
						if (plist2[i]['$classes']):
							h.write('
')
							h.write('$classes	')
							ob6 = str(plist2[i]['$classes'])
							h.write('')
							h.write(str(ob6))
							h.write('	')
							h.write('
')
							test = 1
					except:
						pass
					try:
						if (plist2[i]['$class']):
							h.write('
')
							h.write('$class	')
							ob5 = str(plist2[i]['$class'])
							h.write('')
							h.write(str(ob5))
							h.write('	')
							h.write('
')
							test = 1
					except:
						pass
					try:
						if (plist2[i]['NS.keys']):
							h.write('
')
							h.write('NS.keys	')
							ob0 = str(plist2[i]['NS.keys'])
							h.write('')
							h.write(str(ob0))
							h.write('	')
							h.write('
')
							test = 1
					except:
						pass
					try:
						if (plist2[i]['NS.objects']):
							ob1 = str(plist2[i]['NS.objects'])
							h.write('
')
							h.write('NS.objects	')
							h.write('')
							h.write(str(ob1))
							h.write('	')
							h.write('
')

							test = 1
					except:
						pass
					try:
						if (plist2[i]['NS.time']):
							dia = str(plist2[i]['NS.time'])
							dias = (dia.rsplit('.', 1)[0])
							timestamp = datetime.datetime.fromtimestamp(int(dias)) + delta
							#logfunc (timestamp)

							h.write('
')
							h.write('Time UTC	')
							h.write('')
							h.write(str(timestamp))
							#h.write(str(plist2[i]['NS.time']))
							h.write('	')
							h.write('
')

							test = 1
					except:
						pass
					try:
						if (plist2[i]['NS.base']):
							ob2 = str(plist2[i]['NS.objects'])
							h.write('
')
							h.write('NS.base	')
							h.write('')
							h.write(str(ob2))
							h.write('	')
							h.write('
')

							test = 1
					except:
						pass
					try:
						if (plist2[i]['$classname']):
							ob3 = str(plist2[i]['$classname'])
							h.write('
')
							h.write('$classname	')
							h.write('')
							h.write(str(ob3))
							h.write('	')
							h.write('
')

							test = 1
					except:
						pass
					'''
					try:

							h.write('
')
							h.write('ASCII	')
							h.write(''+str(plist2[i])+'	')
							h.write('
')

							test = 1
					except:
						pass
					'''
					try:
						if test == 0:
							if (plist2[i]) == "AppNotificationMessage":
								h.write('
')
								h.write('
')
								h.write('
')
								h.write('
')
								h.write('Data type	')
								h.write('Value	')
								h.write('
')

								h.write('
')
								h.write('ASCII	')
								h.write(''+str(plist2[i])+'	')
								h.write('
')

							else:
								if plist2[i] in notiparams:
									h.write('
')
									h.write('ASCII	')
									h.write(''+str(plist2[i])+'	')
									h.write('
')
								elif plist2[i] == " ":
									h.write('
')
									h.write('Null	')
									h.write(''+str(plist2[i])+'	')
									h.write('
')
								else:
									h.write('
')
									h.write('ASCII	')
									h.write(''+str(plist2[i])+'	')
									h.write('
')

					except:
						pass

					test = 0

					#h.write('test')

				for dict in plist2:
					liste = dict
					types = (type(liste))
					#logfunc (types)
					try:
						for k, v in liste.items():
							if k == 'NS.data':
								chk = str(v)
								reduced = (chk[2:8])
								#logfunc (reduced)
								if reduced == "bplist":
									count = count + 1
									binfile = open('./'+appdirect+'/incepted'+str(count)+'.bplist', 'wb')
									binfile.write(v)
									binfile.close()

									procfile = open('./'+appdirect+'/incepted'+str(count)+'.bplist', 'rb')
									secondplist = ccl_bplist.load(procfile)
									secondplistint = secondplist["$objects"]
									logfunc('Bplist processed and exported.')
									exportedbplistcount = exportedbplistcount + 1
									h.write('
')
									h.write('NS.data	')
									h.write('')
									h.write(str(secondplistint))
									h.write('	')
									h.write('
')

									procfile.close()
									count = 0
								else:
									h.write('
')
									h.write('NS.data	')
									h.write('')
									h.write(str(secondplistint))
									h.write('	')
									h.write('
')
					except:
						pass
				h.close()
			elif 'AttachmentsList' in file_name:
				test = 0 #future development

	path = reportfolderbase+'/iOS 12 Notifications/'
	dict ={}
	files = os.listdir(path)
	for name in files:
		try:
			size = os.path.getsize(f'{path}{name}/DeliveredNotificationsReport.html')
			key = (f'{name}')
			dict[key] = size
		except NotADirectoryError as nade:
			logfunc(nade)
			pass

	filedatahtml = open(path+'iOS12_Notifications.html', mode='a+')
	filedatahtml.write('

Notifications by GUID (iOS13) or Bundle ID (iOS12) 	Notification size in KB
')
	for k, v in dict.items():
		v = v/1000
		#logfunc(f'{k} -> {v}')
		filedatahtml.write(f'
{k}	{v}
')
	filedatahtml.write('
')
	filedatahtml.close()

	logfunc("Total notification directories processed:"+str(notdircount))
	logfunc("Total exported bplists from notifications:"+str(exportedbplistcount))
	if notdircount == 0:
		logfunc('No notifications located.')
	logfunc('iOS 12+ Notifications function completed.')

def ktx(filefound):
	logfunc(f'Snapshots KTX file finder function executing.')
	logfunc(f'Snapshots located: {len(filefound)}')
	outpath = reportfolderbase +'Snapshots_KTX_Files/'
	outktx = outpath+'KTX_Files/'
	os.mkdir(outpath)
	os.mkdir(outktx)
	nl = '\n'

	filedata = open(outpath+'_Snapshot_KTX_Files_List.csv', mode='a+', encoding='utf8')
	filewrite = csv.writer(filedata, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
	filewrite.writerow([ 'Path', 'Filename'])
	filedata.close()

	filedatahtml = open(outpath+'KTX_Files.html', mode='a+')
	filedatahtml.write('')
	filedatahtml.write('
KTX Files Report
')
	filedatahtml.write ('')
	filedatahtml.write('
')
	filedatahtml.write(f'Extracted KTX files can be examined in the {outpath}KTX_Files/ directory.
')
	filedatahtml.write('
')
	filedatahtml.write('
Path	Filename
')

	for filename in filefound:
		p = pathlib.Path(filename)
		head1, tail1 = os.path.split(filename)
		head2, tail2 = os.path.split(head1)

		tail = ''
		head = ''
		fullp = ''
		for x in p.parts:
			head1, tail = os.path.split(head1)
			fullp = tail+'/'+fullp
			if tail == 'Library':
				fullpw = fullp

		if os.path.exists(outktx+fullpw):
			pass
		else:
			os.makedirs(outktx+fullpw)
		#get the name, filepath write to csv in outpath _KTX_Files_Report.csv

		filedata = open(outpath+'_Snapshot_KTX_Files_List.csv', mode='a+', encoding='utf8')
		filewrite = csv.writer(filedata, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
		filewrite.writerow([filename, tail1])
		filedatahtml.write(f'
{filename}	{tail1}
')
		filedata.close()
		if os.path.exists(filename):
			shutil.copy2(filename, outktx+fullpw)
	filedatahtml.close()
	logfunc(f'Snapshots KTX file finder function completed.')

def calhist(filefound):
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	cursor.execute('''
	SELECT
			ZADDRESS AS "ADDRESS",
			ZANSWERED AS "WAS ANSWERED",
			ZCALLTYPE AS "CALL TYPE",
			ZORIGINATED AS "ORIGINATED",
			ZDURATION AS "DURATION (IN SECONDS)",
			ZISO_COUNTRY_CODE as "ISO COUNTY CODE",
			ZLOCATION AS "LOCATION",
			ZSERVICE_PROVIDER AS "SERVICE PROVIDER",
			DATETIME(ZDATE+978307200,'UNIXEPOCH') AS "TIMESTAMP"
		FROM ZCALLRECORD ''')

	all_rows = cursor.fetchall()
	usageentries = len(all_rows)
	if usageentries > 0:
		logfunc(f'Call History function executing')
		os.makedirs(reportfolderbase+'Call History/')
		with open(reportfolderbase+'Call History/Call History.html', 'w', encoding='utf8') as f:
			f.write('')
			f.write('
 Call History report
')
			f.write(f'Call History entries: {usageentries}
')
			f.write(f'Call History database located at: {filefound[0]}
')
			f.write('')
			f.write('
')
			f.write('')
			f.write(f'
')
			f.write(f'
Address	Was Answered	Call Type	Originated	Duration in Secs	ISO County Code	Location	Service Provider	Timestamp
')
			for row in all_rows:
				an = str(row[0])
				an = (an.replace("b'", ''))
				an = (an.replace("'", ''))

				f.write(f'
{an}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}
')
			f.write(f'
')
			logfunc(f'Call History function completed')
	else:
		logfunc('No call history available')

def smschat(filefound):
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		SELECT
				CASE
					WHEN LENGTH(MESSAGE.DATE)=18 THEN DATETIME(MESSAGE.DATE/1000000000+978307200,'UNIXEPOCH')
					WHEN LENGTH(MESSAGE.DATE)=9 THEN DATETIME(MESSAGE.DATE + 978307200,'UNIXEPOCH')
					ELSE "N/A"
		    		END "MESSAGE DATE",
				CASE
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=18 THEN DATETIME(MESSAGE.DATE_DELIVERED/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=9 THEN DATETIME(MESSAGE.DATE_DELIVERED+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE DELIVERED",
				CASE
					WHEN LENGTH(MESSAGE.DATE_READ)=18 THEN DATETIME(MESSAGE.DATE_READ/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_READ)=9 THEN DATETIME(MESSAGE.DATE_READ+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE READ",
				MESSAGE.TEXT as "MESSAGE",
				HANDLE.ID AS "CONTACT ID",
				MESSAGE.SERVICE AS "SERVICE",
				MESSAGE.ACCOUNT AS "ACCOUNT",
				MESSAGE.IS_DELIVERED AS "IS DELIVERED",
				MESSAGE.IS_FROM_ME AS "IS FROM ME",
				ATTACHMENT.FILENAME AS "FILENAME",
				ATTACHMENT.MIME_TYPE AS "MIME TYPE",
				ATTACHMENT.TRANSFER_NAME AS "TRANSFER TYPE",
				ATTACHMENT.TOTAL_BYTES AS "TOTAL BYTES"
			FROM MESSAGE
			LEFT OUTER JOIN MESSAGE_ATTACHMENT_JOIN ON MESSAGE.ROWID = MESSAGE_ATTACHMENT_JOIN.MESSAGE_ID
			LEFT OUTER JOIN ATTACHMENT ON MESSAGE_ATTACHMENT_JOIN.ATTACHMENT_ID = ATTACHMENT.ROWID
			LEFT OUTER JOIN HANDLE ON MESSAGE.HANDLE_ID = HANDLE.ROWID
			''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'SMS Chat function executing')
			os.makedirs(reportfolderbase+'SMS Chat/')
			with open(reportfolderbase+'SMS Chat/SMS Chat.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 SMS Chat report
')
				f.write(f'SMS Chat entries: {usageentries}
')
				f.write(f'SMS Chat database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Message Date	Date Delivered	Date Read	Message	Contact ID	Service	Account	Is Delivered	Is from Me	Filename	MIME Type	Transfer Type	Total Bytes
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}
')
				f.write(f'
')
				logfunc(f'SMS Chat function completed')
		else:
				logfunc('No SMS Chats available')
	except:
		logfunc('Error on SMS Chat function. Possible empty database.')

	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		SELECT
				CASE
		 			WHEN LENGTH(MESSAGE.DATE)=18 THEN DATETIME(MESSAGE.DATE/1000000000+978307200,'UNIXEPOCH')
		 			WHEN LENGTH(MESSAGE.DATE)=9 THEN DATETIME(MESSAGE.DATE + 978307200,'UNIXEPOCH')
		 			ELSE "N/A"
				END "MESSAGE DATE",
				CASE
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=18 THEN DATETIME(MESSAGE.DATE_DELIVERED/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=9 THEN DATETIME(MESSAGE.DATE_DELIVERED+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE DELIVERED",
				CASE
					WHEN LENGTH(MESSAGE.DATE_READ)=18 THEN DATETIME(MESSAGE.DATE_READ/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_READ)=9 THEN DATETIME(MESSAGE.DATE_READ+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE READ",
				MESSAGE.TEXT as "MESSAGE",
				HANDLE.ID AS "CONTACT ID",
				MESSAGE.SERVICE AS "SERVICE",
				MESSAGE.ACCOUNT AS "ACCOUNT",
				MESSAGE.IS_DELIVERED AS "IS DELIVERED",
				MESSAGE.IS_FROM_ME AS "IS FROM ME",
				ATTACHMENT.FILENAME AS "FILENAME",
				ATTACHMENT.MIME_TYPE AS "MIME TYPE",
				ATTACHMENT.TRANSFER_NAME AS "TRANSFER TYPE",
				ATTACHMENT.TOTAL_BYTES AS "TOTAL BYTES"
			FROM MESSAGE
			LEFT OUTER JOIN MESSAGE_ATTACHMENT_JOIN ON MESSAGE.ROWID = MESSAGE_ATTACHMENT_JOIN.MESSAGE_ID
			LEFT OUTER JOIN ATTACHMENT ON MESSAGE_ATTACHMENT_JOIN.ATTACHMENT_ID = ATTACHMENT.ROWID
			LEFT OUTER JOIN HANDLE ON MESSAGE.HANDLE_ID = HANDLE.ROWID
			WHERE "DATE DELIVERED" IS NOT "N/A"''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'SMS Chat Message Delivered function executing')
			with open(reportfolderbase+'SMS Chat/SMS Message Delivered.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 SMS Chat Message Delivered report
')
				f.write(f'SMS Chat Message Delivered entries: {usageentries}
')
				f.write(f'SMS Chat Message Delivered database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Message Date	Date Delivered	Date Read	Message	Contact ID	Service	Account	Is Delivered	Is from Me	Filename	MIME Type	Transfer Type	Total Bytes
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}
')
				f.write(f'
')
				logfunc(f'SMS Chat Message function completed')
		else:
			logfunc('No SMS Chat Message Delivered available')
	except:
		logfunc('Error on SMS Chat Message Delivered function. Possible empty database.')

	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		SELECT
				CASE
		 			WHEN LENGTH(MESSAGE.DATE)=18 THEN DATETIME(MESSAGE.DATE/1000000000+978307200,'UNIXEPOCH')
		 			WHEN LENGTH(MESSAGE.DATE)=9 THEN DATETIME(MESSAGE.DATE + 978307200,'UNIXEPOCH')
		 			ELSE "N/A"
		     		END "MESSAGE DATE",
				CASE
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=18 THEN DATETIME(MESSAGE.DATE_DELIVERED/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_DELIVERED)=9 THEN DATETIME(MESSAGE.DATE_DELIVERED+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE DELIVERED",
				CASE
					WHEN LENGTH(MESSAGE.DATE_READ)=18 THEN DATETIME(MESSAGE.DATE_READ/1000000000+978307200,"UNIXEPOCH")
					WHEN LENGTH(MESSAGE.DATE_READ)=9 THEN DATETIME(MESSAGE.DATE_READ+978307200,"UNIXEPOCH")
					ELSE "N/A"
				END "DATE READ",
				MESSAGE.TEXT as "MESSAGE",
				HANDLE.ID AS "CONTACT ID",
				MESSAGE.SERVICE AS "SERVICE",
				MESSAGE.ACCOUNT AS "ACCOUNT",
				MESSAGE.IS_DELIVERED AS "IS DELIVERED",
				MESSAGE.IS_FROM_ME AS "IS FROM ME",
				ATTACHMENT.FILENAME AS "FILENAME",
				ATTACHMENT.MIME_TYPE AS "MIME TYPE",
				ATTACHMENT.TRANSFER_NAME AS "TRANSFER TYPE",
				ATTACHMENT.TOTAL_BYTES AS "TOTAL BYTES"
			FROM MESSAGE
			LEFT OUTER JOIN MESSAGE_ATTACHMENT_JOIN ON MESSAGE.ROWID = MESSAGE_ATTACHMENT_JOIN.MESSAGE_ID
			LEFT OUTER JOIN ATTACHMENT ON MESSAGE_ATTACHMENT_JOIN.ATTACHMENT_ID = ATTACHMENT.ROWID
			LEFT OUTER JOIN HANDLE ON MESSAGE.HANDLE_ID = HANDLE.ROWID
			WHERE "DATE READ" IS NOT "N/A"''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'SMS Chat Message Read function executing')
			with open(reportfolderbase+'SMS Chat/SMS Message Read.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 SMS Chat Message Read report
')
				f.write(f'SMS Chat Message Read entries: {usageentries}
')
				f.write(f'SMS Chat Message Readdatabase located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Message Date	Date Delivered	Date Read	Message	Contact ID	Service	Account	Is Delivered	Is from Me	Filename	MIME Type	Transfer Type	Total Bytes
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}
')
				f.write(f'
')
				logfunc(f'SMS Chat Message Read function completed')
		else:
			logfunc('No SMS Chat Message Read available')
	except:
		logfunc('Error on SMS Chat Message Read available. Posible empty database. ')

def safari(filefound):
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		SELECT
				HISTORY_ITEMS.URL AS "URL",
				HISTORY_ITEMS.VISIT_COUNT AS "VISIT COUNT",
				HISTORY_VISITS.TITLE AS "TITLE",
				CASE HISTORY_VISITS.ORIGIN
					WHEN 1 THEN "ICLOUD SYNCED DEVICE"
					WHEN 0 THEN "VISTED FROM THIS DEVICE"
				END "ICLOUD SYNC",
				HISTORY_VISITS.LOAD_SUCCESSFUL AS "LOAD SUCCESSFUL",
				HISTORY_VISITS.REDIRECT_SOURCE AS "REDIRECT SOURCE",
				HISTORY_VISITS.REDIRECT_DESTINATION AS "REDIRECT DESTINATION",
				DATETIME(HISTORY_VISITS.VISIT_TIME+978307200,'UNIXEPOCH') AS "VISIT TIME",
				HISTORY_VISITS.ID AS "HISTORY ITEM ID"
			FROM HISTORY_ITEMS
			LEFT OUTER JOIN HISTORY_VISITS ON HISTORY_ITEMS.ID == HISTORY_VISITS.HISTORY_ITEM
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Safari History function executing')
			os.makedirs(reportfolderbase+'Safari/')
			with open(reportfolderbase+'Safari/Safari History.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Safari History report
')
				f.write(f'Safari History entries: {usageentries}
')
				f.write(f'Safari History database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
URL	Visit Count	Title	Icloud Sync	Load Sucessful	Redirect Source	Redirect Destination	Visit Time	History Item ID
')
				for row in all_rows:
					url = textwrap.fill(row[0])
					f.write(f'
{url}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}
')
				f.write(f'
')
				logfunc(f'Safari History function completed')
		else:
				logfunc('No Safari History available')
	except:
		logfunc('Error on Safari History function.')

def queryp(filefound):
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		select
				content,
				isSent,
				conversationId,
				id,
				uuid,
				datetime(creationTimestamp, "UNIXEPOCH", "LOCALTIME") as START
				from messages
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Query Predictions function executing')
			os.makedirs(reportfolderbase+'Query Predictions/')
			with open(reportfolderbase+'Query Predictions/Query Predictions.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Query Predictions report
')
				f.write(f'Query Predictions entries: {usageentries}
')
				f.write(f'Query Predictions database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Content	Is Sent	Conversation ID	ID	UUID	Start
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}
')
				f.write(f'
')
				logfunc(f'Query Predictions function completed')
		else:
				logfunc('No Query Predictions available')
	except:
		logfunc('Error in the Query Predictions Section.')

def powerlog(filefound):
	os.makedirs(reportfolderbase+'Powerlog/')
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
			   DATETIME(TIMESTAMP, 'unixepoch') AS TIMESTAMP,
			   DATETIME(START, 'unixepoch') AS "START",
			   DATETIME(END, 'unixepoch') AS "END",
			   STATE as "STATE",
			   FINISHED as "FINISHED",
			   HASERROR AS "HAS ERROR",
			   ID AS "PLXPCAGENT_EVENTPOINT_MOBILEBACKUPEVENTS TABLE ID"
			FROM
			   PLXPCAGENT_EVENTPOINT_MOBILEBACKUPEVENTS
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Powerlog Mobile Backup Events executing')
			with open(reportfolderbase+'Powerlog/Mobile Backup Events.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Powerlog Mobile Backup Events report
')
				f.write(f'Mobile Backup Events entries: {usageentries}
')
				f.write(f'Mobile Backup Events database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Timestamp	Start	End	State	Finished	Has Error	ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}
')
				f.write(f'
')
				logfunc(f'Powerlog Mobile Backup Events function completed')
		else:
				logfunc('No Powerlog Mobile Backup Events available')
	except:
		logfunc('Error in Powerlog Mobile Backup Events Section.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
				DATETIME(WIFIPROPERTIES_TIMESTAMP + SYSTEM, 'unixepoch') AS ADJUSTED_TIMESTAMP,
				CURRENTSSID,
				CURRENTCHANNEL,
				DATETIME(TIME_OFFSET_TIMESTAMP, 'unixepoch') AS OFFSET_TIMESTAMP,
				SYSTEM AS TIME_OFFSET,
				WIFIPROPERTIES_ID AS "PLWIFIAGENT_EVENTBACKWARD_CUMULATIVEPROPERTIES TABLE ID"
		   	FROM
		      (
				SELECT
					WIFIPROPERTIES_ID,
					WIFIPROPERTIES_TIMESTAMP,
					TIME_OFFSET_TIMESTAMP,
					MAX(TIME_OFFSET_ID) AS MAX_ID,
					CURRENTSSID,
					CURRENTCHANNEL,
					SYSTEM
				FROM
		            (
					SELECT
						PLWIFIAGENT_EVENTBACKWARD_CUMULATIVEPROPERTIES.TIMESTAMP AS WIFIPROPERTIES_TIMESTAMP,
						CURRENTSSID,
						CURRENTCHANNEL,
						PLWIFIAGENT_EVENTBACKWARD_CUMULATIVEPROPERTIES.ID AS "WIFIPROPERTIES_ID" ,
						PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.TIMESTAMP AS TIME_OFFSET_TIMESTAMP,
						PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.ID AS TIME_OFFSET_ID,
						PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.SYSTEM
					FROM
						PLWIFIAGENT_EVENTBACKWARD_CUMULATIVEPROPERTIES
					LEFT JOIN
						PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET
		            )
		            AS WIFIPROPERTIES_STATE
		        GROUP BY
					WIFIPROPERTIES_ID
		      )
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Powerlog WIFI Properties executing')
			with open(reportfolderbase+'Powerlog/Powerlog WIFI Properties.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Powerlog WIFI Properties Events report
')
				f.write(f'Powerlog WIFI Properties entries: {usageentries}
')
				f.write(f'Powerlog WIFI Properties database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Adj. Timestamp	Current SSID	Current Channel	Offset Timestamp	Time Offset	ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}
')
				f.write(f'
')
				logfunc(f'Powerlog WIFI Properties function completed')
		else:
				logfunc('No Powerlog WIFI Properties available')
	except:
		logfunc('Error in Powerlog WIFI Properties Section.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
				DATETIME(SBAUTOLOCK_TIMESTAMP + SYSTEM, 'unixepoch') AS ADJUSTED_TIMESTAMP,
				AUTOLOCKTYPE AS "AUTO LOCK TYPE",
				DATETIME(TIME_OFFSET_TIMESTAMP, 'unixepoch') AS OFFSET_TIMESTAMP,
				SYSTEM AS TIME_OFFSET,
				SBAUTOLOCK_ID AS "PLSPRINGBOARDAGENT_EVENTPOINT_SBAUTOLOCK TABLE ID"
			FROM
			(
				SELECT
					SBAUTOLOCK_ID,
					SBAUTOLOCK_TIMESTAMP,
					TIME_OFFSET_TIMESTAMP,
					MAX(TIME_OFFSET_ID) AS MAX_ID,
					AUTOLOCKTYPE,
					SYSTEM
				FROM
				(
				SELECT
					PLSPRINGBOARDAGENT_EVENTPOINT_SBAUTOLOCK.TIMESTAMP AS SBAUTOLOCK_TIMESTAMP,
					AUTOLOCKTYPE,
					PLSPRINGBOARDAGENT_EVENTPOINT_SBAUTOLOCK.ID AS "SBAUTOLOCK_ID" ,
					PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.TIMESTAMP AS TIME_OFFSET_TIMESTAMP,
					PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.ID AS TIME_OFFSET_ID,
					PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET.SYSTEM
				FROM
					PLSPRINGBOARDAGENT_EVENTPOINT_SBAUTOLOCK
				LEFT JOIN
					PLSTORAGEOPERATOR_EVENTFORWARD_TIMEOFFSET
				)
				AS SBAUTOLOCK_STATE
				GROUP BY
					SBAUTOLOCK_ID
			)
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Powerlog Device Screen Autolock executing')
			with open(reportfolderbase+'Powerlog/Device Screen Autolock.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Powerlog Device Screen Autolock report
')
				f.write(f'Powerlog Device Screen Autolock entries: {usageentries}
')
				f.write(f'Powerlog Device Screen Autolock located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Adj Timestamp	Auto Lock Type	Offset Timestamp	Time Offset	ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}
')
				f.write(f'
')
				logfunc(f'Powerlog Device Screen Autolock function completed')
		else:
				logfunc('No Powerlog Device Screen Autolock available')
	except:
		logfunc('Error in Powerlog Device Screen Autolock Section.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''
		SELECT
				DATETIME(APPDELETEDDATE, 'unixepoch') AS "APP DELETED DATE",
				DATETIME(TIMESTAMP, 'unixepoch') AS TIMESTAMP,
				APPNAME AS "APP NAME",
				APPEXECUTABLE AS "APP EXECUTABLE NAME",
				APPBUNDLEID AS "BUNDLE ID",
				APPBUILDVERSION AS "APP BUILD VERSION",
				APPBUNDLEVERSION AS "APP BUNDLE VERSION",
				APPTYPE AS "APP TYPE",
				ID AS "PLAPPLICATIONAGENT_EVENTNONE_ALLAPPS TABLE ID"
			FROM
				PLAPPLICATIONAGENT_EVENTNONE_ALLAPPS
			WHERE
				APPDELETEDDATE > 0
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Powerlog App Deletion Events executing')
			with open(reportfolderbase+'Powerlog/App Deletion.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Powerlog App Deletion Events report
')
				f.write(f'Powerlog App Deletion  Events entries: {usageentries}
')
				f.write(f'Powerlog App Deletion  Events database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
App Deleted Date	Timestamp	App Name	Executable Name	Bundle ID	App Build Version	App Bundle Version	App Type	ID
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}
')
				f.write(f'
')
				logfunc(f'Powerlog App DeletionEvents function completed')
		else:
				logfunc('No Powerlog App Deletion Events available')
	except:
		logfunc('Error in Powerlog App Deletion Events Section.')

def delphotos(filefound):
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		Select
		z_pk,
		zfilename AS "File Name",
		zduration AS "Duration in Seconds",
		case
		when ztrashedstate = 1 then "Deleted"
		else "N/A"
		end AS "Is Deleted",
		case
		when zhidden =1 then "Hidden"
		else 'N/A'
		end AS "Is Hidden",
		datetime(ztrasheddate+978307200,'unixepoch','localtime') AS "Date Deleted",
		datetime(zaddeddate+978307200,'unixepoch','localtime') AS "Date Added",
		datetime(zdatecreated+978307200,'unixepoch','localtime') AS "Date Created",
		datetime(zmodificationdate+978307200,'unixepoch','localtime') AS "Date Modified",
		zdirectory AS "File Path"
		from zgenericasset
			''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Photos.sqlite metadata function executing')
			os.makedirs(reportfolderbase+'Photos.sqlite Metadata/')
			with open(reportfolderbase+'Photos.sqlite Metadata/Photos.sqLite DB.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Photos.sqlite Metadata report
')
				f.write(f'Photos.sqlite Metadata entries: {usageentries}
')
				f.write(f'Photos.sqlite database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Primary Key	File Name	Duration in seconds	Is Deleted	Is Hidden	Date Deleted	Date Added	Date Created	Date Modified	File Path
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}
')
				f.write(f'
')
				logfunc(f'Photos.sqlite Metadata function completed')
		else:
				logfunc('No Photos.sqlite Metadata available')
	except:
		logfunc('Error on Photos.sqlite function.')

def timezone(filefound):
	logfunc(f'Timezone function executing.')
	p = open(filefound[0], 'rb')
	plist = plistlib.load(p)

	#create html headers
	filedatahtml = open(reportfolderbase+'Build Info/TimeZone.html', mode='a+')
	filedatahtml.write('')
	filedatahtml.write('
TimeZone Report
')
	filedatahtml.write(f'Timezone info located at: {filefound[0]}
')
	filedatahtml.write ('')
	filedatahtml.write('
')
	#filedatahtml.write(f'
{filefound[0]}
')
	filedatahtml.write('
Key	Value
')

	for key, val in plist.items():
		filedatahtml.write(f'
{key}	{val}
')

	filedatahtml.write('
')
	filedatahtml.close()
	logfunc(f'Timezone function completed.')

def webclips(filefound):
	logfunc('Webclips function executing')
	try:
		webclip_data = {}
		for path_val in filefound:
			# Extract the unique identifier
			pathstr = str(path_val).replace("\\", "/")

			unique_id = pathstr.split("/WebClips/")[1].split(".webclip/")[0]
			if unique_id != '' and unique_id not in webclip_data:
				webclip_data[unique_id] = {'Info': '',
									   	   'Icon_path': '',
										   'Icon_data': '',
									       'Title': '',
										   'URL': ''}

			# Is this the path to the info.plist?
			if "Info.plist" in pathstr:
				webclip_data[unique_id]['Info'] = path_val

			# Is this the path to the icon?
			if "icon.png" in pathstr:
				webclip_data[unique_id]['Icon_path'] = path_val

		logfunc(f'Webclips found: {len(webclip_data)} ')

		for unique_id, data in webclip_data.items():
			# Info plist information
			info_plist_raw = open(data['Info'], 'rb')
			info_plist = plistlib.load(info_plist_raw)
			webclip_data[unique_id]['Title'] = info_plist['Title']
			webclip_data[unique_id]['URL'] = info_plist['URL']
			info_plist_raw.close()

			# Open and convert icon into b64 for serialisation in report
			icon_data_raw = open(data['Icon_path'], 'rb')
			icon_data = base64.b64encode(icon_data_raw.read()).decode('utf-8')
			webclip_data[unique_id]['Icon_data'] = icon_data
			icon_data_raw.close()

		# Create the report
		g = open(reportfolderbase + 'Icon Positions/WebClips.html', 'w')
		g.write("")
		g.write(f'

')
		g.write('')
		for unique_id, data in webclip_data.items():
			g.write('
')
			g.write(f'	')
			g.write(f'UID:{unique_id}
'
					f'Title: {data["Title"]}
'
					f'URL: {data["URL"]}	')
			g.write('
')
		g.write("
")
		g.close()
	except Exception:
		logfunc('Error on Webclips function.')
	logfunc('Webclips function completed')

def healthdb(filefound):
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()
	try:
		cursor.execute('''
		Select
		datetime(samples.start_date+978307200,'unixepoch','localtime') as "Start Date",
		datetime(samples.end_date+978307200,'unixepoch','localtime') as "End Date",
		samples.data_id,
		case
		when samples.data_type = 3 then "weight"
		when samples.data_type = 7 then "steps"
		when samples.data_type = 8 then "dist in m"
		when samples.data_type = 9 then "resting energy"
		when samples.data_type = 10 then "active energy"
		when samples.data_type = 12 then "flights climbed"
		when samples.data_type = 67 then "weekly calorie goal"
		when samples.data_type = 70 then "watch on"
		when samples.data_type = 75 then "stand"
		when samples.data_type = 76 then "activity"
		when samples.data_type = 79 then "workout"
		when samples.data_type = 83 then "some workouts"
		end as "activity type",
		quantity,
		original_quantity,
		unit_strings.unit_string,
		original_unit,
		correlations.correlation,
		correlations.object,
		correlations.provenance
		string_value,
		metadata_values.data_value,
		metadata_values.numerical_value,
		metadata_values.value_type,
		metadata_keys.key
		from samples
		left outer join quantity_samples on samples.data_id = quantity_samples.data_id
		left outer join unit_strings on quantity_samples.original_unit = unit_strings.RowID
		left outer join correlations on samples.data_id = correlations.object
		left outer join metadata_values on metadata_values.object_id = samples.data_id
		left outer join metadata_keys on metadata_keys.ROWID = metadata_values.key_id
		order by "Start Date" desc
		''')

		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'Healthdb_secure.sqlite function executing')
			os.makedirs(reportfolderbase+'HealthDB/')
			with open(reportfolderbase+'HealthDB/Healthdb_secure.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 Healthdb_secure.sqlite report
')
				f.write(f'Healthdb_secure.sqlite entries: {usageentries}
')
				f.write(f'Healthdb_secure.sqlite database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Start Date	End Date	Activity Type	Quantity	Original Quantity	Unit String	Original Unit	Correlation	String Value	Data Value	Numerical Value	Value Type	Key
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}
')
				f.write(f'
')
				logfunc(f'Healthdb_secure.sqlite function completed')
		else:
				logfunc('No Healthdb_secure.sqlite available')
	except:
		logfunc('Error on Healthdb_secure.sqlite function.')
def wiloc(filefound):
	logfunc('Wireless Locations function executing')
	os.makedirs(reportfolderbase+'Wireless Locations/')
	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''SELECT
				MCC AS "MCC",
				MNC AS "MNC",
				CI AS "CI",
				UARFCN AS "UARFCN",
				PID AS "PID",
				ALTITUDE AS "ALTITUDE",
				SPEED AS "SPEED",
				COURSE AS "COURSE",
				CONFIDENCE AS "CONFIDENCE",
				HORIZONTALACCURACY AS "HORIZONTAL ACCURACY",
				VERTICALACCURACY AS "VERTICAL ACCURACY",
				LATITUDE AS "LATITUDE",
				LONGITUDE AS "LONGITUDE",
				DATETIME(TIMESTAMP + 978307200,'UNIXEPOCH') AS "TIMESTAMP"
			FROM LteCellLocation''')
		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'LTE cell locations function executing')
			with open(reportfolderbase+'Wireless Locations/LTE cell locations.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 LTE cell locations report
')
				f.write(f'LTE cell locations entries: {usageentries}
')
				f.write(f'LTE cell locations database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
MCC	MNC	CI	UARFCN	PID	Altitude	Speed	Course	Confidence	Hoz. Acc.	Vert. Acc.	Latitude	Longitude	Timestamp
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}	{row[13]}
')
				f.write(f'
')
				logfunc(f'LTE cell locations function completed')
		else:
				logfunc('No LTE cell locations available')
	except:
		logfunc('Error on LTE cell locations function.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''SELECT
				MCC AS "MCC",
				SID AS "SID",
				NID AS "NID",
				BSID AS "BSID",
				ZONEID AS "ZONEID",
				BANDCLASS AS "BANDCLASS",
				CHANNEL AS "CHANNEL",
				PNOFFSET AS "PNOFFSET",
				ALTITUDE AS "ALTITUDE",
				SPEED AS "SPEED",
				COURSE AS "COURSE",
				CONFIDENCE AS "CONFIDENCE",
				HORIZONTALACCURACY AS "HORIZONTAL ACCURACY",
				VERTICALACCURACY AS "VERTICAL ACCURACY",
				LATITUDE AS "LATITUDE",
				LONGITUDE AS "LONGITUDE",
				DATETIME(TIMESTAMP + 978307200,'UNIXEPOCH') AS "TIMESTAMP"
			FROM CdmaCellLocation''')
		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'CDMA cell locations function executing')
			with open(reportfolderbase+'Wireless Locations/CDMA cell locations.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 CDMA cell locations report
')
				f.write(f'CDMA cell locations entries: {usageentries}
')
				f.write(f'CDMA cell locations database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
MCC	SID	NID	BSID	Zone ID	Band Class	Channel	PNOFFSET	Altitude	Speed	Course	Confidence	Hoz. Acc.	Vert. Acc.	Latitude	Longitude	Timestamp
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}	{row[13]}	{row[14]}	{row[15]}	{row[16]}
')
				f.write(f'
')
				logfunc(f'CDMA cell locations function completed')
		else:
				logfunc('No CDMA cell locations available')
	except:
			logfunc('Error on CDMA cell locations function.')

	try:
		db = sqlite3.connect(filefound[0])
		cursor = db.cursor()
		cursor.execute('''SELECT
				MAC AS "Base10 MAC",
				CHANNEL AS "CHANNEL",
				INFOMASK AS "INFOMASK",
				SPEED AS "SPEED",
				COURSE AS "COURSE",
				CONFIDENCE AS "CONFIDENCE",
				SCORE AS "SCORE",
				REACH AS "REACH",
				HORIZONTALACCURACY AS "HORIZONTAL ACCURACY",
				VERTICALACCURACY AS "VERTICAL ACCURACY",
				LATITUDE AS "LATITUDE",
				LONGITUDE AS "LONGITUDE",
				DATETIME(TIMESTAMP + 978307200,'UNIXEPOCH') AS "TIMESTAMP"
			FROM WifiLocation''')
		all_rows = cursor.fetchall()
		usageentries = len(all_rows)
		if usageentries > 0:
			logfunc(f'WiFi cell locations function executing')
			with open(reportfolderbase+'Wireless Locations/WiFi locations.html', 'w', encoding='utf8') as f:
				f.write('')
				f.write('
 WiFi locations report
')
				f.write(f'WiFi locations entries: {usageentries}
')
				f.write(f'WiFi ocations database located at: {filefound[0]}
')
				f.write('')
				f.write('
')
				f.write('')
				f.write(f'
')
				f.write(f'
Base1o MAC	Channel	Infomask	Speed	Course	Confidence	Score	Reach	Hoz. Acc.	Vert. Acc.	Latitude	Longitude	Timestamp
')
				for row in all_rows:
					f.write(f'
{row[0]}	{row[1]}	{row[2]}	{row[3]}	{row[4]}	{row[5]}	{row[6]}	{row[7]}	{row[8]}	{row[9]}	{row[10]}	{row[11]}	{row[12]}
')
				f.write(f'
')
				logfunc(f'WiFi locations function completed')
		else:
				logfunc('No WiFi locations available')
	except:
			logfunc('Error on WiFi locations function.')