#!/bin/sh

# Author: Michael Geddes  <michael at frog dot wheelycreek dot net>
# Copyright 2008 Michael Geddes
# Licensed under GPL
Version=0.8


# Todo
#   Calling of Macros in dialplan
#   Create a Menu
#   Incoming Zones

debuglevel=0

. /etc/functions.sh

asteriskuci_gen="; Generated by Openwrt AstriskUCI script version ${Version}$N"

# Utils

logerror() {
	echo "Error: $1"
}

logdebug() {
	if [ $(expr $1 "<=" ${debuglevel-0}) == 1 ] ; then
		echo "Log: $2"
	fi
}

is_in_list(){
	val=$1
	shift
	for i in $* ; do
		[ $i == $val ] && return 0
	done
	return 1
}

split_append() { # {list} {prefix} {item} {func call}
	local lhs="$2"
	local rhs="$3"
	
	while [ ! -z "$rhs" ] ; do
		cur=${rhs%%,*}
		nvar=${rhs#*,}
		[ -z "$5" ] || eval "$5 ${cur}"
		append $1 "${lhs}${cur}" "$4"
		[ "$nvar" == "$rhs" ] && break
		rhs=${nvar}
	done
}

get_checksum() {
	if [ -r "$2" ] ; then
		local sum=`md5sum $2 | cut  -d " " -f 1`
		eval "$1=\"$sum\""
	else
		eval "$1=NONE"
	fi
	#eval "logdebug 1 \"Checksum $2 : \${$1}\""
}

check_checksum() {
	if [ -r "$2" ] ; then
		local sum=`md5sum $2 | cut  -d " " -f 1`
	else
		eval sum=NONE
	fi
	#logdebug 1 "Compare $1 checksum $2 with new checksum $sum "
	[ "$sum" == "$1" ]
	return $?
}

# Add config module to initialise list
ast_add_conf() append asterisk_conf_list $1 " "
# Add module to initialise list
ast_add_module() {
	append asterisk_module_list $1 " "
	eval "createdialplan_$1() return 0"
}
# Add to 'reload' list.
ast_add_reload() append asterisk_load_list $1 " "

# Enable a top-level type
ast_enable_type() eval "enabled_section_${1}=1"

# Is a top-level type enabled?
ast_type_enabled() {
	eval "local res=\${enabled_section_${1}}"
	if [ "$res" != 1 ] ; then
		return 1 #Fail
	fi
	return 0
}

# For use in sections - make sure that the last section is processed
check_add() {
	logdebug 1 "Check add $1"
	if [ ! -z "${last_added_checked}" ] ; then
		logdebug 1 "Eval check-add ${last_added_checked}"
		eval "check_add_${last_added_checked}"
	fi
	last_added_checked=$1
}

# Process the section yet to be checked.
check_all_added() check_add ""

# Create static links for stuff we dont want to configure yet.
create_staticlinks() {
	logdebug 1 "Link in a few mostly static configurations"
	linkconfigs="codecs.conf say.conf sip_notify.conf udptl.conf logger.conf"
	module_enabled res_indications && append linkconfigs indications.conf " "
	for i in ${linkconfigs} ; do
		[ -e $DEST_DIR/$i ] || ln -s $DEST/etc/asterisk/$i $DEST_DIR
	done

	logdebug 1 "Link in #include directories"
	for i in include inc libs lib library macro macros ; do
		if [ -e $DEST/etc/asterisk/$i -a  ! -d "$DEST_DIR/$i" -a ! -e "$DEST_DIR/$i" ] ; then
			ln -s $DEST/etc/asterisk/$i $DEST_DIR
		fi
	done
}

# default reboot
reboot_hardware() {}


# Top level handler
setup_asterisk() {
	DEST=${1%/}
	DEST_DIR=/tmp/asterisk

	testing_mode=0
	if [ "$2" == "testonly" ] ; then
		testing_mode=1
	elif [ "$2" == "test" ] ; then
		DEST_DIR=/tmp/asterisk.tmp
		echo Using Test dir: $DEST_DIR
		testing_mode=2
	fi

	[ -z "$3" ] || debuglevel=$3

	logdebug 1 "Loading Asterisk Config"
	. ${UCILIB}/asteriskconf
	logdebug 2 "Loading Module Config"
	. ${UCILIB}/moduleconf
	logdebug 2 "Loading Dialplan Config"
	. ${UCILIB}/dialplanconf

	for f in ${DEST}/etc/asterisk/conf.d/* ; do
		logdebug 1 "Loading Module $f"
		[ -f $f ] && . $f
	done

	include /lib/network
	scan_interfaces

	init_asteriskconf
	init_moduleconf
	init_dialplanconf

	for i in  ${asterisk_module_list} ; do
		logdebug 1 "Init $i module"
		eval "init_${i}"
	done

	for i in ${asterisk_conf_list} ; do
		logdebug 1 "Init $i config"
		eval "init_${i}conf"
	done
 
	config_cb() {
		cur_section=$1/$2
		logdebug 2 "Load $1/$2"
		eval "local val=\"\${dups_$2}\""
		if [ "${val}" == "" ] ; then
			eval "dups_$2=1"
		else
			logerror "Duplicate Section Name: $2  (type $1)"
		fi

		if ast_type_enabled $1 ; then
			eval "handle_$1 \$2"
		elif [ ! -z "$1" ] ; then

		 	logerror "Unknown section: $1/$2"
			option_cb() {
				logerror "Invalid option '$1' for invalid section"
			}
		fi
	}
	config_load asterisk
	check_all_added

	if [ "$testing_mode" != "1" ] ; then
		mkdir -p ${DEST_DIR}

		create_asteriskconf
		for i in ${asterisk_conf_list} ; do
			logdebug 1 "Create $i config"
			eval "create_${i}conf"
		done

		for i in ${asterisk_module_list} ; do
			logdebug 1 "Create Dialplan for module $i"
			eval "createdialplan_${i}"
		done
		create_dialplanconf
		create_moduleconf

		# Link in a few mostly static configurations
		create_staticlinks
	fi
	[ "$testing_mode" == "2" ] && reload_check_asterisk
	return 0
}

astcmd() {
	ASTCMD="${DEST%/}/usr/sbin/asterisk -C /tmp/asterisk/asterisk.conf "
	logdebug 1 "Command: $1"
	if [ -z "${2-}" ] ; then
		${ASTCMD} -r -x "$1" 2>&- 1>&-
	else
		eval "$2=`${ASTCMD} -r -x \"$1\"`"
	fi
	return $?
}

# waitfor() {
# 	while [ -d /proc/$1 ] ; do
# 		sleep 1
# 	done
# }

restart_gracefully() {
	stop_uci_asterisk "$DEST"
	startup_asterisk "$DEST"
	#ret=0
	#echo "Check for pid"
	#if [ -r /var/run/asterisk.ctl ] ; then
	#	astcmd "stop gracefully"
	#	local ret=$?
	#	[ ${ret} = 0 ] || return $ret
	#	waitfor `cat /var/run/asterisk.pid`
	#fi
	#startup_asterisk ${DEST}
	return 0
}
astcmds() {
	while [ ! -z "$1" ] ; do
		astcmd "$1"
		shift
	done
}

reload_check_asterisk() {
	logdebug 1 "Check Reloading"
	local reboot=0
	if [ "${ast_restart-}" == 1 ] ; then
		logdebug 1 "Restarting Gracefully"
		reboot=0
	else
		for i in ${asterisk_load_list} ; do
			logdebug 1 "Checking ${i} reload"
			eval "local doload=\${ast_${i}_restart}"
			case $doload in
				1) logdebug 1 "Reloading ${i}" ;;
				2) logdebug 1 "Unloading ${i}" ;;
			esac
		done
	fi
	[ ${reboot} = 1 ] && logdebug 1 "reboot hardware"
}

reload_asterisk() {
	logdebug 1 "Reloading"
	local reboot=0
	if [ "${ast_restart-}" == 1 ] ; then
		logdebug 2 "Restarting Gracefully"
		restart_gracefully
		reboot=0
	else
		for i in ${asterisk_load_list} ; do
			logdebug 3 "Checking ${i} reload"
			eval "local doload=\${ast_${i}_restart}"
			case $doload in
				1) logdebug 1 "Reloading ${i}"
				eval "reload_${i}" || reboot=1 ;;
				2) logdebug 1 "Unloading ${i}"
				eval "unload_${i}" || reboot=1 ;;
			esac
		done
	fi

	if [ ${reboot} = 1 ] ; then
		( sleep 5; reboot_hardware ) &
	fi
}

startup_asterisk() {
	DEST="${1%/}"
	DEFAULT=$DEST/etc/default/asterisk
	[ -f $DEFAULT ] && . $DEFAULT
	[ -d /var/run ] || mkdir -p /var/run
	[ -d ${asterisk_logdir} ] || mkdir -p ${asterisk_logdir}
	[ -d ${asterisk_spooldir} ] || mkdir -p ${asterisk_spooldir}
	[ -d /var/spool/asterisk ] || mkdir -p /var/spool/asterisk
	[ -h $DEST/usr/lib/asterisk/astdb ] || ln -sf /var/spool/asterisk/astdb $DEST/usr/lib/asterisk/astdb
	[ -e /dev/zappseudo ] && [ ! -d /dev/zap -o ! -e /dev/zap/pseudo ] && mkdir -p /dev/zap && ln -s /dev/zappseudo /dev/zap/pseudo

	$DEST/usr/sbin/asterisk -C /tmp/asterisk/asterisk.conf $UCIOPTIONS -f 2>&1 > ${asterisk_logdir}/asterisk_proc &
	# Wait a bit then reboot the hardware
	( sleep 5; reboot_hardware ) &
}

# Init.d start() handler
start_uci_asterisk() {
	DEST="${1%/}"

	if setup_asterisk $DEST ; then
		startup_asterisk "$DEST"
	fi
}

restart_uci_asterisk() {
	DEST="${1%/}"
	if setup_asterisk $DEST ; then
		echo "Trying to Restart gracefully"
		if [ -r /var/run/asterisk.ctl ] ; then
#			if astcmd "restart gracefully" ; then
			echo "Sending restart"
			if restart_gracefully  ; then
				echo "Restarting gracefully"
				return 0
			fi
		fi
		stop_uci_asterisk "$DEST"
		startup_asterisk "$DEST"
	else
		stop_uci_asterisk $1
		echo "Setup Failed"
		return 1
	fi
}

# init.d stop() handler
stop_uci_asterisk() {
	DEST=${1%/}
	if [ -r /var/run/asterisk.ctl ] ; then
		astcmd "stop now"
		sleep 1
	fi
	[ -f /var/run/asterisk.pid ] && kill $(cat /var/run/asterisk.pid) >/dev/null 2>&1
}

reload_uci_asterisk() {
	DEST=${1%/}
	DEFAULT=$DEST/etc/default/asterisk

	if [ -r /var/run/asterisk.ctl ] ; then

		[ -e /dev/zappseudo ] && [ ! -d /dev/zap -o ! -e /dev/zap/pseudo ] && mkdir -p /dev/zap && ln -s /dev/zappseudo /dev/zap/pseudo
		if setup_asterisk "$DEST" ; then
			# Selective reload modules.
			reload_asterisk
		fi
	else
		start_uci_asterisk "$1"
	fi
}

# vim: ts=2 sw=2 noet foldmethod=indent
