#!/bin/bash

. /etc/clouddirectory/provisioner.cf

die() {
	echo "$*" >&2
	exit 1
}

error() {
	echo "ERROR: $*" >&2
}

debug() {
	if [ "$PROVISIONER_LOGLEVEL" == "DEBUG" ] || [ "$PROVISIONER_LOGLEVEL" == "INFO" ]; then
		echo "DEBUG: $*" 2>&2
	fi
}

info() {
	if [ "$PROVISIONER_LOGLEVEL" == "INFO" ]; then
		echo "INFO: $*" 2>&2
	fi
}

if [ ! "$PROVISIONER_LOGLEVEL" ]; then
	info "loglevel not set. assuming INFO"
	export PROVISIONER_LOGLEVEL=INFO
fi

[ "$PROVISIONER_BATCH_LIMIT"      ] || die "missing config: PROVISIONER_BATCH_LIMIT"
[ "$PROVISIONER_MAILBOX_HOST"     ] || die "missing config: PROVISIONER_MAILBOX_HOST"
[ "$PROVISIONER_MAILBOX_IP"       ] || die "missing config: PROVISIONER_MAILBOX_IP"
[ "$PROVISIONER_MAILBOX_USER"     ] || die "missing config: PROVISIONER_MAILBOX_USER"
[ "$PROVISIONER_MAILBOX_TMP"      ] || die "missing config: PROVISIONER_MAILBOX_TMP"
[ "$PROVISIONER_EAM_CLASS"        ] || die "missing config: PROVISIONER_EAM_CLASS"
[ "$PROVISIONER_EAM_DISCLAIMER"   ] || die "missing config: PROVISIONER_EAM_DISCLAIMER"
[ "$PROVISIONER_EAM_DOMAIN"       ] || die "missing config: PROVISIONER_EAM_DOMAIN"
[ "$PROVISIONER_EAM_HOST"         ] || die "missing config: PROVISIONER_EAM_HOST"
[ "$PROVISIONER_RME_CLASS"        ] || die "missing config: PROVISIONER_RME_CLASS"
[ "$PROVISIONER_RME_DISCLAIMER"   ] || die "missing config: PROVISIONER_RME_DISCLAIMER"
[ "$PROVISIONER_RME_DOMAIN"       ] || die "missing config: PROVISIONER_RME_DOMAIN"
[ "$PROVISIONER_RME_HOST"         ] || die "missing config: PROVISIONER_RME_HOST"
[ "$PROVISIONER_PB_CU_CLASS"      ] || die "missing config: PROVISIONER_PB_CU_CLASS"
[ "$PROVISIONER_PB_CU_DISCLAIMER" ] || die "missing config: PROVISIONER_PB_CU_DISCLAIMER"
[ "$PROVISIONER_PB_CU_HOST"       ] || die "missing config: PROVISIONER_PB_CU_HOST"
[ "$PROVISIONER_ECU_CLASS"      ] || die "missing config: PROVISIONER_ECU_CLASS"
[ "$PROVISIONER_ECU_DISCLAIMER" ] || die "missing config: PROVISIONER_ECU_DISCLAIMER"
[ "$PROVISIONER_ECU_HOST"       ] || die "missing config: PROVISIONER_ECU_HOST"
[ "$PROVISIONER_PB_RM_CLASS"      ] || die "missing config: PROVISIONER_PB_RM_CLASS"
[ "$PROVISIONER_PB_RM_DISCLAIMER" ] || die "missing config: PROVISIONER_PB_RM_DISCLAIMER"
[ "$PROVISIONER_PB_RM_DOMAIN"     ] || die "missing config: PROVISIONER_PB_RM_DOMAIN"
[ "$PROVISIONER_PB_RM_HOST"       ] || die "missing config: PROVISIONER_PB_RM_HOST"

BATCH_CLEAN_SQL_TMPL="_batch_clean.sql"
BATCH_ZMPROV_TMPL="_batch_zmprov"

WELCOME_TEMPLATES=/etc/clouddirectory/welcome-mail

PROCESSED_OIDS=""

_add_cleanbatch() {
	if [ -f "$BATCH_CLEAN_SQL" ]; then
		echo -n ",$1" >> $BATCH_CLEAN_SQL
	else
		echo -n "DELETE FROM creditsuisse.prov_cmd WHERE oid IN ($1" > $BATCH_CLEAN_SQL
	fi
}

_finish_cleanbatch() {
	if [ -f "$BATCH_CLEAN_SQL" ]; then
		echo ");" >> $BATCH_CLEAN_SQL
	fi
}

_add_zmbatch() {
	echo "$*" >> $BATCH_ZMPROV
}

call_psql() {
	psql "$@"
}

