#!/bin/sh
# Bring this machine up to date: the operating system and the phone system,
# both through the package manager, both from the repositories the first
# boot wrote down. Nothing is fetched by hand and nothing is trusted that
# the package manager would not trust: the Alpine repository is signed with
# the key the package installed into /etc/apk/keys, the Debian one with the
# key in /usr/share/keyrings.
set -eu

if [ "$(id -u)" != 0 ]; then
	echo "run this as root" >&2
	exit 1
fi

before=$(nuxpbx version 2>/dev/null || echo "?")

# Which Asterisk is installed, asked the way this machine's package manager
# answers. Empty where nothing can say, and the restart below reads that as
# "cannot tell" and goes ahead: the old behaviour, which is the safe one.
#
# Without the -v. `apk info -v asterisk` never prints a version at all: -v is
# apk's global verbose flag, and `apk info` with no field flag answers with
# the description, the URL and the rounded installed size, so verbose only
# takes the version off the prefix. What it compared was therefore three
# constants and a megabyte rounded to the nearest whole one, and whether the
# restart fired came down to whether that rounding happened to move. Upgraded
# in place from Alpine 3.22 to edge, Asterisk 20.11.1-r6 becoming 22.10.1-r0,
# the three lines come back identical: a whole major version landed on disk,
# the restart did not fire, the old process went on serving calls, and both
# `nuxpbx version` and apk reported the new release. Plain `apk info` prints
# `asterisk-20.11.1-r0 description:`, which carries it.
engine_version() {
	if command -v apk >/dev/null 2>&1; then
		apk info asterisk 2>/dev/null | head -1 || true
	elif command -v dpkg-query >/dev/null 2>&1; then
		dpkg-query -W -f='${Version}' asterisk 2>/dev/null || true
	fi
}
engine_before=$(engine_version)

if command -v apk >/dev/null 2>&1; then
	apk update -q
	apk upgrade -q
	rc-service nuxpbx restart >/dev/null
	# And Asterisk, where the upgrade replaced it on disk. Alpine's asterisk
	# package carries a .pre-install and a .pre-upgrade and nothing that runs
	# afterwards, so apk lands the new binary and leaves the old process
	# serving calls; Debian's postinst restarts the service itself, which is
	# why the branch below says nothing about it. Without this an Alpine box
	# runs the version it was installed with until somebody reboots it, and
	# `nuxpbx version` reports the new one all the while.
	#
	# Only where it replaced it. Restarting the engine ends every call that
	# is up, and most releases here are of nuxpbx alone: done every time, an
	# ordinary nightly update cut the phones on Alpine and left them alone on
	# Debian, which is the asymmetry this was written to take out.
	if [ -z "$engine_before" ] || [ "$engine_before" != "$(engine_version)" ]; then
		rc-service asterisk restart >/dev/null 2>&1 \
			|| echo "the old Asterisk is still running: restart it by hand to see why it refused" >&2
	fi
elif command -v apt-get >/dev/null 2>&1; then
	apt-get update -q
	# dist-upgrade, not upgrade. `upgrade` holds back any package whose new
	# version needs a package that is not installed yet, and nuxpbx has taken
	# on nftables, fail2ban, python3-systemd and cron since the first release:
	# on those upgrades `upgrade` left the old binary in place, changed
	# nothing, and this script then said the machine was already the newest.
	# Nothing new is fetched that the package manager would not trust either
	# way; what changes is that a new dependency may be installed.
	#
	# And the conffile policy, which is not a preference here. eleven of the
	# files nuxpbx-render writes are dpkg conffiles of asterisk-config, the
	# package asterisk depends on at an exact version: extensions.conf,
	# pjsip.conf, sorcery.conf, extconfig.conf, res_odbc.conf, manager.conf,
	# voicemail.conf, features.conf, logger.conf, rtp.conf, and the
	# modules.conf nuxpbx-realtime-on edits. Every one of them differs from
	# the packaged version on every machine here, so the first upstream
	# Asterisk release that changes any of them makes dpkg ask. Asked with no
	# terminal, dpkg fails with "end of file on stdin at conffile prompt",
	# apt exits 100, set -e ends this script before the restart below, and
	# asterisk-config is left half configured so every later apt call refuses
	# until somebody runs dpkg --configure -a. Answered by hand, Y on
	# extensions.conf installs Asterisk's sample dial plan while asterisk's
	# own postinst restarts the engine onto it, and the machine stops being a
	# telephone. Ours is the copy that must survive: whatever these files
	# hold, nuxpbx wrote it and can write it again.
	DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y -q \
		-o Dpkg::Options::=--force-confold \
		-o Dpkg::Options::=--force-confdef
	systemctl restart nuxpbx
else
	echo "neither apk nor apt: fetch the release yourself" >&2
	exit 1
fi

after=$(nuxpbx version 2>/dev/null || echo "?")
# Said where the engine was actually replaced, which is where both branches
# restart it: apk above, and Debian in asterisk's own postinst, which has
# always done it and said nothing. A bare "done" then reads as an update that
# cost nobody anything, and the calls that were up are gone.
if [ -z "$engine_before" ] || [ "$engine_before" != "$(engine_version)" ]; then
	echo "the phone engine was replaced and restarted, so calls that were up are gone."
fi
if [ "$before" = "$after" ]; then
	echo "done. nuxpbx $after was already the newest."
else
	echo "done. nuxpbx $before is now $after."
fi
