#!/bin/bash
#
# Univention
#
# Copyright (C) 2008-2017 Univention GmbH <http://www.univention.de/>
#
# and
#     iKu Systems & Services GmbH & Co. KG
#
# http://www.iku-systems.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.
set -e -u

. /usr/share/univention-ox/ox-lib.sh || exit 1
. /usr/share/univention-lib/all.sh || die "Failed to load all.sh library."

eval "$(univention-config-registry shell)"

MYSQL_HOST="localhost"
MYSQL_USER="openexchange"

SERVERNAME="localhost"
OXADMINMASTER="oxadminmaster"

main () {
	check_params "$@"
	check_join
	check_context

	mysql_prepare
	store_prepare

	init_configdb
	prepare_oxmaster_secret
	config_localhost

	configure_ucr
	setup_listener

	# from here on we need a running server
	restart_services

	init_localdb
	register_server
	register_store

	register_domain ${BINDARGS+"${BINDARGS[@]}"}
}

check_params () {
	PARAM_INIT=()
	BINDARGS=()
	while [ $# -ge 1 ]
	do
		case "$1" in
		--help|-h) usage ; exit 0 ;;
		--ignore-join) check_join () { :; } ; shift 1 ;;
		--mysql-host) OXDB="${2:?missing hostname}" ; export OXDB ; shift 2 ;;
		--mysql-password) OXDBPW="${2:?missing password}" ; export OXDBPW ; shift 2 ;;
		--drop-configdb) PARAM_INIT+=("-i") ; shift 1 ;;
		--context) CONTEXTNUM="${2:?missing context number}" ; shift 2 ;;
		--bind*) BINDARGS+=("$1" "$2") ; shift 2 ;;
		*) die 2 "Unknown option: $1" ;;
		esac
	done
}
usage () {
	cat <<-__USAGE__
	usage: ${0##*/} [options]

	Options:
	 --help, -h           Show this help
	 --mysql-host HOST    Overwrite MySQL host name
	 --mysql-password PW  Specify MySQL password for user '$MYSQL_USER'
	 --drop-configdb      Remove configdb from MySQL database
	 --ignore-join        Skip checking join status
	 --context NUM        Overwrite default context number (default: 10)
	 --bind* STR          LDAP Bind credentials
	__USAGE__
}

check_join () {
	msg "Checking join status..."
	[ -e "/usr/share/univention-join/.joined" ] ||
		die "The server has not joined yet. Use '$0 --ignore-join' to continue."
}

check_context () {
	msg "Checking for Open-Xchange context in LDAP..."
	OXCONTEXTNAME="context${CONTEXTNUM:=10}"
	if ox_context_check_ldap "$OXCONTEXTNAME"
	then
		echo "New context '$OXCONTEXTNAME' will be created." >&2
	else
		echo "Existing context '$OXCONTEXTNAME' will be re-used." >&2
	fi
}

MYSQL_SECRET_ROOT="/etc/mysql.secret"
MYSQL_SECRET_OX="$OXSECRETPATH/dbuser.secret"
mysql_prepare () {
	msg "Checking MySQL credentials..."
	if [ -n "${OXDB:-}" -o -n "${OXDBPW:-}" ]; then
		mysql_check_extern
		return
	fi
	if mysql_load_credentials
	then
		mysql_check_root
	else
		if [ ! -e "$MYSQL_SECRET_ROOT" ]; then
			mysql_check_local
			mysql_setup_root
		fi
		mysql_check_root
		mysql_create_account
	fi
	mysql_grant
}
mysql_check_extern () {
	MYSQL_OPTIONS=(
		-h "$OXDB"
		-u "$MYSQL_USER"
		--password="$OXDBPW"
	)
	_mysql -e '' >/dev/null 2>&1 ||
		die "Connection to MySQL server failed. Please check env. variables 'OXDB' and 'OXDBPW'."
	MYSQL_HOST="$OXDB"
	MYSQL_PASSWORD="$OXDBPW"
}
_mysql () {
	mysql ${MYSQL_OPTIONS+"${MYSQL_OPTIONS[@]}"} "$@"
}
mysql_load_credentials () {
	[ -e "$MYSQL_SECRET_OX" ] ||
		return 1
	MYSQL_PASSWORD="$(cat "$MYSQL_SECRET_OX")" ||
		die 1 "Failed to read MySQL secret from '$MYSQL_SECRET_OX'."
}
mysql_check_local () {
	MYSQL_OPTIONS=()
	_mysql -e '' ||
		die "Connection to MySQL server failed. Aborting"
}
mysql_setup_root () {
	mkdir -p -m 700 "$OXSECRETPATH" 2>/dev/null
	ox_write_secret "$MYSQL_SECRET_ROOT" "" ||
		die "Failed to save secret in '$MYSQL_SECRET_ROOT'."
	makepasswd --nocrypt >"$MYSQL_SECRET_ROOT" ||
		die "Failed to save secret in '$MYSQL_SECRET_ROOT'."
	/usr/bin/mysqladmin -u root password "$(cat "$MYSQL_SECRET_ROOT")" ||
		die "Failed to set MySQL password for user 'root'."
}
mysql_check_root () {
	MYSQL_OPTIONS=(
		-u root
		--password="$(cat "$MYSQL_SECRET_ROOT")"
	)
	_mysql -e '' >/dev/null 2>&1 ||
		die "Connection to MySQL server failed. Please check '$MYSQL_SECRET_ROOT' for user 'root'."
}
mysql_create_account () {
	MYSQL_PASSWORD="$("$OXPATH/sbin/genpw.sh")"
	ox_write_secret "$MYSQL_SECRET_OX" "$MYSQL_PASSWORD" ||
		die "Failed to save secret in '$MYSQL_SECRET_OX'."
}
mysql_grant () {
	_mysql \
		-e "GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'localhost' IDENTIFIED BY '$MYSQL_PASSWORD' WITH GRANT OPTION;" \
		-e "FLUSH PRIVILEGES;" ||
		die "Failed to grant privileges on MySQL databases to user '$MYSQL_USER'."
}

store_prepare () {
	msg "Creating Open-Xchange local file store..."
	OXFILESTORE="/var/oxfilestore"
	mkdir -p "$OXFILESTORE" 2>/dev/null
	chmod 700 "$OXFILESTORE"
	chown open-xchange "$OXFILESTORE"
	OXFILESTORESIZE=$(($(stat -c '%a*%S/1024/1126' -f "$OXFILESTORE")))
}

configure_ucr () {
	msg "Setting up UCR..."
	declare -a ucr=(
		ox/cfg/AdminUser.properties/CHECK_USER_UID_FOR_NOT_ALLOWED_CHARS=false
		ox/cfg/AdminUser.properties/PRIMARY_MAIL_UNCHANGEABLE=false
		ox/cfg/AdminUser.properties/USERNAME_CHANGEABLE=true
		ox/cfg/cache.ccf/jcs.auxiliary.LTCP.attributes.TcpServers='127.0.0.1:57461'
		ox/cfg/cache.ccf/jcs.auxiliary.LTCP.attributes.UdpDiscoveryEnabled=false
		ox/cfg/configjump.properties/URL="https://${ldap_server_name}/umc"
		ox/cfg/foldercache.properties/ENABLE_INTERNAL_USER_EDIT=false
		ox/cfg/Group.properties/CHECK_GROUP_UID_FOR_NOT_ALLOWED_CHARS=false
		ox/cfg/imap.properties/com.openexchange.imap.spamHandler="SpamAssassin"
		ox/cfg/mail.properties/com.openexchange.mail.adminMailLoginEnabled=true
		ox/cfg/push-udp.properties/com.openexchange.push.udp.senderAddress="$hostname.$domainname"
		ox/cfg/sessiond.properties/com.openexchange.sessiond.maxSessionPerUser=1000
	)
	ucr set "${ucr[@]}"
}

setup_listener () {
	local MODULES="/usr/lib/univention-directory-listener/system"
	rm -f "${MODULES}/ox-config.py"
	ln -s -f -t "$MODULES" /usr/share/univention-ox/listener/ox-context.py
	ln -s -f -t "$MODULES" /usr/share/univention-ox/listener/ox-domain.py
	deb-systemd-invoke restart univention-directory-listener.service
}

restart_services () {
	msg "Restarting Open-Xchange daemons..."
	ox_restart ||
		die "Open-Xchange daemon failed to restart."
	deb-systemd-invoke restart apache2.service
}

init_configdb () {
	msg "Creating Open-Xchange MySQL configuration database..."
	ox_retry \
	"$OXADMINPATH/initconfigdb" \
		--configdb-host "$MYSQL_HOST" \
		--configdb-user "$MYSQL_USER" \
		--configdb-pass "$MYSQL_PASSWORD" \
		${PARAM_INIT+"${PARAM_INIT[@]}"} &&
		return 0
	_mysql -e 'SHOW TABLES' "configdb" ||
		die "Failed to create initial MySQL database 'configdb'. Use '$0 --drop-configdb' do force a new one."
}
prepare_oxmaster_secret () {
	if [ -f "$OXMASTERSECRETFILE" ]
	then
		msg "Re-using Open-Xchange Master credentials..."
		OXADMINMASTER_PASSWORD="$(cat "$OXMASTERSECRETFILE")" ||
			die "Failed to read secret from '$OXMASTERSECRETFILE'."
	else
		msg "Creating Open-Xchange Master credentials..."
		OXADMINMASTER_PASSWORD=$("$OXPATH/sbin/genpw.sh")
		ox_write_secret "$OXMASTERSECRETFILE" "$OXADMINMASTER_PASSWORD" ||
			die "Failed to save secret in '$OXMASTERSECRETFILE'."
	fi
}
config_localhost () {
	msg "Setting up Open-Xchange configuration files..."
	ox_retry \
	"$OXADMINPATH/oxinstaller" \
		--configdb-readhost "$MYSQL_HOST" \
		--configdb-writehost "$MYSQL_HOST" \
		--configdb-pass "$MYSQL_PASSWORD" \
		--servername "$SERVERNAME" \
		--master-user "$OXADMINMASTER" \
		--master-pass "$OXADMINMASTER_PASSWORD" \
		--object-link-hostname "$hostname.$domainname/ox6" \
		--servermemory "$ox_java_mem" \
		--no-license ||
		die "Failed to create Open-Xchange configuration files."
}

init_localdb () {
	msg "Creating Open-Xchange MySQL database for '$SERVERNAME'..."
	local id
	/usr/sbin/wait_for_ox_server
	ox_retry \
	"$OXADMINPATH/registerdatabase" \
		--hostname "$MYSQL_HOST" \
		--dbpasswd "$MYSQL_PASSWORD" \
		--adminuser "$OXADMINMASTER" \
		--adminpass "$OXADMINMASTER_PASSWORD" \
		--name "$SERVERNAME" \
		--master true &&
		return 0

	id=$(_mysql -B -N -e "SELECT db_pool_id FROM db_pool WHERE name='$SERVERNAME'" "configdb") &&
		[ -n "$id" ] ||
		die "Failed to create per-server database pool '$SERVERNAME'"
	return 0
}
register_server () {
	msg "Registering Open-Xchange server in MySQL database..."
	local id
	/usr/sbin/wait_for_ox_server
	ox_retry \
	"$OXADMINPATH/registerserver" \
		--adminuser "$OXADMINMASTER" \
		--adminpass "$OXADMINMASTER_PASSWORD" \
		--name "$SERVERNAME" &&
		return 0

	id="$(_mysql -B -N -e "SELECT server_id FROM server WHERE name='$SERVERNAME'" "configdb")" &&
		[ -n "$id" ] ||
		die "Failed to register server '$SERVERNAME'."
	return 0
}
register_store () {
	msg "Registering Open-Xchange file store in MySQL database..."
	local id uri="file://$OXFILESTORE"
	/usr/sbin/wait_for_ox_server
	ox_retry \
	"$OXADMINPATH/registerfilestore" \
		--adminuser "$OXADMINMASTER" \
		--adminpass "$OXADMINMASTER_PASSWORD" \
		--storepath "$uri" \
		--storesize "$OXFILESTORESIZE" &&
		return 0

	id=$(_mysql -B -N -e "SELECT id FROM filestore WHERE uri='$uri'" "configdb") &&
		[ -n "$id" ] ||
		die "Failed to register file-store in MySQL database 'configdb'."
	return 0
}

mysql_check_schema () {
	msg "Checking MySQL database for schema..."
	local schema
	schema="$(_mysql -B -N -e "SELECT db_schema FROM context_server2db_pool NATURAL JOIN server WHERE name='$SERVERNAME'" "configdb")" &&
		[ -n "$schema" ] ||
		die "Failed to determine per-host database name for '$SERVERNAME'."
	_mysql -e 'SHOW TABLES' "$schema" ||
		die "Failed to access per-host database '$schema'."
	return 0
}

register_domain () {
	msg "Registering UCS domain for Open-Xchange..."
	CONTEXTNUM="$CONTEXTNUM" \
	/usr/sbin/ox-register-to-ucs-domain "$@" ||
		die "Failed to register UCS domain in OX."
}

main "$@"
exit $?
