#!/usr/bin/env bash
#
# Author: Georg Voell - georg.voell@standby.cloud
# Version: @(#)transfer 3.2.1 10.10.2024 (c)2024 Standby.cloud
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
#
# This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be
# error free and you will not be reimbursed for any damage it may cause.
#
#@  Get a resource from a host (or internet) via curl and check if an error occured.
#@
#@Usage: transfer [options] url
#@  Options:
#@    -h, --help             : Displays helptext.
#@    -v, --version          : Displays the version of the script.
#@    -q, --quiet            : Don't display any error messages.
#@    -a, --auth             : Using Oracle Authorization Header e.g. -H "Authorization: Bearer Oracle".
#@    -s, --seconds <number> : Max <number> of seconds for the operation to take (default is 10).
#@    -e, --export <filename>: Write output to file "<filename>".
#@  URL: URL can be specified with or without leading "http://".
#@
#@Examples:
#@  transfer http://standby.cloud/download/pdf/Basic-Admin-Scripts.pdf --export manual.pdf
#@    Downloads manual.pdf from server.
#@  transfer --auth http://169.254.169.254/opc/v2/instance
#@    Downloads oci instance metadata for current VM.
#
# Exit codes:
#  01: Unknown or wrong parameter.
#  02: **curl** not found. This script needs **curl** to perform.
#  03: Application error.
#  04: HTML error.
#  05: JSON error.
#  06: No internet connection or URL not found.
#  07: Error while creating output file.
#  99: User interrupt.
#
# See also:
#  **install-scripts**(1)
#
# Update history:
#
# V 3.0.0 24.04.2020 New version
# V 3.0.1 02.06.2020 Updated documentation
# V 3.0.2 11.06.2020 Using library
# V 3.0.3 17.09.2020 Using --connect-timeout instead of --max-time
# V 3.0.4 16.01.2021 Introduce Oracle Authorization Header
# V 3.0.5 13.03.2021 Check if we could write to output file
# V 3.1.0 05.06.2023 New copyright
# V 3.2.0 11.09.2024 New minor version
# V 3.2.1 10.10.2024 Small bug fix
#

# Find executable bash library and source it
lib=`which lib.bash 2>/dev/null | sed 's|^no 'lib.bash' in .*||'`
if [ "$lib" != "" ]; then
	source "$lib"
else
	progdir=`dirname "$0"`
	if [ -r "${progdir}/lib.bash" ]; then
		source "${progdir}/lib.bash"
	else
		echo "Unexpected error: Unable to locate bash library 'lib.bash'."
		exit 1
	fi
fi

# We expect messages in english
SAVEDLANG="$LANG"
LANG="en_US.UTF-8"	# en

# Do extra cleanup
function ExtraCleanup() {
	filecheck -rm ${scratchfile}.log
	LANG="$SAVEDLANG"
}

# Preset
param=""
outfile=""
quietstr=""
useauth=false
debug=false
seconds=5

# Check parameters: Loop until all parameters are used up
while [ $# -gt 0 ]; do
	pname=${1}
	case "$pname" in
		-s | --seconds)
			shift
			if [ "$1" != "" ]; then
				seconds=${1}
				shift
			else
				errstr="Please specify max number of seconds for the operation to take after '$pname'."
			fi
			;;
		-e | --export)
			shift
			if [ "$1" != "" ]; then
				outfile=${1}
				shift
			else
				errstr="Please specify a filename after '$pname'."
			fi
			;;
		-a | --auth)
			shift
			useauth=true
			;;
		-v | --version)
			shift
			showversion=true
			;;
		-h | --help)
			shift
			showhelp=true
			;;
		-q | --quiet)
			shift
			quietstr="$pname"
			;;
		-d | --debug)
			shift
			debug=true
			;;
		*)
			shift
			paramck=`echo "$pname" | grep '^-'` # Types don't begin with '-'
			if [ "$paramck" != "" ]; then
				errstr="Unknown option '$pname'."
			else
				if [ "$param" = "" ]; then
					param="$pname"	# `echo "$pname" | tr "[:upper:]" "[:lower:]"`
				else
					errstr="URL was already specified '$param'. Unknown additional parameter: '$pname'."
				fi
			fi
	esac
done

# Plausibility check
if [ "$param" = "" ]; then
	errstr="No hostname or URL specified."
fi

# Display help or error message
DisplayHelp

# curlparam can only be set after parameter evaluation: Need $seconds
# Set default values fur curl e.g. --connect-timeout 10 --max-time 60 --retry 3 --retry-delay 5 --show-error
curlparam="-skL --connect-timeout $seconds"		# -L = follow links (Location), -m = max time in seconds for the whole operation, -s = silent, -k = ignore cert issues

# Check if he have curl and jq in path
curl=`filecheck -x curl`
jq=`filecheck -x jq`

# wget maybe available in future releases
#wget=`filecheck -x wget`
#if [ "$wget" != "" ]; then
#	$wget -o ${scratchfile}.log "$param" -O $scratchfile
#	stat=$?
#	echo "stat: '$stat'."
#	echo "Logfile:"
#	cat ${scratchfile}.log
#	echo "Scratchfile:"
#	cat $scratchfile
#fi
#
#Cleanup
#exit $exitcode

