#!/usr/bin/env bash
VERSION="0.2.6-daily"

# Global configuration
LIBRARY_PATH="/usr/lib64/pipelight/"
PLUGIN_PATH="/usr/lib64/browser-plugins"
CONFIG_PATH="/usr/share/pipelight/configs"
LICENSE_PATH="/usr/share/pipelight/licenses"
DEPENDENCY_INSTALLER_PATH="/usr/share/pipelight/install-dependency"
DEPENDENCY_INSTALLER_URL="https://bitbucket.org/mmueller2012/pipelight/raw/master/share/install-dependency.sig"
PIPELIGHT_PUBKEY="/usr/share/pipelight/sig-install-dependency.gpg"
PLUGINLOADER64_EXISTS="false"
ACCEPTALL=0

# Supported plugins
STANDARD_PLUGINS=("silverlight5.1" "silverlight5.0" "silverlight4" "flash" "unity3d" "widevine")
ADDITIONAL_PLUGINS=("shockwave" "foxitpdf" "grandstream" "adobereader" "hikvision" "npactivex" "roblox" "vizzedrgr" "viewright-caiway")

if [[ "$PLUGINLOADER64_EXISTS" =~ ^@@.*@@$ ]] || [ "$PLUGINLOADER64_EXISTS" == "true" ]; then
	STANDARD_PLUGINS=("${STANDARD_PLUGINS[@]}" "x64-flash")
	ADDITIONAL_PLUGINS=("${ADDITIONAL_PLUGINS[@]}" "x64-unity3d")
fi

ALL_PLUGINS=("${STANDARD_PLUGINS[@]}" "${ADDITIONAL_PLUGINS[@]}")

# Aliases
declare -A PLUGINALIAS
PLUGINALIAS[silverlight]="silverlight5.1"

usage()
{
	echo ""
	echo "Usage: pipelight-plugin [OPTIONS ...] COMMAND"
	echo ""
	echo "Environment variables:"
	echo "  MOZ_PLUGIN_PATH             overwrite plugin path"
	echo ""
	echo "Options:"
	echo "  --accept                    accept all licenses"
	echo ""
	echo "User commands:"
	echo "  --enable  PLUGIN            enable plugin"
	echo "  --disable PLUGIN            disable plugin"
	echo "  --disable-all               disable all plugins"
	echo "  --list-enabled              list enabled plugins for the current user"
	echo "  --list-enabled-all          list all enabled plugins"
	echo "  --help                      shows this help"
	echo "  --version                   shows the current version of Pipelight"
	echo ""
	echo "Global commands (require root rights):"
	echo "  --create-mozilla-plugins    create copies of libpipelight.so"
	echo "  --remove-mozilla-plugins    remove copies of libpipelight.so"
	echo "  --unlock PLUGIN             unlocks an additional plugin"
	echo "  --lock   PLUGIN             locks an additional plugin"
	echo "  --update                    update the dependency-installer script"
	echo ""
	echo ""
	echo "Supported standard plugins:"
	for entry in "${STANDARD_PLUGINS[@]}"; do
		echo "  $entry"
	done
	echo ""
	echo "Additional plugins (experimental):"
	for entry in "${ADDITIONAL_PLUGINS[@]}"; do
		echo "  $entry"
	done
	echo ""
}

version()
{
	if [[ "$VERSION" =~ ^@@.*@@$ ]]; then
		echo "Pipelight version unknown"
		return 1
	fi

	echo "Pipelight $VERSION"
	return 0
}

# > Get directories
# returns:
# $INSTALLDIR
INSTALLDIR=""
get_directories()
{
	if [ ! -z "$INSTALLDIR" ]; then return 0; fi

	# Fallback to Ubuntu path if not installed via make install
	if [[ "$LIBRARY_PATH" =~ ^@@.*@@$ ]] && [ -f "/usr/lib/pipelight/libpipelight.so" ]; then
		LIBRARY_PATH="/usr/lib/pipelight"
	elif [ ! -d "$LIBRARY_PATH" ]; then
		echo "ERROR: Failed to find $LIBRARY_PATH." >&2
		exit 1
	fi

	if [[ "$PLUGIN_PATH" =~ ^@@.*@@$ ]]; then
		PLUGIN_PATH="/usr/lib/mozilla/plugins"
	fi

	LIBRARY_PATH=$(readlink -m "$LIBRARY_PATH")
	PLUGIN_PATH=$(readlink -m "$PLUGIN_PATH")

	# Global installation
	if [ $(/usr/bin/id -u) -eq 0 ]; then
		INSTALLDIR="$PLUGIN_PATH"

	# Use environment variable (only if it doesn't point to the global directory)
	elif [ ! -z "$MOZ_PLUGIN_PATH" ] && [ "$MOZ_PLUGIN_PATH" != "$PLUGIN_PATH" ] && [ -d "$MOZ_PLUGIN_PATH" ]; then
		INSTALLDIR=$(readlink -m "$MOZ_PLUGIN_PATH")

	# Local installation
	else
		INSTALLDIR="$HOME/.mozilla/plugins"
	fi

	[ ! -z "$INSTALLDIR" ]
	return $?
}

