#!/bin/bash
# This script is written by Martynas Bendorius and DirectAdmin
# It is used to move domain from one user to another
# Official DirectAdmin webpage: http://www.directadmin.com
# Usage:
# ./move_domain.sh <domain> <olduser> <newuser>

if [ "$(id -u)" != 0 ]; then
	echo "You require Root Access to run this script."
	exit 0
fi

if [ $# != 3 ]; then
	echo "Move Domain between users script"
	echo ""
	echo "Usage:"
	echo "$0 <domain> <olduser> <newuser>"
	echo "you gave #$#: $0 $1 $2 $3"
	exit 0
fi

DOMAIN=$1
OLD_USER=$2
NEW_USER=$3

OLD_HOME=$(getent passwd "${OLD_USER}" | cut -d: -f6)
NEW_HOME=$(getent passwd "${NEW_USER}" | cut -d: -f6)

OLD_MAIL_HOME="${OLD_HOME}"
NEW_MAIL_HOME="${NEW_HOME}"
MAIL_PARTITION=$(da config-get mail_partition)
if [ -n "${MAIL_PARTITION}" ]; then
	OLD_MAIL_HOME="${MAIL_PARTITION}/${OLD_USER}"
	NEW_MAIL_HOME="${MAIL_PARTITION}/${NEW_USER}"
fi

APACHE_PUBLIC_HTML=$(da config-get apache_public_html)

urldecode() {
	local string="${1}"
	local strlen=${#string}
	local decoded=""
	local pos c xx o

	for (( pos=0 ; pos<strlen ; pos++ )); do
		c=${string:$pos:1}
		case "$c" in
			%)
				xx=${string:$((pos+1)):2}
				if [ "${#xx}" -eq 2 ] && [ "${xx//[0-9a-fA-F]/}" = "" ]; then
					printf -v o "%b" "\x${xx}"
					pos=$((pos+2))
				else
					o=${c}
				fi
				;;
			+)
				o=" "
				;;
			*)
				o=${c}
				;;
		esac
		decoded+="${o}"
	done
	echo "${decoded}"
}

update_email_domain_dir() {
	VIRTUAL_DOMAIN="/etc/virtual/${DOMAIN}"
	if [ ! -e "${VIRTUAL_DOMAIN}" ] && [ -e "${VIRTUAL_DOMAIN}_off" ]; then
		VIRTUAL_DOMAIN="${VIRTUAL_DOMAIN}_off"
		echo "domain ${DOMAIN} is suspended using ${VIRTUAL_DOMAIN}"
	fi
	if [ ! -e "${VIRTUAL_DOMAIN}" ]; then
		echo "Cannot find ${VIRTUAL_DOMAIN}, aborting swap of ${VIRTUAL_DOMAIN}"
		return
	fi

	OLD_GID=$(id -g mail)
	OLD_UID=$(id -u "${OLD_USER}")
	NEW_GID=$(id -g mail)
	NEW_UID=$(id -u "${NEW_USER}")

	#First find the uid/gid swap them
	sed -i -e "s#:${OLD_UID}:${OLD_GID}::${OLD_MAIL_HOME}/#:${NEW_UID}:${NEW_GID}::${NEW_MAIL_HOME}/#" "${VIRTUAL_DOMAIN}/passwd"

	#Remove the old system mailbox from virtual passwd file - it belongs to system user and issue rewrite to push the new one
	sed -i -e "\#:${OLD_UID}:${OLD_GID}::${OLD_MAIL_HOME}:#d" "${VIRTUAL_DOMAIN}/passwd"
	da taskq --run "action=rewrite&value=email_passwd&user=${NEW_USER}"

	#/etc/virtual/domain.com/aliases
	sed -i -e "s/^${OLD_USER}:/${NEW_USER}:/" "${VIRTUAL_DOMAIN}/aliases"
	sed -i -e "s/\([ :,]\)${OLD_USER}\(,\|$\)/\1${NEW_USER}\2/g" "${VIRTUAL_DOMAIN}/aliases"
	# Update pipe aliases that contain paths
	sed -i -e "s#${OLD_HOME}/#${NEW_HOME}/#" "${VIRTUAL_DOMAIN}/aliases"

	sed -i -e "s#${OLD_MAIL_HOME}#${NEW_MAIL_HOME}#" "${VIRTUAL_DOMAIN}/filter"

	if [ -e "${VIRTUAL_DOMAIN}/usage.cache" ]; then
		sed -i -e "s/^${OLD_USER}:/${NEW_USER}:/" "${VIRTUAL_DOMAIN}/usage.cache"
	fi

	OLD_EMAIL="${OLD_USER}@${DOMAIN}"
	OLD_EMAIL_ESCAPED=$(sed 's/[.[\*^/&$]/\\&/g' <<< "${OLD_EMAIL}")
	NEW_EMAIL="${NEW_USER}@${DOMAIN}"

	if [ -e "${VIRTUAL_DOMAIN}/majordomo" ]; then
		sed -i -e "s/\(:\|\s\)${OLD_EMAIL_ESCAPED}$/\1${NEW_EMAIL}/" "${VIRTUAL_DOMAIN}/majordomo/list.aliases" 2> /dev/null
		sed -i -e "s/\(:\|\s\)${OLD_EMAIL_ESCAPED}$/\1${NEW_EMAIL}/" "${VIRTUAL_DOMAIN}/majordomo/lists/"* 2> /dev/null
	fi
}

