#!/bin/bash

# _______________			 ______ ______			  ______  
# ___  ____/__  /_____ __________  /____  /_______ _________  /__
# __  /_   __  /_  __ `/_  ___/_  __ \_  __ \  __ `/  ___/_  //_/
# _  __/   _  / / /_/ /_(__  )_  / / /  /_/ / /_/ // /__ _  ,<   
# /_/	  /_/  \__,_/ /____/ /_/ /_//_.___/\__,_/ \___/ /_/|_| 
# "Backup, restore, and share your iOS setups."

# Notes:
# ** This is a dangerous script if something goes wrong. ** 
# Should be using printf instead of 'echo -e'
# "set -e" should be used instead of || (at least we have some fancy debug messages)
# DO NOT USE "cp -f" WHEN REPLACING SYSTEM FILES. Its dangerous, but yet no other solution comes to mind.

DEBUG="echo" # set to "echo" to avoid running commands that edit the filesystem.
FLASHBACKDIR="/Library/FlashBack"
BACKUPNAME=$(date +%m-%d-%y-`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1`)
BACKUPLOCATION=
STATUS=
SELECTLOCATION=
AUTOBACKUPLOCATION=
DELETEBACKUP=
DELETESELECT=

FBVERSION="v1_6"
PKGVERSION="1.6"

# report(){ # report to dev example function
# echo "$foo-bar has went wrong"
# echo "Report the dev if this happens more than once"
# exit 1 ; fi ;} # Kill the script