if [ "$curl" = "" ]; then
	exitcode=2
	errormsg $exitcode "($progstr) No 'curl' in '$PATH'. Please install first e.g. 'sudo yum -y install curl'."
	exit $exitcode
else
	# Get result from server via curl
	if [ "$useauth" = false ]; then
		$curl $curlparam "$param" -o $scratchfile 2> ${scratchfile}.log
		stat=$?
	else
		$curl $curlparam -H "Authorization: Bearer Oracle" "$param" -o $scratchfile 2> ${scratchfile}.log
		stat=$?
	fi
	
	if [ $stat -eq 0 -a -f $scratchfile ]; then
		result=`filecheck -b $scratchfile`
		if [ "$result" = "" ]; then
			# scratchfile is not a binary file - check it for errors
			if [ "$debug" = true ]; then echo "Have result." >> ${scratchfile}.log; fi
			grepres="`head -n 1 $scratchfile | grep '^<'`"
			if [ "$grepres" != "" ]; then
				if [ "$debug" = true ]; then echo "Found html: '$grepres'." >> ${scratchfile}.log; fi
				grepres="`grep '>Application Error' $scratchfile`"
				if [ "$grepres" != "" ]; then
					grepres=`echo $grepres | cut -d'>' -f2 | cut -d'<' -f1`
					if [ "$debug" = true ]; then echo "result: '$grepres'." >> ${scratchfile}.log; fi
					printf "" > $scratchfile
					exitcode=3
					errormsg $quietstr $exitcode "($progstr) ${grepres}." "URL: $param"
				else
					grepres="`grep '>Error' $scratchfile`"
					if [ "$grepres" != "" ]; then
						result=`echo $grepres | awk -F '>Error ' '{print $NF}' | cut -d'<' -f1`
						if [ "$debug" = true ]; then echo "result: 'Error $result'." >> ${scratchfile}.log; fi
						printf "" > $scratchfile
						exitcode=4
						errormsg $quietstr $exitcode "($progstr) HTML Error." "$result"
					else
						grepres="`grep '>300 Multiple Choices<' $scratchfile`"
						if [ "$grepres" != "" ]; then
							if [ "$debug" = true ]; then echo "result: '300 Multiple Choices'." >> ${scratchfile}.log; fi
							printf "" > $scratchfile
							exitcode=4
							errormsg $quietstr $exitcode "($progstr) HTML Error." "300 Multiple Choices"
						fi
					fi
				fi
			else
				grepres="`head -n 1 $scratchfile | grep '^{'`"
				if [ "$grepres" != "" ]; then
					if [ "$debug" = true ]; then echo "Found json." >> ${scratchfile}.log; fi
					if [ "$jq" != "" ]; then
						# jq is installed. Pretty print JSON and check if there are any errors.
						cat $scratchfile | $jq '.' > ${scratchfile}.out 2>&1
						stat=$?
						
						if [ $stat -gt 0 ]; then
							exitcode=5
							result=`cat ${scratchfile}.out`
							if [ "$debug" = true ]; then echo "jq detected an error in JSON: $result" >> ${scratchfile}.log; fi
							filecheck -rm ${scratchfile}.out
							
							errormsg $quietstr $exitcode "($progstr) JSON Error." "$result"
						else
							mv ${scratchfile}.out $scratchfile
						fi
					fi
				fi
			fi

			grepres="`head -n 1 $scratchfile | grep '^404 page not found'`"
			if [ "$grepres" != "" ]; then
				if [ "$debug" = true ]; then echo "result: 'Error $grepres'." >> ${scratchfile}.log; fi
				printf "" > $scratchfile
				exitcode=4
				errormsg $quietstr $exitcode "($progstr) HTML Error." "404 page not found"
			fi
		fi
	else
		# No internet access or url not found
		if [ "$debug" = true ]; then
			echo "No internet access or URL '$param' not found." >> ${scratchfile}.log
			echo "stat: '$stat'." >> ${scratchfile}.log
		fi
		
		exitcode=6
		errormsg $quietstr $exitcode "($progstr) No internet access or URL '$param' not found."
	fi

	if [ "$debug" = true ]; then
		echo "Logfile:" > /dev/stderr
		cat ${scratchfile}.log > /dev/stderr
		echo "End of Logfile." > /dev/stderr
	fi
	
	# If we got an result, print it
	result=`filecheck -s $scratchfile`
	if [ "$result" != "" ]; then
		if [ "$outfile" != "" ]; then
			dname=`dirname "$outfile"`
			if [ ! -d "$dname" ]; then
				mkdir -m 0755 -p "$dname"
				stat=$?
			else
				stat=0
			fi
			
			if [ $stat -ne 0 ]; then
				exitcode=7
				errormsg $exitcode "Could not create folder '$dname'."
			else
				touch $outfile 2>/dev/null
				stat=$?
				
				if [ $stat -ne 0 ]; then
					exitcode=7
					errormsg $exitcode "Could not write to output file '$outfile'."
				else
					cat $scratchfile > "$outfile"
				fi
			fi
		else
			cat $scratchfile
		fi
	fi
fi

# Cleanup and exit
Cleanup
exit $exitcode