mboxhost_by_cos() {
	case "$1" in
		"$PROVISIONER_PB_CU_CLASS")
			echo -n "$PROVISIONER_PB_CU_HOST"
		;;
		"$PROVISIONER_ECU_CLASS")
            echo -n "$PROVISIONER_ECU_HOST"
        ;;
		"$PROVISIONER_PB_RM_CLASS")
			echo -n "$PROVISIONER_PB_RM_HOST"
		;;
		"$PROVISIONER_EAM_CLASS")
			echo -n "$PROVISIONER_EAM_HOST"
		;;
		"$PROVISIONER_RME_CLASS")
			echo -n "$PROVISIONER_RME_HOST"
		;;
		*)
			echo -n "$PROVISIONER_MAILBOX_HOST"
	esac
}

process_line() {
	IFS='|' read rec_oid rec_class rec_operation rec_ident rec_firstname rec_lastname rec_email rec_cos rec_org_unit rec_notification rec_alias rec_old_alias rec_old_notification rec_old_username
        rec_firstname=`echo "$rec_firstname" | sed -e "s/'/'/g"`
        rec_lastname=` echo "$rec_lastname"  | sed -e "s/'/'/g"`
	local rec_host=`mboxhost_by_cos "$rec_cos"`
	case "$rec_operation" in
		"INSERT")
			_add_zmbatch "createAccount '$rec_email' '$rec_email' givenName \"$rec_firstname\" sn \"$rec_lastname\" displayName \"$rec_lastname, $rec_firstname ($rec_org_unit)\" title \"$rec_class\" zimbraMailHost \"$rec_host\""
			_add_zmbatch "setAccountCOS '$rec_email' '$rec_cos'"
			if [ "$rec_notification" != "" ]; then
				_add_zmbatch "modifyAccount '$rec_email' zimbraPrefNewMailNotificationAddress '$rec_notification'"
			fi
			if [ "$rec_alias" != "" ]; then
				_add_zmbatch "addAccountAlias '$rec_email' '$rec_alias'"
			fi
			_add_zmbatch "selectMailbox '$rec_email' addMessage '/INBOX' '$PROVISIONER_MAILBOX_TMP/$rec_class.eml'"
			_add_cleanbatch "$rec_oid"
		;;
		"UPDATE")
			if [ ! -z "$rec_old_username" ] ; then
			_add_zmbatch "modifyAccount '$rec_old_username' givenName \"$rec_firstname\" sn \"$rec_lastname\" displayName \"$rec_lastname, $rec_firstname ($rec_org_unit)\" title '$rec_class'"
			_add_zmbatch "setAccountCOS '$rec_old_username' '$rec_cos'"
		
			TEMP_COS=`echo $rec_cos|tr '[:lower:]' '[:upper:]'`
			TEMP_DOMAIN_NAME="PROVISIONER_"$TEMP_COS"_DOMAIN"
			TEMP_DOMAIN_NAME=`echo $TEMP_DOMAIN_NAME | sed -e "s/-/_/g"`
			TEMP_DOMAIN_NAME=`eval echo \\${$TEMP_DOMAIN_NAME}`	
			
				_add_zmbatch "renameAccount '$rec_old_username' '$rec_ident@$TEMP_DOMAIN_NAME'"
			else
				_add_zmbatch "modifyAccount '$rec_email' givenName \"$rec_firstname\" sn \"$rec_lastname\" displayName \"$rec_lastname, $rec_firstname ($rec_org_unit)\" title '$rec_class'"
				_add_zmbatch "setAccountCOS '$rec_email' '$rec_cos'"

			fi;

			## update alias
			if [ "$rec_alias" != "$rec_old_alias" ]; then	# alias has changed
				if [ "$rec_old_alias" != "" ]; then	# drop old alias
					_add_zmbatch "removeAccountAlias" "$rec_email" "$rec_old_alias"
				fi
				if [ "$rec_alias" != "" ]; then		# add new alias
					_add_zmbatch "addAccountAlias '$rec_email' '$rec_alias'"
				fi
			fi

			# push new mail notification address when changed
			if [ "$rec_notification" != "" ] && [ "$rec_notification" != "$rec_old_notification" ]; then
				_add_zmbatch "modifyAccount '$rec_email' zimbraPrefNewMailNotificationAddress '$rec_notification'"
			fi

			_add_cleanbatch "$rec_oid"
		;;
		"DELETE")
			_add_zmbatch "deleteAccount '$rec_email'"
			_add_cleanbatch "$rec_oid"
		;;
		*)
			error "# unsupported operation: $rec_operation"
		;;
	esac
}