# > Resolve plugin alias
# arguments:
# $1	- name of the plugin
resolve_plugin_alias()
{
	local PLUGIN="$1"

	if [ ! -z "${PLUGINALIAS[$PLUGIN]}" ]; then
		echo "${PLUGINALIAS[$PLUGIN]}"
	else
		echo "$PLUGIN"
	fi

	exit 0
}

# > Checks if a given additional plugin is supported
# arguments:
# $1	- name of the plugin
is_additional_plugin()
{
	local PLUGIN="$1"
	for entry in "${ADDITIONAL_PLUGINS[@]}"; do
		if [ "$PLUGIN" == "$entry" ]; then return 0; fi
	done
	return 1
}

# > Checks if a given plugin is supported
# arguments:
# $1	- name of the plugin
is_supported_plugin()
{
	local PLUGIN="$1"
	for entry in "${ALL_PLUGINS[@]}"; do
		if [ "$PLUGIN" == "$entry" ]; then return 0; fi
	done
	return 1
}

# > Shows the license agreement of a specific plugin and asks the user
# arguments:
# $1	- name of the plugin
show_license_dialog()
{
	local PLUGIN="$1"

	if [[ "$CONFIG_PATH" =~ ^@@.*@@$ ]]; then return 1; fi
	if [[ "$LICENSE_PATH" =~ ^@@.*@@$ ]]; then return 1; fi

	if [ ! -f "$CONFIG_PATH/pipelight-$PLUGIN" ]; then
		echo "ERROR: Config file for plugin $PLUGIN not found, unable to check license" >&2
		return 1
	fi

	local color0=$(echo -en "\e[0m")
	local color1=$(echo -en "\e[1;31m")
	local color2=$(echo -en "\e[1;34m")
	local color3=$(echo -en "\e[1m")

	local licenses=0
	for dep in $(sed -n 's|^[ \t]*dependency[ \t]*=[ \t]*wine-\(.*\)-installer[ \t]*$|\1|p' "$CONFIG_PATH/pipelight-$PLUGIN"); do
		if [ -f "$LICENSE_PATH/license-$dep.txt" ]; then
			if [ "$licenses" -eq 0 ]; then
				echo ""
				echo "The following modules require a license confirmation before they can be enabled:"
				echo ""
			fi
			while IFS= read line; do
				if [ "$line" == "---" ]; then break; fi
				echo "$line" | sed	-e 's|^\(\[\*\].*\)$|'$color1'\1'$color0'|g' \
									-e 's|\(http://[^ \t]*\)|'$color3'\1'$color0'|g' \
									-e 's|\(/usr/[^ \t]*\)|'$color3'\1'$color0'|g'
			done < "$LICENSE_PATH/license-$dep.txt"
			echo ""
			(( licenses++ ))
		fi
	done

	if [ "$ACCEPTALL" -eq 0 ] && [ "$licenses" -ne 0 ]; then
		read -p "Do you accept the $licenses license(s) above? [Y/N] " -n 1 -r choice
		echo ""
		if [[ ! "$choice" =~ ^[Yy]$ ]]; then
			return 1
		fi
	fi

	local licenses=0
	for dep in $(sed -n 's|^[ \t]*optional-dependency[ \t]*=[ \t]*wine-\(.*\)-installer[ \t]*$|\1|p' "$CONFIG_PATH/pipelight-$PLUGIN"); do
		if [ -f "$LICENSE_PATH/license-$dep.txt" ]; then
			if [ "$licenses" -eq 0 ]; then
				echo ""
				echo "The following modules are marked as optional dependencies:"
				echo ""
			fi
			while IFS= read line; do
				if [ "$line" == "---" ]; then break; fi
				echo "$line" | sed	-e 's|^\(\[\*\].*\)$|'$color2'\1 [OPTIONAL]'$color0'|g' \
									-e 's|\(http://[^ \t]*\)|'$color3'\1'$color0'|g' \
									-e 's|\(/usr/[^ \t]*\)|'$color3'\1'$color0'|g'
			done < "$LICENSE_PATH/license-$dep.txt"
			echo ""
			echo "	To agree to this license run (for each user who wants to use this module):"
			echo "	"$color3"touch \$HOME/.config/wine-$dep-installer.accept-license"$color0
			echo ""
			(( licenses++ ))
		fi
	done

	return 0
}


