#!/bin/bash

################################################################################
#
# zaptel init script
#
# Copyright (C) 2005, Nadi Sarrar
#
# Nadi Sarrar <nadi@beronet.com>
#
# This program is free software, distributed under the terms of
# the GNU General Public License
#

#
# USAGE:
#
#   /etc/init.d/zaptel start|stop|restart|scan|deepscan|config|help
#

#
# CONFIGURATION:
#
LOADORDER="wct1xxp,wcte11xp,wct4xxp,tor2,wctdm"
PRITYPE="E1" # "E1" or "T1" or "Channelbank"
DCHAN=16

E1_options="ccs,hdb3,crc4"
T1_options="esf,b8zs"
PRI_signalling="pri_cpe"
#
################################################################################

ZAPTELCONF=/etc/zaptel.conf
ZAPATACONF=/etc/asterisk/zapata.conf
#ZAPTELCONF=./zaptel.conf
#ZAPATACONF=./zapata.conf

THISPATH=/etc/init.d/zaptel

ANAmod=wctdm
ANArmmod=wcfxs
PRI1mod_old=wct1xxp
PRI1mod=wcte11xp
PRI4mod=wct4xxp
TOR2mod=tor2
ZTDUMMY=ztdummy

LSPCI=lspci
LSMOD=lsmod
MODPROBE=modprobe
RMMOD=rmmod
DMESG=dmesg
ZTCFG=ztcfg

PRI1cards_old=0
PRI1cards=0
PRI4cards=0
TOR2cards=0
PRI2cards=0
ANAcards=0
	
IFS=$'\n'
NL="
"

function scan_analog_modules {

	if ${LSMOD} | grep ${ANArmmod} > /dev/null ; then
		echo "[ i] unloading module: ${ANArmmod}"
		eval "${RMMOD} ${ANArmmod} 2> /dev/null"
		unloaded="1"
	fi
	
	${DMESG} -c > /dev/null

	echo "[ i] loading module: ${ANAmod}"
	eval "${MODPROBE} ${ANAmod} 2> /dev/null"

	index=1
	for line in $(${DMESG} | sed -ne '/Module/{s/^Module [0123]: \(.*\)$/\1/p}'); do
		ANAmodules[${index}]=${line}
		let "index = ${index} + 1"
	done
	
	if [ "${unloaded}" == "" ]; then
		echo "[ i] unloading module: ${ANArmmod}"
		eval "${RMMOD} ${ANArmmod} 2> /dev/null"
	fi
}

function scan_cards {
	for line in $(${LSPCI} -n -d "e159:0001"); do
		busslot=$(echo ${line} | sed -e 's/[^:]*:\([^ ]*\).*/\1/')
		subid=$(${LSPCI} -nv -s "${busslot}" | sed -ne '/.*Subsystem: /{s/.*Subsystem: \(....\):.*/\1/;p}')
		case "${subid}" in
			a159|e159|b100|b1d9|b119|a9fd|a8fd|a800|a801|a908|a901)
				let "ANAcards = ${ANAcards} + 1"
			;;
			6159)
				let "PRI1cards_old = ${PRI1cards_old} + 1"
			;;
			71fe|79fe|795e|79de|797e)
				let "PRI1cards = ${PRI1cards} + 1"
			;;
		esac
	done
	for line in $(${LSPCI} -n -d "10b5:d00d"); do
		let "TOR2cards = ${TOR2cards} + 1"
	done
	for line in $(${LSPCI} -n -d "10ee:0314"); do
		let "PRI4cards = ${PRI4cards} + 1"
	done
	for line in $(${LSPCI} -n -d "d161:*"); do
		devid=$(echo ${line} | sed -e 's/.*d161:\(....\).*$/\1/')
		case "${devid}" in
			0410|0405)
				let "PRI4cards = ${PRI4cards} + 1"
				;;
			0205|0210)
				let "PRI2cards = ${PRI2cards} + 1"
				;;
		esac
	done
}

