
# Copyright 2015-2020 Rivoreo

# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:

# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

http_post() {
	if [ $# != 2 ]; then
		echo "Usage: http_post <url> <data>" 1>&2
		return 255
	fi
	command="${HTTP_CLIENT#*=}"
	case "${HTTP_CLIENT%%=*}" in
		wget)
			[ -z "$command" ] && command=wget
			$command --timeout 2 --tries 1 --no-verbose "$1" --post-data "$2" --output-document - &
			;;
		curl)
			[ -z "$command" ] && command=curl
			$command "$1" --request POST --data-binary "$2" &
			;;
		netcat)
			[ -z "$HTTP_SERVER_NAME" ] && prepare_http_server_information "$1"
			[ -z "$command" ] && command=netcat
			#post_data="`printf %s \"$2\" | sed 's/ /%20/g;s/!/%21/g;s/\"/%22/g;s/#/%23/g;s/\\$/%24/g;s/\\&/%26/g;s/'\"'\"'/%27/g;s/(/%28/g;s/)/%29/g;s/:/%3A/g'`"
			post_data="$2"
			printf 'POST %s HTTP/1.0\r
Host: %s\r
Content-Type: application/x-www-form-urlencoded\r
Content-Length: %s\r\n\r\n%s' "$HTTP_REQUEST_PATH" "$HTTP_SERVER_NAME" \
				"`printf %s \"$post_data\" | wc -c`" "$post_data" | \
					$command "$HTTP_SERVER_NAME" "$HTTP_SERVER_PORT" > /dev/null &
			;;
		bash)
			[ -z "$HTTP_SERVER_NAME" ] && prepare_http_server_information "$1"
			#post_data="`printf %s \"$2\" | sed 's/ /%20/g;s/!/%21/g;s/\"/%22/g;s/#/%23/g;s/\\$/%24/g;s/\\&/%26/g;s/'\"'\"'/%27/g;s/(/%28/g;s/)/%29/g;s/:/%3A/g'`"
			post_data="$2"
			printf 'POST %s HTTP/1.0\r
Host: %s\r
Content-Type: application/x-www-form-urlencoded\r
Content-Length: %s\r\n\r\n%s' "$HTTP_REQUEST_PATH" "$HTTP_SERVER_NAME" \
				"`printf %s \"$post_data\" | wc -c`" "$post_data" > \
					"/dev/tcp/$HTTP_SERVER_NAME/$HTTP_SERVER_PORT"
			;;
		*)
			printf "HTTP client type '%s' not recognized\\n" "$HTTP_CLIENT" 1>&2
			return 1
			;;
	esac
}

get_ip_address() {
	if [ $# != 1 ]; then
		echo "Usage: get_ip_address <interface>" 1>&2
		return 255
	fi
	ifconfig "$1" | grep -Ev '^[[:space:]]+tunnel ' | grep -Eo -m 1 '^[[:space:]]+inet[ a-z:]+([0-9]{1,3}\.){3}[0-9]{1,3}' | sed -r 's/^[[:space:]]+inet[ a-z:]+//'
	return 0
}

set_hostname_from_interface() {
	HOSTNAME="`get_ip_address \"$1\"`"
	if [ -z "$HOSTNAME" ]; then
		printf "Cannot get IP address from interface '%s'\\n" "$1" 1>&2
		exit 1
	fi
}

load_config_file() {
	[ -f "$1" ] || return
	eval "`grep -Eo '^[A-Z0-9_]+=[-A-Za-z0-9_@\" .:=/\\]+' \"$1\"`"
}

check_config() {
	if { [ -z "$INFLUXDB_BASE_URL" ] || [ -z "$INFLUXDB_DB_NAME" ]; } && [ -z "$CARBON_SERVER" ]; then
		echo "INFLUXDB_BASE_URL and INFLUXDB_DB_NAME must be set, or CARBON_SERVER must be set" 1>&2
		exit 1
	fi
	if [ -n "$INFLUXDB_BASE_URL" ] && [ -z "$INFLUXDB_DB_NAME" ]; then
		echo "Set INFLUXDB_BASE_URL but INFLUXDB_DB_NAME is not set" 1>&2
		exit 1
	fi
	if [ -n "$INFLUXDB_BASE_URL" ]; then
		if ! printf %s "$INFLUXDB_BASE_URL" | grep -q -e "^http://" -e "^https://"; then
			echo "INFLUXDB_BASE_URL doesn't contain a supported protocol" 1>&2
			exit 1
		fi
		[ -n "${INFLUXDB_BASE_URL##*/}" ] && INFLUXDB_BASE_URL="$INFLUXDB_BASE_URL/"
	fi
	[ -z "$HTTP_CLIENT" ] && check_http_client
	if [ -n "$INTERVAL" ]; then
		if ! [ "$INTERVAL" -gt 0 ]; then
			echo "Invalid INTERVAL setting; it must be a positive integer" 1>&2
			exit 1
		fi
	else
		INTERVAL=5
	fi
	[ -n "$INTERFACE" ] && set_hostname_from_interface "$INTERFACE"
	[ -z "$HOSTNAME" ] && HOSTNAME="`hostname`"
}

handle_command_line_options() {
	while getopts i:I:n: c
	do case "$c" in
		i)
			INTERVAL="$OPTARG"
			;;
		I)
			INTERFACE="$OPTARG"
			;;
		n)
			HOSTNAME="$1"
			;;
		\?)
			printf "Usage: %s [-i <interval>] [-I <interface>] [-n <hostname>]\\n" "$0" 1>&2
			exit 255
			;;
	esac done
	check_config
}