update_email_settings() {
	echo "Updating email settings."

	#domainowners
	sed -i -e "s/^${DOMAIN//./\\.}:.*$/${DOMAIN}: ${NEW_USER}/" /etc/virtual/domainowners

	#snidomains
	if [ -s /etc/virtual/snidomains ]; then
		sed -i -e "s/:${OLD_USER}:${DOMAIN//./\\.}$/:${NEW_USER}:${DOMAIN}/" /etc/virtual/snidomains
	fi

	#repeat for domain pointers too.
	#at this stage, the domain.com.pointers file has already been moved.
	while IFS= read -r p; do
		sed -i -e "s/^${p//./\\.}:.*$/${p}: ${NEW_USER}/" /etc/virtual/domainowners
		# pointers may also have seprate cert files
		sed -i -e "s/:${OLD_USER}:${p//./\\.}$/:${NEW_USER}:${p}/" /etc/virtual/snidomains
	done < <(cut -d= -f1 "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.pointers")

	#/etc/virtual/domain.com
	update_email_domain_dir

	#/home/username/.spamassassin/user_spam/user@domain.com
	#if it doesnt exist, dont bother
	if [ -e "${OLD_HOME}/.spamassassin/user_spam" ]; then
		mkdir -p "${NEW_HOME}/.spamassassin/user_spam"
		mv "${OLD_HOME}/.spamassassin/user_spam/"*"@${DOMAIN}" "${NEW_HOME}/.spamassassin/user_spam/"
		chown -R "${NEW_USER}:mail" "${NEW_HOME}/.spamassassin/user_spam"
		chmod 771                   "${NEW_HOME}/.spamassassin/user_spam"
		chmod 660                   "${NEW_HOME}/.spamassassin/user_spam/"*
	fi

	#/home/username/imap/domain.com
	if [ -e "${OLD_MAIL_HOME}/imap/${DOMAIN}" ]; then
		if [ -e "${NEW_MAIL_HOME}/imap/${DOMAIN}" ]; then
			echo "'${NEW_MAIL_HOME}/imap/${DOMAIN}' already exists.. merging as best we can."
			mv -f "${OLD_MAIL_HOME}/imap/${DOMAIN}/"* "${NEW_MAIL_HOME}/imap/${DOMAIN}"
		else
			if [ ! -e "${NEW_MAIL_HOME}/imap" ]; then
				mkdir -p                 "${NEW_MAIL_HOME}/imap"
				chown "${NEW_USER}:mail" "${NEW_MAIL_HOME}/imap"
				chmod 770                "${NEW_MAIL_HOME}/imap"
			fi
			mv -f "${OLD_MAIL_HOME}/imap/${DOMAIN}" "${NEW_MAIL_HOME}/imap/${DOMAIN}"
		fi

		chown -R "${NEW_USER}:mail" "${NEW_MAIL_HOME}/imap/${DOMAIN}"
		chmod -R 770                "${NEW_MAIL_HOME}/imap/${DOMAIN}"
	fi

	#symlinks for domain pointers
	while IFS= read -r p; do
		rm -f "${OLD_MAIL_HOME}/imap/${p}"
		ln -s "${DOMAIN}"           "${NEW_MAIL_HOME}/imap/${p}"
		chown -h "${NEW_USER}:mail" "${NEW_MAIL_HOME}/imap/${p}"
	done < <(cut -d= -f1 "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.pointers")

	#/var/spool/virtual/domain.com (permissions only)
	if [ -e "/var/spool/virtual/${DOMAIN}" ]; then
		chown -R "${NEW_USER}:mail" "/var/spool/virtual/${DOMAIN}"
	fi

	#/etc/dovecot/conf/sni/domain.com.conf
	if [ -s "/etc/dovecot/conf/sni/${DOMAIN}.conf"  ]; then
		sed -i -e "s#/usr/local/directadmin/data/users/${OLD_USER}/#/usr/local/directadmin/data/users/${NEW_USER}/#g" "/etc/dovecot/conf/sni/${DOMAIN}.conf"
	fi

	#cert inclusions for pointers as well
	while IFS= read -r p; do
		if [ -s "/etc/dovecot/conf/sni/${p}.conf"  ]; then
			sed -i -e "s#/usr/local/directadmin/data/users/${OLD_USER}/#/usr/local/directadmin/data/users/${NEW_USER}/#g" "/etc/dovecot/conf/sni/${p}.conf"
		fi
	done < <(cut -d= -f1 "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.pointers")
}

