#!/bin/sh
#
# $OpenIMAPD$
#
# Copyright (c) 2026 David Williams <dhw@openimapd.dev>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# imapd-teardown, completely remove an installed imapd, to test
# repeated from-scratch installs.
#
# Usage:
#   doas ./imapd-teardown [-y] [-M] [-c credentials-dir] [-f config-file]
#       [-s spool-root] [-T tls-cert] [-K tls-key]
#
#   -y  skip the general confirmation prompt (still stops to ask
#       separately if -M is also given)
#   -M  also remove the mail spool
#
set -e

BINDIR=/usr/local/sbin
MAN5DIR=/usr/local/man/man5
MAN8DIR=/usr/local/man/man8
EXAMPLEDIR=/usr/local/share/examples/imapd
RELINKDIR=/usr/share/relink/usr/local/sbin/imapd
RELINKLOG=/tmp/imapd-relink.log

CRED_DIR=/etc/imapd
CONF_FILE=/etc/imapd.conf
SPOOL_ROOT=/var/mail/imapd
TLS_CERT=/etc/ssl/imapd.crt
TLS_KEY=/etc/ssl/private/imapd.key

ASSUME_YES=0
WIPE_MAIL=0

usage() {
	echo "usage: ${0##*/} [-y] [-M] [-c credentials-dir] [-f config-file]" 1>&2
	echo "           [-s spool-root] [-T tls-cert] [-K tls-key]" 1>&2
	exit 1
}

while getopts "c:f:s:T:K:yM" opt; do
	case "$opt" in
	c)	CRED_DIR=$OPTARG ;;
	f)	CONF_FILE=$OPTARG ;;
	s)	SPOOL_ROOT=$OPTARG ;;
	T)	TLS_CERT=$OPTARG ;;
	K)	TLS_KEY=$OPTARG ;;
	y)	ASSUME_YES=1 ;;
	M)	WIPE_MAIL=1 ;;
	*)	usage ;;
	esac
done
shift $((OPTIND - 1))
[ $# -eq 0 ] || usage

if [ "$(id -u)" -ne 0 ]; then
	echo "${0##*/}: must be run as root" 1>&2
	exit 1
fi

FOUND_ANY=0
DRYRUN=1

# $1 = human label, $2 = path, $3 = "f" (plain rm -f) or "r" (rm -rf)
do_rm() {
	_label=$1
	_path=$2
	_mode=$3
	if [ -e "$_path" ] || [ -L "$_path" ]; then
		FOUND_ANY=1
		if [ "$DRYRUN" -eq 1 ]; then
			echo "  $_path  ($_label)"
		else
			case "$_mode" in
			r)	rm -rf "$_path" ;;
			*)	rm -f "$_path" ;;
			esac
			echo "${0##*/}: removed $_path" 1>&2
		fi
	fi
}

# $1 = human label, $2 = account name
do_userdel() {
	_label=$1
	_acct=$2
	if id "$_acct" >/dev/null 2>&1; then
		FOUND_ANY=1
		if [ "$DRYRUN" -eq 1 ]; then
			echo "  system account $_acct  ($_label)"
		else
			userdel "$_acct" 2>/dev/null || true
			# useradd(8) makes a same-named group by default and
			# userdel(8) leaves a primary group behind.
			groupdel "$_acct" 2>/dev/null || true
			echo "${0##*/}: removed account $_acct (and its group, if any)" 1>&2
		fi
	fi
}

list_targets() {
	do_rm "installed daemon binary" "$BINDIR/imapd" f
	do_rm "installed imapduser tool" "$BINDIR/imapduser" f
	do_rm "imapd.8 man page" "$MAN8DIR/imapd.8" f
	do_rm "imapd.conf.5 man page" "$MAN5DIR/imapd.conf.5" f
	do_rm "imapduser.8 man page" "$MAN8DIR/imapduser.8" f
	do_rm "installed sample config directory" "$EXAMPLEDIR" r
	do_rm "rc.d script" "/etc/rc.d/imapd" f
	do_rm "boot-time relink artifact directory" "$RELINKDIR" r
	do_rm "relink boot log" "$RELINKLOG" f
	do_rm "config file" "$CONF_FILE" f
	do_rm "credentials directory" "$CRED_DIR" r
	do_rm "TLS certificate" "$TLS_CERT" f
	do_rm "TLS private key" "$TLS_KEY" f
	do_userdel "auth's privilege-drop account" "_imapauth"
	do_userdel "listener's privilege-drop account" "_imapd"
	do_userdel "keymgr's privilege-drop account" "_imapkey"
	if [ "$WIPE_MAIL" -eq 1 ]; then
		do_rm "mail spool -- REAL MAIL DATA" "$SPOOL_ROOT" r
	fi
}

echo "${0##*/}: the following would be removed:" 1>&2
list_targets

if [ "$FOUND_ANY" -eq 0 ]; then
	echo "${0##*/}: nothing found -- already torn down" 1>&2
	exit 0
fi

if [ "$ASSUME_YES" -ne 1 ]; then
	printf "%s: proceed? [y/N] " "${0##*/}" 1>&2
	read -r ANSWER
	case "$ANSWER" in
	[Yy]|[Yy][Ee][Ss])	;;
	*)	echo "${0##*/}: aborted, nothing removed" 1>&2; exit 1 ;;
	esac
fi

if [ "$WIPE_MAIL" -eq 1 ]; then
	echo "" 1>&2
	echo "${0##*/}: -M was given -- this will also permanently delete" \
	    "$SPOOL_ROOT and every mailbox in it. This cannot be undone." 1>&2
	printf "Type the spool path (%s) to confirm, or anything else to skip it: " \
	    "$SPOOL_ROOT" 1>&2
	read -r CONFIRM_SPOOL
	if [ "$CONFIRM_SPOOL" != "$SPOOL_ROOT" ]; then
		echo "${0##*/}: spool path not confirmed -- leaving $SPOOL_ROOT alone" 1>&2
		WIPE_MAIL=0
	fi
fi

# Stop and disable the service before touching any of its files.
# rcctl disable's own documented behavior (man.openbsd.org/rcctl.8) is
# what actually reverses "rcctl enable imapd": it strips the
# pkg_scripts entry and any rcctl-set variables from rc.conf.local,
# rather than this script trying to hand-edit that file itself.
rcctl stop imapd >/dev/null 2>&1 || true
rcctl disable imapd >/dev/null 2>&1 || true

DRYRUN=0
list_targets

echo "${0##*/}: done" 1>&2