# > Enables/Disables a given plugin
# arguments:
# $1	- name of the plugin
enable_plugin()
{
	local PLUGIN="$1"
	if ! get_directories; then return 1; fi

	PLUGIN=$(resolve_plugin_alias "$PLUGIN")
	[ $? -eq 0 ] || return 1;

	if ! is_supported_plugin "$PLUGIN"; then
		echo "ERROR: Plugin $PLUGIN is unknown" >&2
		return 1
	fi

	local src="$LIBRARY_PATH/libpipelight-$PLUGIN.so"
	local dst="$INSTALLDIR/libpipelight-$PLUGIN.so"


	if [ ! -f "$src" ]; then
		if is_additional_plugin "$PLUGIN"; then
			echo "ERROR: You first need to call this program with: --unlock $PLUGIN" >&2
		else
			echo "ERROR: Your system is missing a copy of $LIBRARY_PATH/libpipelight.so at $src" >&2
		fi
		return 1
	fi

	# Create directory if it does not exist yet
	if [ ! -d "$INSTALLDIR" ] && ! mkdir -p "$INSTALLDIR" 2>/dev/null; then
		echo "ERROR: Failed to create $INSTALLDIR" >&2
		return 1
	fi

	# check if there is already a file
	if [ -L "$dst" ]; then
		rm "$dst"
	elif [ -e "$dst" ]; then
		echo "ERROR: $dst exists but is not a symlink, aborting - delete or rename this file manually." >&2
		return 1
	elif ! show_license_dialog "$PLUGIN"; then
		echo "Aborting" >&1
		return 1
	fi

	local srclnk="$LIBRARY_PATH/libpipelight-$PLUGIN.so"

	if ! ln -s "$srclnk" "$dst"; then
		echo "ERROR: Failed to create symlink from $src to $dst." >&2
		return 1
	fi

	echo "Plugin $PLUGIN is now enabled"
	return 0
}

disable_plugin()
{
	local PLUGIN="$1"
	if ! get_directories; then return 1; fi

	PLUGIN=$(resolve_plugin_alias "$PLUGIN")
	[ $? -eq 0 ] || return 1;

	if ! is_supported_plugin "$PLUGIN"; then
		echo "ERROR: Plugin $PLUGIN is unknown" >&2
		return 1
	fi

	if [ ! -d "$INSTALLDIR" ]; then
		echo "ERROR: Your plugin dir $INSTALLDIR does not exist - are you running this as a wrong user?" >&2
		return 1
	fi

	local dst="$INSTALLDIR/libpipelight-$PLUGIN.so"

	# check if there is a file
	if [ -L "$dst" ]; then
		if ! rm "$dst" 2>/dev/null; then
			echo "ERROR: Failed to delete symlink $dst." >&2
			return 1
		fi

		echo "Plugin $PLUGIN is now disabled"

	elif [ -e "$dst" ]; then
		echo "ERROR: $dst exists but is not a symlink, aborting - delete or rename this file manually." >&2
		return 1
	fi

	return 0
}

# > Checks if a plugin is enabled
# arguments:
# $1	- directory to check
# $2	- name of the plugin
is_enabled_plugin()
{
	local DIRECTORY="$1"
	local PLUGIN="$2"

	PLUGIN=$(resolve_plugin_alias "$PLUGIN")
	[ $? -eq 0 ] || return 1;

	if ! is_supported_plugin "$PLUGIN"; then
		echo "ERROR: Plugin $PLUGIN is unknown" >&2
		return 1
	fi

	if [ ! -d "$DIRECTORY" ]; then
		# Don't complain if the directory doesn't exist
		# echo "ERROR: Your plugin dir $DIRECTORY does not exist - are you running this as a wrong user?" >&2
		return 1
	fi

	local dst="$DIRECTORY/libpipelight-$PLUGIN.so"

	# check if there is a file
	[ -e "$dst" ] && [ -L "$dst" ]
	return $?
}

