#!/bin/bash

if [ -z "$SERVICE_NAME" ]; then
	echo 'Error: $SERVICE_NAME is not set' >&2
	exit 1;
fi

TIMEOUT="5400" #90s * 60 sec = 1.5h
TIMEOUT_KILL="60" # 60 sec to kill after timeout

FACILITY_NAME=$1
DESTINATION=$2
DESTINATION_TYPE=$3

PERUN_CERT="/etc/perun/ssl/perun-send.pem"
PERUN_KEY="/etc/perun/ssl/perun-send.key"
PERUN_CHAIN="/etc/perun/ssl/perun-send.chain"

#predefined different types of destination
DESTINATION_TYPE_URL="url"
DESTINATION_TYPE_EMAIL="email"
DESTINATION_TYPE_HOST="host"
DESTINATION_TYPE_USER_HOST="user@host"
DESTINATION_TYPE_USER_HOST_PORT="user@host:port"
DESTINATION_TYPE_USER_HOST_WINDOWS="user@host-windows"
DESTINATION_TYPE_HOST_WINDOWS_PROXY="host-windows-proxy"

#This function converts stdin based on DESTINATION_TYPE variable
function destination_type_transformation {
	if [ "$DESTINATION_TYPE" = "$DESTINATION_TYPE_HOST_WINDOWS_PROXY" ]; then
		base64 | sed -e "\$s/\$/ $DESTINATION/g" #converts stdin to base64 and append single space and "$DESTINATION" at the end of it
	elif [ "$DESTINATION_TYPE" = "$DESTINATION_TYPE_USER_HOST_WINDOWS" ]; then
		base64 #converts stdin to base64
	else
		cat #just prints stdin to stdout for other destination types
	fi
}

#if there is no destination type, use default 'host'
if [ -z "$DESTINATION_TYPE" ]; then
	DESTINATION_TYPE=$DESTINATION_TYPE_HOST
fi

#choose transport command, only url type has different transport command at this moment
if [ "$DESTINATION_TYPE" != "$DESTINATION_TYPE_URL" ]; then
	TRANSPORT_COMMAND="ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no -o GSSAPIKeyExchange=no -o ConnectTimeout=5"
else
	#add certificate to the curl if cert file and key file exists and they are readable
	if [ -r "${PERUN_CERT}" -a -r "${PERUN_KEY}" -a -r "${PERUN_CHAIN}" ]; then
		PERUN_CERT_SETTING="--cert ${PERUN_CERT} --key ${PERUN_KEY} --cacert ${PERUN_CHAIN}"
	fi
	TMPFILE=`mktemp /tmp/perun-generic-send-script.XXXXXX`
	if [ $? -ne 0 ]; then
		echo "Can't create TMPFILE /tmp/perun-generic-send-script.XXXXXX" >&2
		exit 255
	fi
	trap 'rm -r -f "$TMPFILE"' EXIT
	TRANSPORT_COMMAND="curl ${PERUN_CERT_SETTING} -i -H Content-Type:application/x-tar -w %{http_code} --show-error --silent -o $TMPFILE -X PUT --data-binary @- "
fi

#overriding of existing variables as TRANSPORT_COMMAND etc.
if [ -f "/etc/perun/services/${SERVICE_NAME}/${SERVICE_NAME}.conf" ]; then
	. "/etc/perun/services/${SERVICE_NAME}/${SERVICE_NAME}.conf"
fi

#load variables from generic_send configuration like WINDOWS_PROXY etc.
if [ -f "/etc/perun/services/generic_send/generic_send.conf" ]; then
	. "/etc/perun/services/generic_send/generic_send.conf"
fi

#use standard time and language settings (ASCII)
export LC_TIME="C"
export LANG="C"

SLAVE_COMMAND="/opt/perun/bin/perun"
SERVICE_FILES_BASE_DIR="`pwd`/../gen/spool"
SERVICE_FILES_DIR="$SERVICE_FILES_BASE_DIR/$FACILITY_NAME/$SERVICE_NAME"

#dir which contains special configuration for this destination (this dir may not exist)  ==IT MUST BE ABSOLUTE PATH (because of double -C in tar command)==
SERVICE_FILES_FOR_DESTINATION="$SERVICE_FILES_DIR/_destination/$DESTINATION"

#Just safety check. This should not happen.
if [ ! -d "$SERVICE_FILES_DIR" ]; then echo '$SERVICE_FILES_DIR: '$SERVICE_FILES_DIR' is not a directory' >&2 ; exit 1; fi

#unless specific configuration for destination exists use common configuration for all destination
[ -d "$SERVICE_FILES_FOR_DESTINATION" ] || SERVICE_FILES_FOR_DESTINATION="$SERVICE_FILES_DIR/_destination/all"

#prepare additional parameters for tar if using configuration per destination
TAR_OPTIONS_CONF_PER_DESTINATION=""
[ -d "$SERVICE_FILES_FOR_DESTINATION" ] && TAR_OPTIONS_CONF_PER_DESTINATION=" -C '${SERVICE_FILES_FOR_DESTINATION}' . "

