#!/bin/bash

set -eu -o pipefail

# Set some variable

logpathname="/var/log/pbx/asterisk-switch-version"
logfilename="$(date +"%Y-%m-%d.%H:%M:%S.%Z")"
logfullname="$logpathname/$logfilename"
fwversion="$(/usr/sbin/fwconsole -V | /usr/bin/sed 's/^FW\sConsole.*Utility\s//g' | /usr/bin/cut -d. -f1)";
astsipdriver="$(/usr/sbin/fwconsole setting ASTSIPDRIVER | sed 's/.*select)//' | cut -d " " -f 1 2>/dev/null)";

if [[ ! -e "$logpathname" ]]; then
	mkdir -p "$logpathname"
fi

ver=""; pkg=""; ext=""
fullname=""; fulldesc=""

logmsg() { echo -e "$@" > "$logfullname"; }
saymsg() { logmsg "$@"; echo -e "$@"; }
banner() { printf "\n"; "$@"; printf "\n"; }


# Set the current asterisk version into logfile
# logmsg "Current Asterisk Version=$current_version"

title()
{
	g="\e[32m"; # Green
	b="\e[30m"; # black
	y="\e[33m"; # yellow
	w="\e[97m"; # white
	r="\e[31m"; # red
	n="\e[0m";  # normal
	# https://misc.flogisoft.com/bash/tip_colors_and_formatting
	curent_version=$(asterisk -V);
	/usr/bin/pgrep -x asterisk >/dev/null && pid=$g"is running"$n || pid=$r"is not running"$n

	clear
	echo -e "$n $w"
	echo -e "\tCurrent version:$n $y $curent_version $n$pid";
	echo
	echo -e "\t$y(LTS)$n = Long Term Support | $y(EOL)$n = End of Life | $y(S)$n = Standard"
}