function load_modules {
	
	scan_cards
	
	function load_module {
		echo "[ i] loading module: ${1}"
		eval "${MODPROBE} ${1} 2> /dev/null"
	}

	if [ $(echo "${PRI1cards_old}+${PRI1cards}+${PRI4cards}+${TOR2cards}+${PRI2cards}+${ANAcards}"|bc) -eq 0 ]; then
		load_module ${ZTDUMMY}
	else	
		
		IFS=$','

		for _mod in ${LOADORDER}; do
			case ${_mod} in
				${PRI1mod_old})
					if [ ${PRI1cards_old} -gt 0 ]; then
						load_module ${PRI1mod_old}
					fi
					;;
				${PRI1mod})
					if [ ${PRI1cards} -gt 0 ]; then
						load_module ${PRI1mod}
					fi
					;;
				${PRI4mod})
					if [ ${PRI4cards} -gt 0 ] || [ ${PRI2cards} -gt 0 ]; then
						load_module ${PRI4mod}
					fi
					;;
				${TOR2mod})
					if [ ${TOR2cards} -gt 0 ] ; then
						load_module ${TOR2mod}
					fi
					;;
				${ANAmod}|${ANArmmod})
					if [ ${ANAcards} -gt 0 ]; then
						load_module ${ANAmod} ${ANArmmod}
					fi
					;;
			esac
		done
		
		IFS=$'\n'
	fi

	eval "${ZTCFG} 2> /dev/null"
	if [ "$?" == "0" ]; then
		echo "[ i] success."
	else
		echo "[!!] something failed! here is the output of \"${ZTCFG}\":"
		eval "${ZTCFG}"
	fi
}

function unload_modules {
	for mod in $(${LSMOD} | sed -ne '/Module/!{s/\([^ ]*\).*/\1/;p}');
	do
		case "${mod}" in
			${ANArmmod}|${PRI1mod}|${PRI1mod_old}|${PRI4mod}|${ZTDUMMY})
				echo "[ i] unloading module: ${mod}"
				eval "${RMMOD} ${mod} 2> /dev/null"
			;;
		esac
	done
}