check_http_client() {
	if wget --version 2> /dev/null | grep -q "^GNU Wget "; then
		HTTP_CLIENT=wget
	elif curl --version 2> /dev/null | grep -q "^curl "; then
		HTTP_CLIENT=curl
	elif printf %s "$INFLUXDB_BASE_URL" | grep -q "^http://"; then
		if ncat --version 2>&1 | grep -q "^Ncat: "; then
			HTTP_CLIENT=netcat=ncat
		else
			for nc in netcat nc; do case "`$nc --version 2>&1 | sed 1!d`" in
				"Ncat: "*|*"The GNU Netcat"*)
					HTTP_CLIENT=netcat=$nc
					return
					;;
			esac done
			if nc -h 2>&1 | grep -Eq '^\[v1\..+\]$'; then
				HTTP_CLIENT=netcat=nc
			elif [ -n "$BASH" ]; then
				HTTP_CLIENT=bash
			else
				echo "Need a HTTP client tool to post data via HTTP" 1>&2
				exit 1
			fi
		fi
	else
		echo "Need a HTTP client tool to post data via HTTPS" 1>&2
		echo "Please install wget(1) or curl(1)" 1>&2
		exit 1
	fi
}

prepare_http_server_information() {
	HTTP_SERVER_NAME="${1#http://}"
	HTTP_REQUEST_PATH="/${HTTP_SERVER_NAME#*/}"
	HTTP_SERVER_NAME="${HTTP_SERVER_NAME%%/*}"
	HTTP_SERVER_PORT="${HTTP_SERVER_NAME##*:}"
	if [ "$HTTP_SERVER_PORT" = "$HTTP_SERVER_NAME" ]; then
		HTTP_SERVER_PORT=80
	else
		HTTP_SERVER_NAME="${HTTP_SERVER_NAME%:[0-9]*}"
	fi
}

check_netcat_for_carbon() {
	if ncat --version 2>&1 | grep -q "^Ncat: "; then
		NETCAT_FOR_CARBON="ncat -n"
		return 0
	fi
	for nc in netcat nc; do case "`$nc --version 2>&1 | sed 1!d`" in
		"Ncat: "*|*"The GNU Netcat"*)
			NETCAT_FOR_CARBON="$nc -n"
			return 0
			;;
	esac done
	if nc -h 2>&1 | grep -Eq '^\[v1\..+\]$'; then
		NETCAT_FOR_CARBON="nc -n -q 1"
		return 0
	fi
	if bash --version | grep -q "^GNU bash"; then
		NETCAT_FOR_CARBON="bash -c 'exec cat > /dev/tcp/\$1/\$2'"
		return 0
	fi
}

send_carbon_lines() {
	[ -n "$CARBON_SERVER" ] || exec cat > /dev/null
	[ -n "$CARBON_PORT" ] || CARBON_PORT=2003
	if [ -n "$BASH" ]; then
		until cat > "/dev/tcp/$CARBON_SERVER/$CARBON_PORT"; do sleep 4; done
	else
		[ -n "$NETCAT_FOR_CARBON" ] || check_netcat_for_carbon || exit
		until $NETCAT_FOR_CARBON "$CARBON_SERVER" "$CARBON_PORT"; do sleep 4; done
	fi
}