pick_asterisk_version()
{
	g="\e[32m"; # Green
	y="\e[33m"; # yellow
	w="\e[97m"; # white
	r="\e[31m"; # red
	n="\e[0m";  # normal

	if ! [ $# -eq 0 ]
	then
		passedOpt=$1
	fi

	local picked=0
	while true
	do
		local opt
		echo
		echo -e "\tPress$g 1$n for $g Asterisk 18$y (EOL)$n"
		echo -e "\tPress$g 2$n for $g Asterisk 18$y (Certified)$n"
		echo -e "\tPress$g 3$n for $g Asterisk 20$y (LTS)$n"
		echo -e "\tPress$g 4$n for $g Asterisk 20$y (Certified)$n"
		echo -e "\tPress$g 5$n for $g Asterisk 21$y (S)$n"
		echo -e "\tPress$g 6$n for $g Asterisk 22$y (LTS)$n"
		echo -e "\tPress$g 7$n for $g Asterisk 23$y (S)$n"
		echo
		echo -e "\tPress$g q$n to exit and$w not change$n your Asterisk Version"
		echo
		echo -e "\t\e[43m${b}This action below will cause Asterisk to stop and all calls in progress will be terminated\e[0m"
		echo
		if [ -z ${passedOpt+x} ]
		then
			read -n1 -p "Please, select the Asterisk Version to change to : " opt
		else
			opt=$passedOpt
		fi

		case $opt in
			1) ver="18"; pkg="asterisk${ver}"       ; ext=""                  ; action[14]="allow"  ; action[15]="allow"    ; action[16]="allow"    ; action[17]="allow"    ; msg[14]="" ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			2) ver="18"; pkg="asterisk${ver}cert"  	; ext="Certified" ; action[14]="allow"	; action[15]="allow"	; action[16]="allow"	; action[17]="allow"	; msg[14]="" ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			3) ver="20"; pkg="asterisk${ver}"       ; ext=""          ; action[14]="block"  ; action[15]="allow"    ; action[16]="allow"    ; action[17]="allow"    ; msg[14]=""  ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			4) ver="20"; pkg="asterisk${ver}cert"  	; ext="Certified" ; action[14]="allow"	; action[15]="allow"	; action[16]="allow"	; action[17]="allow"	; msg[14]="" ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			5) ver="21"; pkg="asterisk${ver}"       ; ext=""          ; action[14]="block"  ; action[15]="allow"    ; action[16]="allow"    ; action[17]="allow"    ; msg[14]=""  ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			6) ver="22"; pkg="asterisk${ver}"       ; ext=""          ; action[14]="block"  ; action[15]="block"    ; action[16]="block"    ; action[17]="allow"    ; msg[14]=""  ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			7) ver="23"; pkg="asterisk${ver}"       ; ext=""          ; action[14]="block"  ; action[15]="block"    ; action[16]="block"    ; action[17]="allow"    ; msg[14]=""  ; msg[15]="" ; msg[16]="" ; msg[17]="" ;;
			Q|q)
				echo
				echo -e "Bye!"
				echo; exit 0
				;;
			*)
				if [ $# -eq 0 ]
				then
					echo; echo
					echo -e "\t\e[41mThe option you selected $opt is not valid.\e[0m"
					echo -e "\tPlease pick a valid option."
					sleep 2
					clear
					title
					continue
				fi

				echo; echo
				echo -e "\t\e[41mInvalid argument $opt\e[0m"
				echo
				exit 0
				;;
		esac

		if [[ ${action[${fwversion}]} = "block" ]]; then
			echo; echo
			echo -e "\t\e[1m${r}The selected Asterisk version ${w}${ver} ${ext}${r} is not supported on the installed PBX version.\e[0m"
			echo -e "\n\e[41m${b}${msg[${fwversion}]}\e[0m\n"
			sleep 5
			NOWAY=1
			break
		fi

		if [[ ${action[${fwversion}]} = "alert" ]]; then
			echo; echo
			echo -e "\e[41m${b}${msg[${fwversion}]}${n}\e[0m\n"
			confirmed=1
			while true; do
				read -n1 -p "Confirm the unrecommended Asterisk version. (y/N)? " CHK
				case $CHK in
					N|n) confirmed=0 ;;
				esac
				echo; break
			done
			if [[ $confirmed -eq 0 ]]; then
				NOWAY=1
				break
			fi
		fi

		echo; echo
		fullname="$pkg"
		fulldesc="Asterisk $ver"
		if [[ $ext != "" ]]; then
			fullname+=" $ext"
			fulldesc+=" $ext"
		fi

		#for asterisk version 21 or greater if chan_sip is selected then cannot upgrade to 21 or greater
		if [ $ver -ge 21 ]; then
			case "$astsipdriver" in
				*chan_sip*)
					;&
				*both*)
					echo -e "${y}\t You are currently using chan_sip driver and trying to upgrade to Asterisk ${r}$ver${y}, it's crucial to note that this asterisk version no longer supports the chan_sip driver. "
					echo -e "\t${y} To proceed with the upgrade smoothly, you have two options:"
					echo -e "\t${y} Transition to PJSIP: Update your existing SIP driver (${g}$astsipdriver${n})${y} configuration to PJSIP ."
					echo -e "\t${y} if required, convert legacy chan_sip extensions/trunks to pjsip via fwconsole cli utility before proceeding with the upgrade. "
					echo -e "\t${y} Only PJSIP is supported in Asterisk 21+ which offers enhanced features and performance compared to chan_sip. "
					echo -e "\t${y} Use a compatible Asterisk version: If transitioning to PJSIP is not feasible or preferred, consider using an Asterisk version that still supports the chan_sip driver."
					echo
					echo -e "\t${y} Exiting the asterisk switch process."

					sleep 20

					NOWAY=1
					break
					;;

				*chan_pjsip*)
					;;
			esac

		fi

		#If asterisk version is selected as a part of argument then no need to ask for confirmation
		if [ -z ${passedOpt+x} ]
		then
			while true; do
				read -n1 -p "Selected ${fulldesc}. Confirm (y/N)? " CONFIRM
				case $CONFIRM in
					Y|y) picked=1 ;;
				esac
				echo; break
			done
		else
			picked=1
		fi

		[[ $picked -eq 1 ]] && NOWAY=0; break
		clear
		title
	done
}