function create_config_files {

	zaptel_conf="${NL}loadzone=fr${NL}defaultzone=fr${NL}"
	zapata_conf="${NL}[channels]${NL}context=default${NL}group=0${NL}"

	spancount=1
	chancount=1
	ccount=1

	if [ "${T1_options}" != "" ]; then
		T1_options=",${T1_options}"
	fi
	if [ "${E1_options}" != "" ]; then
		E1_options=",${E1_options}"
	fi

	function get_channel_str {
		case ${DCHAN} in
			1)
				echo "$(echo "${1}+1" | bc)-$(echo "${1}+${2}-1" | bc)"
				;;
			2)
				echo "${1},$(echo "${1}+2" | bc)-$(echo "${1}+${2}-1" | bc)"
				;;
			$(echo "${2}-1" | bc))
				echo "${1}-$(echo "${1}+${2}-3" | bc),$(echo "${1}+${2}-1" | bc)"
				;;
			${2})
				echo "${1}-$(echo "${1}+${2}-2" | bc)"
				;;
			*)
				echo "${1}-$(echo "${1}+${DCHAN}-2" | bc),$(echo "${1}+${DCHAN}" | bc)-$(echo "${1}+${2}-1" | bc)"
				;;
		esac
	}
	

	IFS=$','
	done_pri1=0
	done_pri4=0
	for _mod in ${LOADORDER}; do
		case ${_mod} in
			${PRI1mod}|${PRI1mod_old}|${PRI4mod}|${TOR2mod})
				if [ "${_mod}" == "${PRI4mod}" -o "${_mod}" == "${TOR2mod}" ]; then
					if [ ${done_pri4} -eq 1 ]; then
						continue
					else
						done_pri4=1
						end=$(echo "(${PRI4cards} * 4) + (${PRI2cards} * 2)+ (${TOR2cards}*4)" | bc)
					fi
				elif [ ${done_pri1} -eq 1 ]; then
					continue
				else
					done_pri1=1
					end=${PRI1cards}
				fi
				index=0
				while [ ${index} -lt ${end} ]; do
					case ${PRITYPE} in
						T1)
							channel_str=$(get_channel_str ${chancount} "24")
							zaptel_conf="${zaptel_conf}${NL}# PRI port ${spancount} (T1)${NL}span=${spancount},0,0${T1_options}${NL}bchan=${channel_str}${NL}dchan=$(echo "${chancount}+${DCHAN}-1" | bc)${NL}"
							zapata_conf="${zapata_conf}${NL}; PRI port ${spancount} (T1)${NL}; context=${ccount}${NL}; group=${ccount}${NL}signalling=${PRI_signalling}${NL}channel=>${channel_str}${NL}"
							let "chancount = ${chancount} + 24"
						;;
						E1)
							channel_str=$(get_channel_str ${chancount} "31")
							zaptel_conf="${zaptel_conf}${NL}# PRI port ${spancount} (E1)${NL}span=${spancount},0,0${E1_options}${NL}bchan=${channel_str}${NL}dchan=$(echo "${chancount}+${DCHAN}-1" | bc)${NL}"
							zapata_conf="${zapata_conf}${NL}; PRI port ${spancount} (E1)${NL}; context=${ccount}${NL}; group=${ccount}${NL}signalling=${PRI_signalling}${NL}channel=>${channel_str}${NL}"
							let "chancount = ${chancount} + 31"
						;;
						Channelbank)
							zaptel_conf="${zaptel_conf}${NL}# PRI port ${spancount} (Channelbank)${NL}span=${spancount},0,0${T1_options}${NL}fxoks=${chancount}-$(echo "${chancount}+23" | bc)${NL}"
							zapata_conf="${zapata_conf}${NL}; PRI port ${spancount} (Channelbank)${NL}; context=${ccount}${NL}; group=${ccount}${NL}signalling=${PRI_signalling}${NL}channel=>${chancount}-$(echo "${chancount}+23" | bc)${NL}"
							let "chancount = ${chancount} + 24"
						;;
					esac
					let "spancount = ${spancount} + 1"
					let "ccount = ${ccount} + 1"
					let "index = ${index} + 1"
				done
				;;
			${ANAmod}|${ANArmmod})
				if [ ${ANAcards} -gt 0 ]; then
					index=1
					while [ ! -z ${ANAmodules[${index}]} ]; do
						if echo ${ANAmodules[${index}]} | grep "FXO" > /dev/null ; then
							FXSKS="${FXSKS}${chancount},"
						elif echo ${ANAmodules[${index}]} | grep "FXS" > /dev/null ; then
							FXOKS="${FXOKS}${chancount},"
						fi
						let "index = ${index} + 1"
						let "chancount = ${chancount} + 1"
					done
					IFS=$'\n'
					if [ "${FXSKS}" != "" ]; then
						channel_str="$(echo ${FXSKS} | sed -e 's/^\(.*\),$/\1/')"
						zaptel_conf="${zaptel_conf}${NL}# Analog channel(s), type: fxsks${NL}fxsks=${channel_str}"
						zapata_conf="${zapata_conf}${NL}; Analog channel(s), type: fxsks${NL}; context=${ccount}${NL}; group=${ccount}${NL}signalling=fxs_ks${NL}channel=>${channel_str}${NL}"
						let "ccount = ${ccount} + 1"
					fi
					if [ "${FXOKS}" != "" ]; then
						channel_str="$(echo ${FXOKS} | sed -e 's/^\(.*\),$/\1/')"
						zaptel_conf="${zaptel_conf}${NL}# Analog channel(s), type: fxoks${NL}fxoks=${channel_str}"
						zapata_conf="${zapata_conf}${NL}; Analog channel(s), type: fxoks${NL}; context=${ccount}${NL}; group=${ccount}${NL}signalling=fxo_ks${NL}channel=>${channel_str}${NL}"
						let "ccount = ${ccount} + 1"
					fi
					zaptel_conf="${zaptel_conf}${NL}"
					zapata_conf="${zapata_conf}${NL}"
					IFS=$','
				fi
				;;
			esac
	done
	IFS=$'\n'

	function write_file {
		if [ -f "${1}" ]; then
			echo "[ i] \"${1}\" already present. saving a backup: \"${1}.save\""
			cp "${1}" "${1}.save"
			if [ "$?" == "0" ]; then
				echo "${2}" > ${1}
			else
				echo "[!!] failed writing to file: \"${1}.save\". check permissions and rerun \"${THISPATH} config\"."
				exit 1;
			fi
		else
			echo "${2}" > ${1}
		fi
	}
	
	write_file "${ZAPTELCONF}" "${zaptel_conf}"
	write_file "${ZAPATACONF}" "${zapata_conf}"
}

