#!/sbin/openrc-run
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

extra_started_commands="forcestop reload"

depend() {
	need net
	use nscd dns dahdi mysql postgresql slapd capi
}

is_running() {
	[ -r "${ast_rundir}/asterisk.pid" ] || return 1
	PID="$(cat "${ast_rundir}/asterisk.pid")"
	[ -d "/proc/${PID}" ] || return 1
	EXE="$(readlink -f /proc/${PID}/exe)"
	EXE="${EXE% (deleted)}" # in case asterisk got upgraded and we're still looking at an old one.
	[ "${EXE}" = /usr/sbin/asterisk ] || return 1 # pid got re-used for another process.

	# PID reported in pidfile is active, and is still an asterisk instance.
	return 0
}

# Sets up a few variables for us for use
# ast_instancename: eg, asterisk when RC_SVCNAME=asterisk, or asterisk(foo) when asterisk.foo.
# ast_rundir: directory to be used as run folder (pid and ctl files).
setup_svc_variables()
{
	local t

	ast_instancename=asterisk
	ast_rundir=/run/${RC_SVCNAME}
	ast_logdir=/var/log/${RC_SVCNAME}
	ast_confdir=/etc/${RC_SVCNAME}
	ast_cachedir=/var/cache/asterisk
	ast_stop_timeout=120
	ast_stop_method="gracefully"

	if [ "${RC_SVCNAME}" != "asterisk" ]; then
		t="${RC_SVCNAME#asterisk.}"
		if [ "${RC_SVCNAME}" = "${t}" ]; then
			eerror "Invalid SVCNAME of ${RC_SVCNAME}, must be of the format asterisk.name."
			return 1
		fi
		ast_instancename="${ast_instancename}(${t})"
	fi

	[ -n "${ASTERISK_RUNDIR}" ] && ast_rundir="${ASTERISK_RUNDIR}"
	[ -n "${ASTERISK_LOGDIR}" ] && ast_logdir="${ASTERISK_LOGDIR}"
	[ -n "${ASTERISK_CONFDIR}" ] && ast_confdir="${ASTERISK_CONFDIR}"
	[ -n "${ASTERISK_CACHEDIR}" ] && ast_confdir="${ASTERISK_CACHEDIR}"
	[ -n "${ASTERISK_STOP_TIMEOUT}" ] && ast_stop_timeout="${ASTERISK_STOP_TIMEOUT}"
	case "${ASTERISK_STOP_METHOD}" in
		gracefully|when\ convenient|now)
			ast_stop_method="${ASTERISK_STOP_METHOD}"
		;;
	esac
	ast_group=
	if [ -n "${ASTERISK_USER}" ]; then
		ast_user="${ASTERISK_USER%%:*}"
		if [ "${ast_user}" != "${ASTERISK_USER}" ]; then
			ast_group="${ASTERISK_USER#*:}"
			ast_group="${ast_group%%:*}"
		fi
	fi

	[ -z "${ast_user}" ] && ast_user=asterisk

	ast_pgroup="$(getent group $(getent passwd "${ast_user}" | awk -F: '{ print $4 }') | sed -re 's/:.*//')"

	return 0
}