isinstalled()
{
	PKG_OK=$(/usr/bin/dpkg-query -W --showformat='${Status}\n' "$@" 2>/dev/null|grep "install ok installed")
	if [ "" = "$PKG_OK" ]; then
		false
	else
		true
	fi
}

pkg_install()
{
	PKG=$@
	if isinstalled $PKG; then
		logmsg "$PKG already present ...."
	else
		logmsg "Installing $PKG Now ...."
		apt-get -y --ignore-missing -o Dpkg::Options::="--force-confold" install $PKG 
		if isinstalled $PKG; then
			saymsg "$PKG installed successfully...."
		else
			saymsg "$PKG failed to install ...."
		fi
	fi
}


install_asterisk ()
{
	astver=$1
	ASTPKGS=("addons"
		"addons-bluetooth"
		"addons-core"
		"addons-mysql"
		"addons-ooh323"
		"core"
		"curl"
		"dahdi"
		"doc"
		"odbc"
		"ogg"
		"flite"
		"g729"
		"resample"
		"snmp"
		"speex"
		"sqlite3"
		"res-digium-phone"
		"voicemail"
	)

	banner echo "Installing to $astver"
	pkg_install $astver

	for i in "${!ASTPKGS[@]}"; do
		pkg_install $astver-${ASTPKGS[$i]}
	done
	pkg_install $astver.0-freepbx-asterisk-modules
	pkg_install sangoma-pbx${fwversion}
}

switch_asterisk_version()
{
	banner echo "Switching to $fullname"
	apt-get -y remove asterisk[1-99]* libjansson-dev
	apt-get -y --ignore-missing -o Dpkg::Options::="--force-confold"  install dpkg-dev
	install_asterisk ${pkg}
	apt-get -y --ignore-missing -o Dpkg::Options::="--force-overwrite" install jansson*
}

verify_asterisk_package()
{
	if [[ $(/usr/bin/dpkg-query -S "${pkg}*" | wc -l ) -gt 0 ]]; then
		banner saymsg "$fullname has now been verified to be installed"
	else
		banner saymsg "$fullname installation had an issue and was NOT completed"
		echo "Review the console logs and resolve the RPM conflicts first,"
		echo "then rerun this script to try again."
		echo
		exit 1
	fi
}

SYSLIBPATH="$(grep '^/lib' /etc/ld.so.conf.d/`dpkg-architecture -qDEB_HOST_GNU_TYPE`.conf)"
LIBPATH=$SYSLIBPATH/asterisk/modules

DPMA="no"
if [ -e "$LIBPATH/res-digium-phone.so" ]; then
	DPMA="yes"
fi

NOWAY=1;

if [[ $# -eq 1 ]]
then
	if [ "$1" = "-v" ]
	then
		/usr/bin/dpkg-query -W --showformat='${Version}\n'  asterisk-version-switch
		echo; exit 0
	fi
fi

while [[ $NOWAY -eq 1 ]]
do
	title
	if [ $# -eq 0 ]
	then
		pick_asterisk_version
	else
		pick_asterisk_version $1
	fi
done

logmsg "New Asterisk Version=$pkg ($fullname)"

banner echo "You picked $pkg - clearing apt cache"
apt-get clean all

switch_asterisk_version
verify_asterisk_package

if [ -e "$LIBPATH/res_amqp.so" ]; then
	saymsg "Yes.\nres_amqp is installed.  You will need to reinstall this module after the switch"
fi

for libpath in "$LIBPATH"
do
	[[ ! -d "$libpath" ]] && continue

#echo "Checking for orphaned asterisk files in ${libpath}..."

#find $libpath -type f -exec /bin/sh -c "rpm -qf {} &> /dev/null || echo {}" \; | while read -r line ; do
#               echo -e "\tFound orphaned module of $line"
#               echo -e "\t\tMoving $line to /tmp to prevent asterisk crashes, if you need this file you can manually restore it"
#               mv -f $line /tmp
#       done
#       echo "Finished checking ${libpath}"
done

echo Restarting Asterisk...
fwconsole restart

echo Regenerate FreePBX Dialplan...
fwconsole reload

echo Chowning all needed files
fwconsole chown