case "$1" in
	
	start|--start|restart|--restart)
		echo "[ i] (re)loading modules for your zaptel cards in the order: ${LOADORDER}"
		unload_modules
		sleep 1
		load_modules
		;;
	stop|--stop)
		unload_modules
		;;
	scan|--scan)
		scan_cards
		echo -n "[ i] scan results:"
		if [ $(echo "${PRI1cards_old}+${PRI1cards}+${PRI4cards}+${PRI2cards}+${ANAcards}"|bc) -eq 0 ]; then
			echo " no cards found!"
		else
			echo
		fi

		IFS=$','
		for _mod in ${LOADORDER}; do
			case ${_mod} in
				${PRI1mod_old})
					if [ ${PRI1cards_old} -gt 0 ]; then
						echo "     PRI 1-Port (${PRI1mod_old}) cards: ${PRI1cards_old}"
					fi
					;;
				${PRI1mod})
					if [ ${PRI1cards} -gt 0 ]; then
						echo "     PRI 1-Port (${PRI1mod}) cards: ${PRI1cards}"
					fi
					;;
				${TOR2mod})
					if [ ${TOR2cards} -gt 0 ]; then
						echo "     PRI 4-Port (${TOR2mod}) cards: ${TOR2cards}"
					fi
					;;
				${PRI4mod})
					if [ ${PRI2cards} -gt 0 ]; then
						echo "     PRI 2-Port (${PRI4mod}) cards: ${PRI2cards}"
					fi
					if [ ${PRI4cards} -gt 0 ]; then
						echo "     PRI 4-Port (${PRI4mod}) cards: ${PRI4cards}"
					fi
					;;
				${ANAmod}|${ANArmmod})
					if [ ${ANAcards} -gt 0 ]; then
						echo "     Analog (${ANAmod}) cards: ${ANAcards}"
					fi
					;;
				esac
		done
		IFS=$'\n'
		if [ ${ANAcards} -gt 0 ]; then
			echo ""		
			echo "[ i] to scan the modules on your analog"
			echo "     card(s), run \"${THISPATH} deepscan\"."
		fi
		;;
	deepscan|--deepscan)
		scan_cards
		if [ ${ANAcards} -gt 0 ]; then
			scan_analog_modules
		fi
		echo -n "[ i] scan results:"
		if [ $(echo "${PRI1cards_old}+${PRI1cards}+${PRI4cards}+${PRI2cards}+${ANAcards}"|bc) -eq 0 ]; then
			echo " no cards found!"
		else
			echo
		fi
		IFS=$','
		for _mod in ${LOADORDER}; do
			case ${_mod} in
				${PRI1mod_old})
					if [ ${PRI1cards_old} -gt 0 ]; then
						echo "     PRI 1-Port (${PRI1mod_old}) cards: ${PRI1cards_old}"
					fi
					;;
				${PRI1mod})
					if [ ${PRI1cards} -gt 0 ]; then
						echo "     PRI 1-Port (${PRI1mod}) cards: ${PRI1cards}"
					fi
					;;
				${PRI4mod})
					if [ ${PRI2cards} -gt 0 ]; then
						echo "     PRI 2-Port (${PRI4mod}) cards: ${PRI2cards}"
					fi
					if [ ${PRI4cards} -gt 0 ]; then
						echo "     PRI 4-Port (${PRI4mod}) cards: ${PRI4cards}"
					fi
					;;
				${ANAmod}|${ANArmmod})
					if [ ${ANAcards} -gt 0 ]; then
						echo "     Analog (${ANAmod}) cards: ${ANAcards}"
						index=1
						while [ ! -z ${ANAmodules[${index}]} ]; do
							echo "        Module ${index}: ${ANAmodules[${index}]}"
							let "index = ${index} + 1"
						done
					fi
					;;
				esac
		done
		IFS=$'\n'
		;;
	config|--config)
		echo "[ i] scanning your devices..."
		scan_cards
		if [ ${ANAcards} -gt 0 ]; then
			scan_analog_modules
		fi
		echo "-------------"
		echo "[ i] creating \"${ZAPTELCONF}\" and \"${ZAPATACONF}\"..."
		create_config_files
		echo "[OK] done. now run \"${THISPATH} start\" to activate your new config."
		;;
	*)
		echo "usage: ${THISPATH} start|stop|restart|scan|deepscan|config|help"
		;;
esac