init_prov() {
	_add_zmbatch "createDomain" "$PROVISIONER_PB_CU_DOMAIN"
	_add_zmbatch "createDomain" "$PROVISIONER_ECU_DOMAIN"
	_add_zmbatch "createDomain" "$PROVISIONER_PB_RM_DOMAIN"
	_add_zmbatch "createDomain" "$PROVISIONER_EAM_DOMAIN"
	_add_zmbatch "createDomain" "$PROVISIONER_RME_DOMAIN"
	_add_zmbatch "createDomain" "$PROVISIONER_PR_DOMAIN"
	_add_zmbatch "createCOS"    "$PROVISIONER_PB_CU_CLASS"
	_add_zmbatch "createCOS"    "$PROVISIONER_ECU_CLASS"
	_add_zmbatch "createCOS"    "$PROVISIONER_PB_RM_CLASS"
	_add_zmbatch "createCOS"    "$PROVISIONER_EAM_CLASS"
	_add_zmbatch "createCOS"    "$PROVISIONER_RME_CLASS"
	_add_zmbatch "createCOS"    "$PROVISIONER_PR_CLASS"
}

readlines() {
	local gotlines
	while read line ; do
		if [ ! "$gotlines" ]; then
			init_prov
			gotlines=1
		fi
		echo "$line" | sed -e "s~'~\\'~g;" | process_line
	done
	_finish_cleanbatch
}

do_query() {
	call_psql -At -c "SELECT oid, class, operation, ident, firstname, lastname, email, cos, org_unit, email_notification, email_alias, old_email_alias, old_notify,old_username FROM clouddirectory.provision_createuser ORDER BY ctime ASC LIMIT $PROVISIONER_BATCH_LIMIT"
}

process_output() {
	local got_error=""
	local m="[0-9a-z]"
	while read line ; do
		line=`echo "$line" | sed -e 's~prov> ~~g;'`
		case $line in
			*email\ address\ already\ exists:*)
				line=`echo "$line" | sed -e 's~.*email address already exists:~~; s~, at DN:.*~~; s~ ~~g;'`
				info "Skipped existing account: $line"
			;;
			*/tmp/eam.eml*|*/tmp/employee.eml*|*/tmp/pb-cu.eml*|*/tmp/ecu.eml*)
				echo >/dev/null
			;;
			\ \ $m$m$m$m$m$m$m$m-$m$m$m$m-$m$m$m$m-$m$m$m$m-$m$m$m$m$m$m$m$m$m$m$m$m)
				echo "KEY: $line"
			;;
			*account.DOMAIN_EXISTS*)
				line=`echo "$line" | sed -e 's~.*domain already exists: ~~;'`
				info "Skipped existing domain: $line"
			;;
			*account.NO_SUCH_ACCOUNT*)
				line=`echo "$line" | sed -e 's~.*no such account: ~~;'`
				info "Skipped non-existing account: $line"
			;;
			*cos\ already\ exists:*)
				line=`echo "$line" | sed -e 's~.*cos already exists: ~~;'`
				info "Skipping existing cos: $line"
			;;
			*ERROR:*)
				error "zmprov error: $line"
				got_error="1"
			;;
			*)
				info "zmprov line:  $line"
			;;
		esac
	done
	if [ "$got_error" ]; then
		error "remote zmprov call failed"
		return 1
	else
		debug "remote zmprov call succeed"
		return 0
	fi
}

call_zmprov() {
	debug "Running zmprov batch on $1 to $PROVISIONER_MAILBOX_IP"
	BASENAME=`basename "$1"`
	if ! scp -q "$1" "zimbra@$PROVISIONER_MAILBOX_IP:/tmp/ZMPROV.$BASENAME" ; then
		error "Failed pushing zmprov batch to server"
		return 1
	fi

	if (ssh $PROVISIONER_MAILBOX_USER@$PROVISIONER_MAILBOX_IP zmprov -f /tmp/ZMPROV.$BASENAME 2>&1) | process_output ; then
#		ssh $PROVISIONER_MAILBOX_USER@$PROVISIONER_MAILBOX_IP rm -f /tmp/ZMPROV.$BASENAME
#		rm -f $1
		debug "DONE"
		return 0
	else
		error "Provisioning batch failed: $1"
		return 1
	fi
}

push_welcome() {
	scp -q $WELCOME_TEMPLATES/*.eml $PROVISIONER_MAILBOX_USER@$PROVISIONER_MAILBOX_IP:$PROVISIONER_MAILBOX_TMP
}

push_welcome

while true ; do
	DATE=`date "+%s"`
	BATCH_CLEAN_SQL="$BATCH_CLEAN_SQL_TMPL.$DATE"
	BATCH_ZMPROV="$BATCH_ZMPROV_TMPL.$DATE"
	rm -f $BATCH_CLEAN_SQL $BATCH_ZMPROV
	do_query | readlines
	if [ -f $BATCH_ZMPROV ]; then
		info "Provisioning batch: $DATE"
		if call_zmprov "$BATCH_ZMPROV" ; then
			debug "Import succeed. cleaning journal records"
			call_psql < $BATCH_CLEAN_SQL >/dev/null && rm -f $BATCH_CLEAN_SQL
		else
			error "ERROR: zmprov import failed"
			exit 1
		fi
	else
		debug "No more journal records"
		exit 0
	fi
done