# > Disables all plugins
disable_all_plugin()
{
	for entry in "${ALL_PLUGINS[@]}"; do
		if ! disable_plugin "$entry"; then return 1; fi
	done

	return 0
}

# > List enabled plugins
list_enabled_plugins()
{
	if ! get_directories; then return 1; fi

	for entry in "${ALL_PLUGINS[@]}"; do
		if is_enabled_plugin "$INSTALLDIR" "$entry"; then echo "$entry"; fi
	done

	return 0
}

# > List all enabled plugins
list_all_enabled_plugins()
{
	if ! get_directories; then return 1; fi

	for entry in "${ALL_PLUGINS[@]}"; do
		if is_enabled_plugin "$INSTALLDIR" "$entry"; then echo "$entry"; fi
	done

	if [ "$INSTALLDIR" != "$PLUGIN_PATH" ]; then
		for entry in "${ALL_PLUGINS[@]}"; do
			if is_enabled_plugin "$PLUGIN_PATH" "$entry"; then echo "$entry"; fi
		done
	fi

	return 0
}

# > Create/Remove mozilla plugin copies
# arguments:
# $1	- Only change this plugin (optional, only used internally)
create_mozilla_plugins()
{
	if ! get_directories; then return 1; fi

	if [ -z "$1" ]; then
		local PLUGIN_LIST=("${ALL_PLUGINS[@]}")
		local skip_additional=0
	else
		local PLUGIN_LIST=("$1")
		local skip_additional=1
	fi

	local src="$LIBRARY_PATH/libpipelight.so"

	if [ ! -f "$src" ]; then
		echo "ERROR: Can't find Pipelight installation at $src." >&2
		return 1
	fi

	# Create copy of the original plugin in libpipelight-*.so
	for entry in "${PLUGIN_LIST[@]}"; do
		local dst="$LIBRARY_PATH/libpipelight-$entry.so"

		if [ -e "$dst" ]; then
			if ! rm -f "$dst" 2>/dev/null; then
				echo "ERROR: $dst exists but unable to delete it, aborting" >&2
				echo "ERROR: are you running this program with root rights?" >&2
				return 1
			fi
		elif [ "$skip_additional" -eq 0 ] && is_additional_plugin "$entry"; then
			continue
		fi

		if ! install -m 0644 "$src" "$dst" 2>/dev/null; then
			echo "ERROR: failed to create copy of $src at $dst" >&2
			echo "ERROR: are you running this program with root rights?" >&2
			return 1
		fi
	done

	return 0
}

remove_mozilla_plugins()
{
	if ! get_directories; then return 1; fi

	if [ -z "$1" ]; then
		local PLUGIN_LIST=("${ALL_PLUGINS[@]}")
	else
		local PLUGIN_LIST=("$1")
	fi

	for entry in "${PLUGIN_LIST[@]}"; do
		local dst="$LIBRARY_PATH/libpipelight-$entry.so"

		if [ -e "$dst" ] && ! rm -f "$dst" 2>/dev/null; then
			echo "ERROR: Failed to remove $dst." >&2
			return 1
		fi

	done

	return 0
}

# > Locks/Unlocks a given plugin
# arguments:
# $1	- name of the plugin
unlock_plugin()
{
	local PLUGIN="$1"
	if ! get_directories; then return 1; fi

	PLUGIN=$(resolve_plugin_alias "$PLUGIN")
	[ $? -eq 0 ] || return 1;

	if ! is_additional_plugin "$PLUGIN"; then
		echo "ERROR: Additional plugin $PLUGIN is unknown" >&2
		return 1
	fi

	if ! create_mozilla_plugins "$PLUGIN"; then
		return 1
	fi

	echo "Plugin $PLUGIN is now unlocked"
	return 0
}

lock_plugin()
{
	local PLUGIN="$1"
	if ! get_directories; then return 1; fi

	PLUGIN=$(resolve_plugin_alias "$PLUGIN")
	[ $? -eq 0 ] || return 1;

	if ! is_additional_plugin "$PLUGIN"; then
		echo "ERROR: Additional plugin $PLUGIN is unknown" >&2
		return 1
	fi

	if ! remove_mozilla_plugins "$PLUGIN"; then
		return 1
	fi

	echo "Plugin $PLUGIN is now locked"
	return 0
}