update_ftp_settings() {
	echo "Updating ftp settings."

	#for the password files, we only change the user@domain.com accounts.
	#the system account isn't touched.
	OLD_GID=$(id -g "${OLD_USER}")
	OLD_UID=$(id -u "${OLD_USER}")
	NEW_GID=$(id -g "${NEW_USER}")
	NEW_UID=$(id -u "${NEW_USER}")

	#proftpd.passwd. First find the uid/gid and homedir matchup and swap them.
	sed -i -e "s#:${OLD_UID}:${OLD_GID}:\(domain\|user\|custom\):${OLD_HOME}/domains/${DOMAIN//./\\.}\(:\|/\)#:${NEW_UID}:${NEW_GID}:\1:${NEW_HOME}/domains/${DOMAIN}\2#" /etc/proftpd.passwd

	#take care of anonymous account in proftpd.passwd (no UID change)
	sed -i -e "s#:anonymous:${OLD_HOME}/domains/${DOMAIN//./\\.}/#:anonymous:${NEW_HOME}/domains/${DOMAIN}/#" /etc/proftpd.passwd
}

update_da_settings() {
	echo "Moving domain data to the ${NEW_USER} user."
	mv -f -T "${OLD_HOME}/domains/${DOMAIN}" "${NEW_HOME}/domains/${DOMAIN}"
	mv -f "/usr/local/directadmin/data/users/${OLD_USER}/domains/${DOMAIN}."* "/usr/local/directadmin/data/users/${NEW_USER}/domains/"
	echo "Setting ownership for ${DOMAIN} domain."
	chown -R "${NEW_USER}:${NEW_USER}" "${NEW_HOME}/domains/${DOMAIN}"

	if [ "$APACHE_PUBLIC_HTML" -eq 1 ]; then
		echo "apache_public_html=1 is set, updating public_html and private_html in ${NEW_HOME}/domains/${DOMAIN}"
		chmod 750    "${NEW_HOME}/domains/${DOMAIN}/public_html" "${NEW_HOME}/domains/${DOMAIN}/private_html"
		chgrp apache "${NEW_HOME}/domains/${DOMAIN}/public_html" "${NEW_HOME}/domains/${DOMAIN}/private_html"
	fi

	if [ -s "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.subdomains.docroot.override" ]; then
		while IFS= read -r line; do
			SUBDOMAIN=$(cut -f1 -d= <<< "${line}")
			DOCROOT=$(sed -n -e "s|^${SUBDOMAIN}.*[=&]public_html=\([^&]\+\).*$|\1|p" <<< "${line}")
			DOCROOT_DECODED=$(urldecode "${DOCROOT}")
			if [[ "${DOCROOT_DECODED}" = "/domains/${DOMAIN}/"* ]]; then
				#docroot is inside the already moved domain dir
				continue
			fi
			RELATIVE_MOVE_PATH="${DOCROOT_DECODED}"
			if [ "${DOCROOT_DECODED}" = "/domains/${SUBDOMAIN}.${DOMAIN}/public_html" ]; then
				RELATIVE_MOVE_PATH="/domains/${SUBDOMAIN}.${DOMAIN}"
			fi
			su -s /bin/sh -c "umask 066; mkdir -p '${NEW_HOME//\'/\'\"\'\"\'}${RELATIVE_MOVE_PATH//\'/\'\"\'\"\'}'" "${NEW_USER}"
			echo "Moving ${SUBDOMAIN}.${DOMAIN} custom docroot to the ${NEW_USER} user."
			mv -f -T "${OLD_HOME}${RELATIVE_MOVE_PATH}" "${NEW_HOME}${RELATIVE_MOVE_PATH}"
			echo "Setting ownership for the ${SUBDOMAIN}.${DOMAIN} subdomain."
			chown -R "${NEW_USER}:${NEW_USER}" "${NEW_HOME}${RELATIVE_MOVE_PATH}"

			if [ "$APACHE_PUBLIC_HTML" -eq 1 ]; then
				echo "apache_public_html=1 is set, updating ${NEW_HOME}${RELATIVE_MOVE_PATH} permissions"
				chmod 750    "${NEW_HOME}${RELATIVE_MOVE_PATH}"
				chgrp apache "${NEW_HOME}${RELATIVE_MOVE_PATH}"
			fi
		done < "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.subdomains.docroot.override"
	fi

	if [ -e "${NEW_HOME}/domains/${DOMAIN}/stats" ]; then
		echo "Setting stats directory ownership for ${DOMAIN} domain."
		chown -R root:root "${NEW_HOME}/domains/${DOMAIN}/stats"
	fi

	echo "Removing domain from ${OLD_USER} user."
	sed -i -e "\#^${DOMAIN//./\\.}\$#d" "/usr/local/directadmin/data/users/${OLD_USER}/domains.list"

	echo "Adding domain to ${NEW_USER} user."
	echo "${DOMAIN}" >> "/usr/local/directadmin/data/users/${NEW_USER}/domains.list"
	sed -i -e "s#/usr/local/directadmin/data/users/${OLD_USER}/#/usr/local/directadmin/data/users/${NEW_USER}/#g" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}."* 2> /dev/null
	sed -i -e "s#${OLD_HOME}/#${NEW_HOME}/#g" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}."* 2> /dev/null
	if [ -d "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.routes" ]; then
		sed -i -e "s#${OLD_HOME}/#${NEW_HOME}/#g" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.routes/"* 2> /dev/null
	fi

	#ensure the user.conf doesn't have the old domain. No need for new User, as they'd already have a default.
	if grep -q -F -x "domain=${DOMAIN}" "/usr/local/directadmin/data/users/${OLD_USER}/user.conf"; then
		#figure out a new default domain.. 
		DEFAULT_DOMAIN=$(head -n1 "/usr/local/directadmin/data/users/${OLD_USER}/domains.list")
		#may be filled.. may be empty.
		sed -i -e "s/^domain=${DOMAIN//./\\.}$/domain=${DEFAULT_DOMAIN}/" "/usr/local/directadmin/data/users/${OLD_USER}/user.conf"

		#if the new default domain exists, reset the ~/public_html link.
		if [ -h "${OLD_HOME}/public_html" ] && [ "${DEFAULT_DOMAIN}" != "" ] && [ -d "${OLD_HOME}/domains/${DEFAULT_DOMAIN}/public_html" ]; then
			rm -f                                           "${OLD_HOME}/public_html"
			ln -s "./domains/${DEFAULT_DOMAIN}/public_html" "${OLD_HOME}/public_html"
			chown -h "${OLD_USER}:${OLD_USER}"              "${OLD_HOME}/public_html"
		fi
	fi

	echo "Changing domain owner."
	sed -i -e "s/username=${OLD_USER}/username=${NEW_USER}/g" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.conf"

	#ip swapping, if needed.
	#empty the domain.ip_list, except 1 IP.
	OLD_IP=$(grep "^ip=" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.conf" | cut -d= -f2)
	NEW_IP=$(grep "^ip=" "/usr/local/directadmin/data/users/${NEW_USER}/user.conf"              | cut -d= -f2)
	if [ "${OLD_IP}" != "${NEW_IP}" ]; then
		echo "The old IP (${OLD_IP}) does not match the new IP (${NEW_IP}). Swapping..."
		#./ipswap.sh <oldip> <newip> [<file>]
		/usr/local/directadmin/scripts/ipswap.sh "${OLD_IP}" "${NEW_IP}" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.conf"
		/usr/local/directadmin/scripts/ipswap.sh "${OLD_IP}" "${NEW_IP}" "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.ftp"

		if [ -e /etc/debian_version ]; then
			/usr/local/directadmin/scripts/ipswap.sh "${OLD_IP}" "${NEW_IP}" "/etc/bind/${DOMAIN}.db"
		else
			/usr/local/directadmin/scripts/ipswap.sh "${OLD_IP}" "${NEW_IP}" "/var/named/${DOMAIN}.db"
		fi

		echo "${NEW_IP}" > "/usr/local/directadmin/data/users/${NEW_USER}/domains/${DOMAIN}.ip_list"

		#update the serial:
		da taskq --run "action=rewrite&value=named&domain=${DOMAIN}"
	fi

	#Update .htaccess files in case there is a protected password directory.
	PROTECTED_LIST="${NEW_HOME}/domains/${DOMAIN}/.htpasswd/.protected.list"
	if [ -s "${PROTECTED_LIST}" ]; then
		echo "Updating protected directories via ${PROTECTED_LIST}"
		while IFS= read -r PROTECTED_LINE; do
			PROTECTED_PATH="${NEW_HOME}/${PROTECTED_LINE}"
			if [ ! -d "${PROTECTED_PATH}" ]; then
				echo "Cannot find a directory at ${PROTECTED_PATH}"
				continue
			fi

			HTA=${PROTECTED_PATH}/.htaccess
			if [ ! -s "${HTA}" ]; then
				echo "${HTA} appears to be empty."
				continue
			fi

			sed -i -e "s#AuthUserFile ${OLD_HOME}/#AuthUserFile ${NEW_HOME}/#" "${HTA}"
		done < "${PROTECTED_LIST}"
	fi

	#complex bug: if multi-ip was used, should go into the zone and surgically remove the old ips from the zone, leaving only the NEW_IP.

	#this is needed to update "show all users" cache.
	da taskq --run "action=cache&value=showallusers"
	#this is needed to rewrite /usr/local/directadmin/data/users/USERS/httpd.conf
	da taskq --run "action=rewrite&value=httpd&user=${OLD_USER}"
	da taskq --run "action=rewrite&value=httpd&user=${NEW_USER}"
}