case $DESTINATION_TYPE in
	${DESTINATION_TYPE_HOST})
		HOSTNAME="$DESTINATION"
		HOST="root@$DESTINATION"
		;;
	${DESTINATION_TYPE_USER_HOST})
		# Get the user name from the destination
		HOSTNAME=`echo $DESTINATION | sed -e 's/^.*@//'`
		HOST="$DESTINATION"
		;;
	${DESTINATION_TYPE_USER_HOST_PORT})
		HOST=`echo $DESTINATION | sed -e 's/:.*//'`
		HOSTNAME=`echo $HOST | sed -e 's/^.*@//'`
		PORT=`echo $DESTINATION | sed -e 's/^.*://'`
		;;
	${DESTINATION_TYPE_URL})
		HOSTNAME="$DESTINATION"
		HOST="$DESTINATION"
		;;
	${DESTINATION_TYPE_USER_HOST_WINDOWS})
		HOST=`echo $DESTINATION | sed -e 's/:.*//'`
		HOSTNAME=`echo $HOST | sed -e 's/^.*@//'`
		;;
	${DESTINATION_TYPE_HOST_WINDOWS_PROXY})
		if [ -z "${WINDOWS_PROXY}" ]; then echo 'Variable WINDOWS_PROXY is not defined. It is usually defined in /etc/perun/services/generic_send/generic_send.conf.' >&2 ; exit 1; fi
		HOST=`echo $WINDOWS_PROXY | sed -e 's/^.*@//'`
		;;
	${DESTINATION_TYPE_EMAIL})
		echo "Destination type '$DESTINATION_TYPE' is not supported yet." >&2
		exit 1;
		;;
	*)
		echo "Unknown destination type '$DESTINATION_TYPE'." >&2
		exit 1;
		;;
esac

if [ -n "${PORT}" ]; then
	TRANSPORT_COMMAND="${TRANSPORT_COMMAND} -p ${PORT}"
fi

TMP_HOSTNAME_DIR="`mktemp -d /tmp/perun-send.XXXXXXXXXX`"
if [ $? -ne 0 ]; then
	echo "Can't create temporary dir" >&2
	exit 255
fi

trap 'rm -r -f "$TMP_HOSTNAME_DIR" "$TMPFILE"' EXIT

echo $HOSTNAME > "$TMP_HOSTNAME_DIR/HOSTNAME"
if [ $? -ne 0 ]; then
	echo "Can't write hostname to $TMP_HOSTNAME_DIR/HOSTNAME" >&2
	exit 255
fi

#Default tar mode - create an archive
TAR_MODE="-c"

#Should we gzip the resulting tar archive?
#Do it for HTTP transport by default
if [ "$DESTINATION_TYPE" = "$DESTINATION_TYPE_URL" ]; then
  # Send a gziped tar archive via HTTP(s)
  TAR_MODE="${TAR_MODE}z"
fi

#Add host to the transport command for all types of destination
TRANSPORT_COMMAND="$TRANSPORT_COMMAND $HOST"
#Add also slave command if this is not url type of destination
if [ "$DESTINATION_TYPE" != "$DESTINATION_TYPE_URL" ]; then
	TRANSPORT_COMMAND="$TRANSPORT_COMMAND $SLAVE_COMMAND"
fi

if [ -d "$SERVICE_FILES_FOR_DESTINATION" ]
then
	STDOUT=`tar $TAR_MODE -C "$SERVICE_FILES_FOR_DESTINATION" . -C "$SERVICE_FILES_DIR"  --exclude="_destination" .  -C "$TMP_HOSTNAME_DIR" . | destination_type_transformation | timeout -k $TIMEOUT_KILL $TIMEOUT $TRANSPORT_COMMAND`
else
	STDOUT=`tar $TAR_MODE -C "$SERVICE_FILES_DIR"  --exclude="_destination" .  -C "$TMP_HOSTNAME_DIR" . | destination_type_transformation | timeout -k $TIMEOUT_KILL $TIMEOUT $TRANSPORT_COMMAND`
fi

ERR_CODE=$?

if [ $ERR_CODE -eq 124 ]; then
	#Special situation when error code 124 has been thrown. That means - timeouted and terminated from our side
	echo "$STDOUT"
	echo "Communication with slave script was timed out with return code: $ERR_CODE (Warning: this error can mask original error 124 from peer!)" >&2
else
	#In all other cases we need to resolve if 'ssh' or 'curl' was used
	if [ "$DESTINATION_TYPE" = "$DESTINATION_TYPE_URL" ]; then
		#In this situation 'curl' was used
		if [ $ERR_CODE -eq "0" ]; then
			#Check if curl ended without an error (ERR_CODE = 0) (if not, we can continue as usual, because there is an error on STDERR)
			if [ 200 -ne "$STDOUT" ]; then
				#Check if HTTP_CODE is different from OK (200)
				#If yes, then we will use HTTP_CODE as ERROR_CODE which is always non-zero
				ERR_CODE=$STDOUT
				cat "$TMPFILE" >&2
			else
				#If HTTP_CODE is 200, then call was successful and result call can be printed with info
				#Result call is saved in $TMPFILE
				ERR_CODE=0
				cat "$TMPFILE"
			fi
		fi
	else
		#In this situation 'ssh' was used, STDOUT has to be printed
		echo "$STDOUT"
	fi
	#For all situations different from time-out by our side we can return value from ERR_CODE as the result
  if [ $ERR_CODE -ne 0 ]; then
    echo "Communication with slave script ends with return code: $ERR_CODE" >&2
  fi
fi

exit $ERR_CODE