update_dependency_installer()
{
	if [[ "$DEPENDENCY_INSTALLER_PATH" =~ ^@@.*@@$ ]]; then return 1; fi
	if [[ "$PIPELIGHT_PUBKEY" =~ ^@@.*@@$ ]]; then return 1; fi

	local tmpfile=$(mktemp)
	[ -f "$tmpfile" ] || return 1

	# Grab the latest version if the dependency-installer script
	if ! wget -O "$tmpfile" "$DEPENDENCY_INSTALLER_URL"; then
		echo ""
		echo "ERROR: Failed to download latest dependency-installer script" >&2
		rm "$tmpfile"
		return 1
	fi

	local decfile=$(mktemp)
	if [ ! -f "$decfile" ]; then
		rm "$tmpfile"
		return 1
	fi

	# Ensure the signature is valid, extract the content
	if ! gpg --batch --no-default-keyring --keyring "$PIPELIGHT_PUBKEY" --decrypt "$tmpfile" > "$decfile"; then
		rm "$tmpfile"
		rm "$decfile"
		echo ""
		echo "ERROR: Failed to verify signature of the dependency-installer script" >&2
		return 1
	fi

	# We don't need the original one anymore
	rm "$tmpfile"

	# Check if something has changed by comparing the sha256sum
	local sha="$(sha256sum "$decfile" | cut -d' ' -f1)"
	if [ -f "$DEPENDENCY_INSTALLER_PATH" ] && [ "$sha" == "$(sha256sum "$DEPENDENCY_INSTALLER_PATH" | cut -d' ' -f1)" ]; then
		rm "$decfile"
		echo ""
		echo "Script dependency-installer is already up-to-date."
		return 0
	fi

	if ! install -m 0755 "$decfile" "$DEPENDENCY_INSTALLER_PATH" 2>/dev/null; then
		rm "$decfile"
		echo ""
		echo "ERROR: Root rights required to replace dependency-installer script" >&2
		return 1
	fi

	rm "$decfile"
	echo ""
	echo "Script dependency-installer has been updated to version $sha"
	return 0
}

# Print usage message when no arguments are given at all
if [ $# -eq 0 ]; then
	usage
	exit 0
fi

RET=0

while [[ $# > 0 ]] ; do
	CMD="$1"; shift
	case "$CMD" in
		--accept|-y)
			ACCEPTALL=1
			;;

		--enable-plugin|--enable)
			if ! enable_plugin "$1"; then RET=1; fi
			shift
			;;
		--enable-plugin=*|--enable=*)
			if ! enable_plugin "${CMD#*=}"; then RET=1; fi
			;;

		--disable-plugin|--disable)
			if ! disable_plugin "$1"; then RET=1; fi
			shift
			;;
		--disable-plugin=*|--disable=*)
			if ! disable_plugin "${CMD#*=}"; then RET=1; fi
			;;

		--disable-all)
			if ! disable_all_plugin; then RET=1; fi
			;;

		--list-enabled)
			if ! list_enabled_plugins; then RET=1; fi
			;;
		--list-enabled-all)
			if ! list_all_enabled_plugins; then RET=1; fi
			;;

		--create-mozilla-plugins)
			if ! create_mozilla_plugins; then RET=1; fi
			;;
		--remove-mozilla-plugins)
			if ! remove_mozilla_plugins; then RET=1; fi
			;;

		--unlock-plugin|--unlock)
			if ! unlock_plugin "$1"; then RET=1; fi
			shift
			;;
		--unlock-plugin=*|--unlock=*)
			if ! unlock_plugin "${CMD#*=}"; then RET=1; fi
			;;

		--lock-plugin|--lock)
			if ! lock_plugin "$1"; then RET=1; fi
			shift
			;;
		--lock-plugin=*|--lock=*)
			if ! lock_plugin "${CMD#*=}"; then RET=1; fi
			;;

		--update)
			if ! update_dependency_installer; then RET=1; fi
			;;

		--help)
			usage
			;;
		--version)
			if ! version; then RET=1; fi
			;;
		*)
			echo "ERROR: Unknown argument $CMD." >&2
			RET=1
			;;
	esac
done

exit "$RET"