update_awstats() {
	sed -i -e "s#/home/${OLD_USER}/#/home/${NEW_USER}/#g" "/home/${NEW_USER}/domains/${DOMAIN}/awstats/.data/"*".conf"

	sed -i -e "s#/home/${OLD_USER}/#/home/${NEW_USER}/#g" "/home/${NEW_USER}/domains/${DOMAIN}/awstats/awstats.pl"

	#And for subdomains:
	sed -i -e "s#/home/${OLD_USER}/#/home/${NEW_USER}/#g" "/home/${NEW_USER}/domains/${DOMAIN}/awstats/"*"/.data/"*".conf"

	sed -i -e "s#/home/${OLD_USER}/#/home/${NEW_USER}/#g" "/home/${NEW_USER}/domains/${DOMAIN}/awstats/"*"/awstats.pl"
}

doChecks() {
	if [ ! -e "/usr/local/directadmin/data/users/${OLD_USER}/domains.list" ]; then
		echo "File '/usr/local/directadmin/data/users/${OLD_USER}/domains.list' does not exist. Can not continue."
		exit 1
	fi

	if [ "${DOMAIN}" = "" ]; then
		echo "The domain is blank"
		exit 1
	fi

	if [ "${OLD_HOME}" = "" ]; then
		echo "Could not get SOURCE user homedir! Can not continue."
		exit 1
	fi

	if [ "${NEW_HOME}" = "" ]; then
		echo "Could not get DESTINATION user homedir! Can not continue."
		exit 1
	fi

	if [ ! -e "/usr/local/directadmin/data/users/${NEW_USER}/domains.list" ]; then
		echo "File '/usr/local/directadmin/data/users/${NEW_USER}/domains.list' does not exist. Can not continue."
		exit 1
	fi

	if ! grep -q -F -x "${DOMAIN}" "/usr/local/directadmin/data/users/${OLD_USER}/domains.list"; then
		echo "Domain ${DOMAIN} is not owned by ${OLD_USER} user."
		exit 1
	fi

	if [ ! -d "${OLD_HOME}/domains/${DOMAIN}" ]; then
		echo "Direcory '${OLD_HOME}/domains/${DOMAIN}' does not exist. Can not continue."
		exit 1
	fi

	if [ -d "${NEW_HOME}/domains/${DOMAIN}" ]; then
		echo "Direcory '${NEW_HOME}/domains/${DOMAIN}' exists. Can not continue."
		exit 1
	fi
}

doChecks
update_da_settings
update_email_settings
update_ftp_settings
update_awstats

echo "Domain has been moved to ${NEW_USER} user."