start() {
	local OPTS PID
	local tmp x

	local OPTS ARGS WRAPPER_OPTS

	setup_svc_variables || return $?

	ebegin "Starting ${ast_instancename} PBX"

	eindent

	# filter (redundant) arguments
	OPTS="$(echo "${ASTERISK_OPTS}" | sed -re "s:-[cfF]::g")"

	# default options
	OPTS="${OPTS}${OPTS:+ }-C ${ast_confdir}/asterisk.conf -f"  # don't fork / detach breaks wrapper script...

	WRAPPER_OPTS="--syslog"
	if [ "${RC_SVCNAME}" != "asterisk" ]; then
		WRAPPER_OPTS="${WRAPPER_OPTS} --instance ${RC_SVCNAME#asterisk.}"
	fi
	WRAPPER_OPTS="${WRAPPER_OPTS} --rundir ${ast_rundir}"
	
	# ensure that ASTERISK_RESTART_DELAY is integer.
	ASTERISK_RESTART_DELAY="$(echo "${ASTERISK_RESTART_DELAY}" | sed -re 's/^([0-9]*).*/\1/')"
	[ -z "${ASTERISK_RESTART_DELAY}" ] && ASTERISK_RESTART_DELAY=5
	WRAPPER_OPTS="${WRAPPER_OPTS} --restartdelay ${ASTERISK_RESTART_DELAY}"

	if [ -n "${ASTERISK_CORE_SIZE}" ] &&
	   [ "${ASTERISK_CORE_SIZE}" != "0" ]; then
		WRAPPER_OPTS="${WRAPPER_OPTS} --dumpcore ${ASTERISK_CORE_SIZE}"	
		OPTS="${OPTS} -g"

		if [ -n "${ASTERISK_CORE_DIR}" ] && \
		   [ ! -d "${ASTERISK_CORE_DIR}" ]
		then
			checkpath -d -m 0755 -o ${ast_user}:${ast_group} "${ASTERISK_CORE_DIR}"
		fi
		ASTERISK_CORE_DIR="${ASTERISK_CORE_DIR:-/tmp}"

		cd "${ASTERISK_CORE_DIR}"
		einfo "Core dump size            : ${ASTERISK_CORE_SIZE}"
		einfo "Core dump location        : ${ASTERISK_CORE_DIR}"

		if [ -n "${ASTERISK_CORE_COMPRESS}" ]; then
			einfo "Core compression tool     : ${ASTERISK_CORE_COMPRESS}"
			WRAPPER_OPTS="${WRAPPER_OPTS} --corecompress ${ASTERISK_CORE_COMPRESS}"
		fi

		if yesno "${ASTERISK_CORE_USEHOSTNAME}"; then
			WRAPPER_OPTS="${WRAPPER_OPTS} --corerename core-%H-%D-%T"
		else
			WRAPPER_OPTS="${WRAPPER_OPTS} --corerename core-%D-%T"
		fi
	else
		cd /
	fi

	if [ -n "${ASTERISK_MAX_FD}" ]; then
		WRAPPER_OPTS="${WRAPPER_OPTS} --maxfd ${ASTERISK_MAX_FD}"
		einfo "Max open filedescriptors  : ${ASTERISK_MAX_FD}"
	fi

	if [ -n "${ASTERISK_NICE}" ]; then
		if [ ${ASTERISK_NICE} -ge -20 ] && \
		   [ ${ASTERISK_NICE} -le  19 ]; then
			einfo "Nice level                : ${ASTERISK_NICE}"
			WRAPPER_OPTS="${WRAPPER_OPTS} --nicelevel ${ASTERISK_NICE}"
		else
			eerror "Nice value must be between -20 and 19"
			return 1
		fi
	fi

	if [ -n "${ASTERISK_NOTIFY_EMAIL}" ]; then
		if [ -x /usr/sbin/sendmail ]; then
			einfo "Email notifications go to : ${ASTERISK_NOTIFY_EMAIL}"
			WRAPPER_OPTS="${WRAPPER_OPTS} --crashemail ${ASTERISK_NOTIFY_EMAIL}"
		else
			ewarn "Notifications disabled, /usr/sbin/sendmail doesn't exist or is not executable!"
		fi
	fi

	if [ -n "${ASTERISK_TTY}" ]; then
		for x in "${ASTERISK_TTY}" \
			 "/dev/tty${ASTERISK_TTY}" \
			 "/dev/vc/${ASTERISK_TTY}"
		do
			if [ -c "${x}" ]; then
				TTY="${x}"
			fi
		done
		if [ -n "${TTY}" ]; then
			einfo "Messages are sent to      : ${TTY}"
			WRAPPER_OPTS="${WRAPPER_OPTS} --tty ${TTY}"
		else
			ewarn "ASTERISK_TTY=${TTY} ignored, not valid."
		fi
	fi

	if yesno "${ASTERISK_CONSOLE}" && [ -n "${TTY}" ]; then
		einfo "Starting Asterisk console : Yes"
		OPTS="${OPTS} -c"
	fi

	if ! getent passwd "${ast_user}" >/dev/null 2>&1; then
		eerror "Requested to run asterisk as ${ast_user}, which doesn't exist."
		return 1
	fi
	OPTS="${OPTS} -U ${ast_user}"

	if [ -n "${ast_group}" ] && ! getent group "${ast_group}" >/dev/null 2>&1; then
		eerror "Requested to run ${ast_instancename} with group ${ast_group}, which doesn't exist."
		return 1
	fi
	[ -n "${ast_group}" ] && OPTS="${OPTS} -G ${ast_group}"

	if [ "${ast_user}" = root ]; then
		ewarn "Starting asterisk as root is not recommended (SERIOUS SECURITY CONSIDERATIONS)."
	elif [ "${ast_group}" = root ]; then
		ewarn "Starting asterisk with group root is not recommended (SERIOUS SECURITY CONSIDERATIONS)."
	fi

	checkpath -d -m 0755 -o "${ast_user}:${ast_group}" "${ast_logdir}" "${ast_rundir}"
	checkpath -d -m 0750 -o "${ast_user}:${ast_group}" "${ast_cachedir}"

	einfo "Starting asterisk as      : ${ast_user}:${ast_group:-${ast_pgroup} (+supplementaries)}"
	einfo "Wrapper options           : ${WRAPPER_OPTS}"
	einfo "Asterisk options          : ${OPTS}"

	/usr/sbin/asterisk_wrapper ${WRAPPER_OPTS} -- ${OPTS} &
	result=$?

	if [ $result -eq 0 ]; then
		# 2 seconds should be enough for asterisk to start
		sleep 2
		is_running
		result=$?

		[ $result -eq 0 ] || wrapperstop
	fi

	eoutdent
	eend $result

	if [ $result -eq 0 ] && yesno "${ASTERISK_WAITBOOTED}"; then
		if [ ! -r "${ast_rundir}/asterisk.ctl" ]; then
			# asterisk can crash during startup ...
			ebegin "Waiting for ctl file to appear"
			while is_running && [ ! -r "${ast_rundir}/asterisk.ctl" ]; do
				sleep 1
			done
			is_running
			result=$?
			eend $result
		fi
		if [ $result -eq 0 ]; then
			ebegin "Waiting for ${ast_instancename} to fully boot"
			/usr/sbin/asterisk -C "${ast_confdir}/asterisk.conf" -r -x "core waitfullybooted" >/dev/null 2>&1
			eend $?
		fi
	fi

	return $result
}