tests() { 
if [ ! $(id -u) = "0" ] ; then # root check
	echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mMust be \e[4;37mroot\e[0m \n\e[1;31m\e[0;100m[*]\e[0m Current User is\e[0m \e[4;37m$USER\e[0m\n"
exit 1 ; fi

if [ ! -d $FLASHBACKDIR/Backups ] ; then # check for /Library/Flashback/Backups, ask the user to create it if it doesn't exist.
	echo -e "\n\e[0;100m[*]\e[0m\e[1;31m Directory $FLASHBACKDIR/Backups doesn't exist!\e[0m \n\n\e[1;37mShall it be created?\e[0m"
	read -rp "	[y/N] " response # https://stackoverflow.com/questions/3231804/in-bash-how-to-add-are-you-sure-y-n-to-any-command-or-alias
		if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]] # Couldn't remember the expression for this.
		 then 	# Do it.
		 	mkdir -p $FLASHBACKDIR/Backups || exit 1
				 else 	# or Abort.
		 	echo -e "\n\e[1;97m\"Run away! Run away!\" \e[0m\n" 
				exit 1; fi; fi ;}
# -----------------------\

pause(){
	read -sp "`echo -e '\n\e[0;100m[!]\e[0m \e[104mPress enter to continue...\e[0m'`" -t 120  # read has a timeout function that could be used to advance the script by its own.
		exit_status=$?
		if [[ $exit_status -eq 142 ]]; then
    		exit 0
		fi
	echo -e "\n" ;}
	
# -----------------------\ 

shopt -s extglob # "Shell option set extglob" https://www.linuxjournal.com/content/bash-extended-globbing 

# -----------------------\

one() { # Function that backs-up the current preferences
	set -f # "Disable file name generation (globbing)."
	
	TEMPBACKUPNAME=
	read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter backup name...\e[0m'` > " TEMPBACKUPNAME # BACKUPNAME has the date
	
	TEMPBACKUPNAME=${TEMPBACKUPNAME//[^a-zA-Z0-9-.]/} # Stop bad inputs
	if [[ $TEMPBACKUPNAME = "" ]] ; then
		echo -e "\n\e[0;100m[!]\e[0m \e[104mBad or no input... Using $BACKUPNAME instead\e[0m"
	else
		TEMPBACKUPNAME=${TEMPBACKUPNAME//[^a-zA-Z0-9-.]/}
		BACKUPNAME=$TEMPBACKUPNAME; fi
	set +f
	BACKUPLOCATION=$FLASHBACKDIR/Backups/$BACKUPNAME
	mkdir -p $BACKUPLOCATION/{Preferences,SBFolder,WidgetsInfo/SBHTML,WidgetsInfo/LocKHTML} || STATUS="mkdir failed"
	echo -e "\n\e[0;100m[!]\e[0m \e[104mCopying to $BACKUPLOCATION\e[0m"
	
	cp -rf "/var/mobile/Library/Preferences/"!(com.apple*|com.saurik*|ckkeyrolld|nfcd|UITextInputContextIdentifiers|.GlobalPreferences).plist $BACKUPLOCATION/Preferences/ || STATUS="cp failed" #copy all non-apple Plists to Preference folder within backup haha
	cp -rf /var/mobile/Library/SpringBoard/@(*Icon*|*Background*|SB*) $BACKUPLOCATION/SBFolder/ || STATUS="cp failed"		#copy IconState Plist to SBFolder folder within backup
		
	touch $BACKUPLOCATION/$FBVERSION
	
	# |||||||||||||||||||||||||||||||||||
	if [[ ! $STATUS = "" ]] ; then
		echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mSomething went wrong: $STATUS \e[0m\n"
		exit 1 ; fi # TODO MCApollo: Make a report to developer function.
	# //////////////////////////////////
	
	echo -e "\n\e[104m Success! \e[0m \n"
	
	pause ;}

# -----------------------\

two() { # Restore backups made with function one

	# TODO: MCApollo
	# Check if any backups exist before doing this.
	# We softlock if we don't have any backups
	
	echo -e "\n\e[104m Available Backups: \e[0m \n"
	for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files.
		echo -e " \e[100m---->\e[0m  \e[33m$i\e[0m" ; done
	 
	SELECTBACKUP=
	while [[ $SELECTBACKUP = "" ]] ; do
		set -f
		unset RESET
		read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mSelect Backup\e[0m'` -> " SELECTBACKUP
		SELECTBACKUP=${SELECTBACKUP//[^a-zA-Z0-9-.]/}
		if [[ $SELECTBACKUP = "" ]] ; then
			echo -e "\n\e[0;100m[*]\e[0m \e[1;31mBad or no input!\e[0m\n" 
			RESET="YES"; fi
		if [[ ! -d $FLASHBACKDIR/Backups/$SELECTBACKUP ]] && [[ -z ${RESET+x} ]]  ; then
						echo -e "\n\e[0;100m[*]\e[0m \e[1;31mNo backup with that name exists!\e[0m"
						SELECTBACKUP="" ; fi
		
		set +f ; done
		
	SELECTLOCATION=$FLASHBACKDIR/Backups/$SELECTBACKUP
	
	if [ -f $SELECTLOCATION/$FBVERSION ] || [ -f $SELECTLOCATION/1.5 ] || [ -f $SELECTLOCATION/1.5.1 ] || [ -f $SELECTLOCATION/1.4 ]
	then
	
		AUTOBACKUPLOCATION=$FLASHBACKDIR/Backups/AutoBackup_$(date '+%d-%m-%Y_%H:%M:%S')
		
		echo -e "\n\e[0;100m[!]\e[0m \e[104mMoving current Preferences to $AUTOBACKUPLOCATION\e[0m"
		
		mkdir -p $AUTOBACKUPLOCATION/{Preferences,SBFolder} || STATUS="mkdir failed"
		cp "/var/mobile/Library/Preferences/"!(com.apple*|com.saurik*|ckkeyrolld|nfcd|UITextInputContextIdentifiers).plist  $AUTOBACKUPLOCATION/Preferences || STATUS="cp failed"
		cp -r /var/mobile/Library/SpringBoard/@(*Icon*|*Background*|SB*) $AUTOBACKUPLOCATION/SBFolder/ || STATUS="cp failed"
		touch $AUTOBACKUPLOCATION/$FBVERSION
		
		echo -e "\n\e[0;100m[!]\e[0m \e[104mCopying Backup to appropriate system directories...\e[0m"
		
		cp -r $SELECTLOCATION/Preferences/*.plist /var/mobile/Library/Preferences/ || STATUS="cp failed"
		cp -r $SELECTLOCATION/SBFolder/* /var/mobile/Library/SpringBoard/ || STATUS="cp failed"
		
		echo -e "\n\e[0;100m[*]\e[0m \e[104mRebuilding image cache...\e[0m"
		
		uicache || STATUS="uicache failed"
		recache --no respring || echo -e "\n\e[0;100m[*]\e[0m \e[104mAnemone not installed. Proceeding anyway.\e[0m"
		killall cfprefsd #Clear settings caches - thanks to Grant/NewD
		
		if [[ ! $STATUS = "" ]] ; then
		echo -e "\a\n\e[0;100m[*]\e[0m \e[1;31mSomething went wrong: $STATUS \e[0m\n"
		exit 1 ; fi # TODO: Make a report to developer function.
		
		if [ -z ${SSH_TTY+x} ] ; then # Should we kill SpringBoard or not?
			# This is NewTerm
			echo -e "\a\n\e[0;100m[!]\e[0m \e[1;31mKilling SpringBoard \e[0m\n\n\e[0;100m Thank you for using Flashback! \e[0m"
			killall -9 SpringBoard && exit 0 # Kill the script.
		else
			# This is a SSH Session
			echo -e "\a\n\e[0;100m[!]\e[0m \e[1;31mKilling SpringBoard \e[0m\n\n\e[0;100m Thank you for using Flashback! \e[0m"
			killall -9 SpringBoard
		fi
	
	else
	
		echo -e "\n\e[0;100m[*]\e[0m \e[1;31mIncompatible Backup Version!\e[0m"
	
	fi
	pause ;}
	
three(){ # Function that deletes backups
	echo -e "\n\e[104m Available Backps: \e[0m \n"
	for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files.
		echo -e " \e[100m---->\e[0m  \e[33m$i\e[0m" ; done
		
	DELETEBACKUP=
	while [[ $DELETEBACKUP = "" ]] ; do
				unset RESET
				set -f
				read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mSelect Backup\e[0m'` -> " DELETEBACKUP
				DELETELOCATION=$FLASHBACKDIR/Backups/$DELETEBACKUP
				#DELETEBACKUP=${DELETEBACKUP//[^a-zA-Z0-9-.]/}
			   if [[ $DELETEBACKUP = "" ]]; then
						echo -e "\n\e[0;100m[*]\e[0m \e[1;31mBad or no input!\e[0m" 
								RESET="YES" ; fi
			   if [[ ! -d $DELETELOCATION ]] && [[ -z ${RESET+x} ]]  ; then
						echo -e "\n\e[0;100m[*]\e[0m \e[1;31mNo backup with that name exists!\e[0m"
						DELETEBACKUP="" ; fi
			   set +f ; done
	
	DELETECP=
	echo -e "\n\e[0;100m[!]\e[0m\e[1;31m Are you REALLY sure you want to delete this backup?\e[0m\n \n\e[1;37mType \"FLASHBACK\" exactly the way it is if you're sure!\e[0m\n"
	read -p "`echo -e ' \e[0;100m---->\e[0m \e[1;31m'` " DELETECP
	if [[ $DELETECP = "FLASHBACK" ]]
	then
		echo -e "\n\e[0;100m[!]\e[0m \e[104mDeleting $DELETELOCATION\e[0m"
		rm -r $DELETELOCATION
	else
	echo -e "\n\e[0;100m[!]\e[0m \e[104mNot deleting $DELETELOCATION\e[0m"; fi
	
	pause ;}

four(){ # Function that deletes autobackups made in function two
	DELETEAB=
	echo -e "\n\e[0;100m[!]\e[0m\e[1;31m Are you REALLY sure you want to delete all AutoBackups?\e[0m\n \n\e[1;37mType \"FLASHBACK\" exactly the way it is if you're sure!\e[0m\n"
	read -p "`echo -e ' \e[0;100m---->\e[0m \e[1;31m'` " DELETEAB
	if [[ $DELETEAB = "FLASHBACK" ]]
	then
		echo -e "\n\e[0;100m[!]\e[0m \e[104mDeleting all autobackups...\e[0m"
		rm -r $FLASHBACKDIR/Backups/AutoBackup*
	else
		echo -e "\n\e[0;100m[!]\e[0m \e[104mExiting...\e[0m"; fi
	pause ;}
	
five(){ # I'm not going to painstakingly fix this. You gotta do that yourself. - Apollo
	echo -e "\n\e[104m Available Backps: \e[0m \n"
	for i in $(ls $FLASHBACKDIR/Backups/ || echo "#CRTL-C_to_exit#") ; do # Find and sed are not default commands- can't exclude files.
		echo -e " \e[100m---->\e[0m  \e[33m$i\e[0m" ; done
	read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mChoose a Backup\e[0m'` > " PACKAGEBACKUP
	read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter Your UserName\e[0m'` > " USERNAME
	read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mEnter A Short Description\e[0m'` > " USERDESC
	
	# TODO: MCApollo
	# Clean the input, wildcard (*) makes it game over.
	echo -e "\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\nWould you like to specify dependancies?\nIf so, it's recommended to use iCleaner Pro to clean up unused preference files before you start.\n\n\e[0;100mAutomatic:\e[0m You select which packages are dependancies, for a streamlined installation.\nThis is highly recommended if you intend to host your setup on a repo, or share with other users.\n\n\e[0;100mManual:\e[0m Dependancies are not set for users, they must install the tweaks themselves.\nThis is recommended if you plan to use this setup personally.\n\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m"
	read -p "`echo -e '\n\e[0;100m[!]\e[0m \e[104mWould you like to proceed in automatic mode? (yes/no)\e[0m'` > " autoMode
	
	if [[ $autoMode = "yes" ]]
	then
		read -p "`echo -e '\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\n\e[0;100m[!]\e[0m Staring automatic mode. A list of installed packages will appear in a moment.\nUse that list to select which packages are dependancies. \e[104mPress enter to proceed.\e[0m'` > "
		apt-mark auto "gsc*" &> /dev/null || STATUS="apt-mark failed"
		# For some reason, apt likes to seg fault. Maybe due to too much memory is being used?
		echo -e "\n\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m"
		apt-mark showmanual || STATUS="SEG FAULT"
		
		# TODO: MCApollo
		# Copy paste the STATUS check and exit if seg fault.
		# Or better yet, the exit code is 139 if it's a seg fault.
		# Use the exit code to see if apt seg fault; exit or try again once.
		
		read -p "`echo -e '\e[0;100m~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m\n\e[0;100m[!]\e[0m \e[104mPlease copy all desired dependancies from above EXACTLY as they are displayed. Separate them with a comma and a space (, )\e[0m'` > " USERSETDEPENDENCIES
	fi
	
	mkdir $FLASHBACKDIR/tmp
	WORKINGDIR=$FLASHBACKDIR/tmp/$PACKAGEBACKUP
	mkdir $WORKINGDIR
	mkdir $WORKINGDIR/DEBIAN
	
	mkdir -p $WORKINGDIR$FLASHBACKDIR/Backups/$PACKAGEBACKUP # Correct answer; you're hard-coding /Library/FlashBack
	
	cp -r $FLASHBACKDIR"/Backups/"$PACKAGEBACKUP/!(control*) $WORKINGDIR/Library/FlashBack/Backups/$PACKAGEBACKUP/
	
	if [[ $autoMode = "yes" ]]
	then

cat > $WORKINGDIR/DEBIAN/control <<EOF
Package: com.$USERNAME.$PACKAGEBACKUP
Name: $PACKAGEBACKUP
Depends: com.mpg13.FlashBack, $USERSETDEPENDENCIES
architecture: iphoneos-arm
Version:$PKGVERSION
Description: $USERDESC
Maintainer: $USERNAME
Author: $USERNAME
Section: Addons (FlashBack)
EOF

	else
	
cat > $WORKINGDIR/DEBIAN/control <<EOF
Package: com.$USERNAME.$PACKAGEBACKUP
Name: $PACKAGEBACKUP
Depends: com.mpg13.FlashBack
architecture: iphoneos-arm
Version:$PKGVERSION
Description: $USERDESC
Maintainer: MPG13
Author: $USERNAME
Section: Addons (FlashBack)
EOF

	fi
	
	dpkg-deb -Zgzip -b $WORKINGDIR &> /dev/null
	echo -e "\e[0;100m[!]\e[0m Creating DEB..."
	cp $WORKINGDIR.deb $FLASHBACKDIR
	rm -r -f $FLASHBACKDIR/tmp
	
	echo -e "\n\e[0;100m[!]\e[0mThe DEB can be found in "$FLASHBACKDIR"/"com.$USERNAME.$PACKAGEBACKUP".deb"

# TODO MCApollo
# Use dpkg-deb or dpkg to make sure it's a vaild package. (Maybe extract it?) 

	pause
}

# TODO Idea: MCApollo
# Get the amount of $COLUMNS and $LINES, scale the UI base on that information
# For example, (( ~ X $COLUMNS)) into a VAR and then echo $VAR instead of hard-coding "~~~~~~~~~~~"

show_menus() {
	clear
	echo -e "   _____________________ \n  |  ___      ___       |\n  | | __|    | _ )      |\n  | | _|     | _ \      |\n  | |_| LASH |___/ACK   |\n  |_____________________|"
	echo -e "\n\e[1;32m   Please read the FAQ\n   in the Cydia package\n   depiction!" 
	echo -e "\n\e[1;31m   When inputting backup\n   names,use plaintext\n   and numbers ONLY!\n   Special characters\n   may result in dangerous\n   side effects!\e[0m\n"
	echo -e "\e[0;100m[1.]\e[0m \e[33mBackup Current Preferences\e[0m"
	echo -e "\e[0;100m[2.]\e[0m \e[33mRestore Backup\e[0m"
	echo -e "\e[0;100m[3.]\e[0m \e[33mDelete Backups\e[0m"
	echo -e "\e[0;100m[4.]\e[0m \e[33mDelete AutoBackups\e[0m"
	echo -e "\e[0;100m[5.]\e[0m \e[33mPackage Backup to DEB\e[0m"
	echo -e "\e[0;100m[6.]\e[0m \e[91mQuit\e[0m"
}

read_options(){
	local choice
	read -p "`echo -e '\e[0;100m[!]\e[0m \e[104mEnter choice [1 - 6]\e[0m'` > " choice
	case $choice in
		1) one ;;
		2) two ;;
		3) three ;;
		4) four ;;		
		5) five;;
		6) exit 0;;
		*) echo "Invalid Selection!" && sleep 2
	esac
}

tests
while true
do
 	shopt -s extglob
	show_menus
	echo " "
	read_options
done