wrapperstop() {
	# Older path.
	if [ -r "${ast_rundir}/wrapper_loop.running" ]; then
		ebegin "Signalling ${ast_instancename} wrapper script to terminate"
		rm "${ast_rundir}/wrapper_loop.running"
		eend $?
	fi

	if [ -r "${ast_rundir}/asterisk_wrapper.pid" ]; then
		ebegin "Signalling ${ast_instancename} wrapper script to terminate"
		rm "${ast_rundir}/asterisk_wrapper.pid"
		eend $?
	fi

	return 0
}

forcestop() {
	setup_svc_variables || return $?

	# Just to be sure - when we want to forcestop we should make it all tear down.
	wrapperstop

	ebegin "Stopping ${ast_instancename} PBX"
	start-stop-daemon --stop --pidfile /run/asterisk/asterisk.pid
	eend $?
}

stop() {
	setup_svc_variables || return $?

	wrapperstop

	if ! is_running; then
		eerror "${ast_instancename} is not running!"
		return 0
	fi

	ebegin "Stopping ${ast_instancename} PBX ${ast_stop_method}"
	/usr/sbin/asterisk -C "${ast_confdir}/asterisk.conf" -r -x "core stop ${ast_stop_method}" >/dev/null 2>&1
	# Now we have to wait until asterisk has _really_ stopped.
	sleep 1
	if is_running; then
		einfon "Waiting for ${ast_instancename} to shutdown ."
		local cnt=0
		while is_running; do
			cnt="$(expr $cnt + 2)"
			if [ ${ast_stop_timeout} -gt 0 -a $cnt -gt ${ast_stop_timeout} ] ; then
				echo
				eend 1 "Failed waiting for ${ast_instancename} to stop."
				return 1
			fi
			sleep 2
			printf "."
		done
		echo
	fi
	eend 0
}

reload() {
	setup_svc_variables || return $?

	if is_running; then
		ebegin "Requesting ${ast_instancename} to reload configuration"
		/usr/sbin/asterisk -C "${ast_confdir}/asterisk.conf" -r -x "module reload" >/dev/null 2>&1
		eend $?
	else
		eerror "${ast_instancename} is not running!"
	fi
}