#!/bin/bash
################################################################################
# Filename: ./src/base/include/qrm-setup-functions
# 
# The contents of this file are subject to the Qlusters Public License
# Version 1.1 (the License); you may not use this file except in compliance
# with the License.
# You may obtain a copy of the License at
# http://www.openqrm.org/content/view/33/69/.
# 
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
# 
# The Original Code is openQRM.
# 
# The Initial Developer of the Original Code is Qlusters Corporation. Portions
# created by Qlusters Corporation are Copyright (C) 2003-2005. All Rights
# Reserved.
# 
# Contributor(s):
# 
# Description:
# 
# Comments:
################################################################################
# 
# Qrm functions for setup and installation
#

export QRM_SERVER_BASE_DIR=${QRM_SERVER_BASE_DIR:-`readlink /etc/init.d/qrm-server | sed -e "s#/qrm/etc/init.d/qrm-server##g"`}
if [ -z "$QRM_SERVER_HOOKS" ]; then
	. $QRM_SERVER_BASE_DIR/qrm/include/qrm-functions
fi

ARCH="`uname -m 2>/dev/null`"
if [ -z "$ARCH" ] && [ -x /usr/bin/dpkg ] ; then
	# For debian
	ARCH=$(/usr/bin/dpkg --print-installation-architecture)
elif [ -z "$ARCH" ] ; then
	echo "WARNING: Cannot find Architecture, assuming i386"
	ARCH="i386"
fi
SYSTEM=`uname -s`
QRM_BUILD_BASE_DIR=${QRM_BUILD_BASE_DIR:-/var}
export QRM_CACHE_DIR=${QRM_CACHE_DIR:-${QRM_BUILD_BASE_DIR}/cache/qrm}
export QRM_ROOT_DIR=${QRM_ROOT_DIR:-${QRM_BUILD_BASE_DIR}/tmp/qrm}
export QRM_BUILD_DIR=${QRM_BUILD_DIR:-${QRM_ROOT_DIR}/build}

function set_install_log_end_time() {
	sync
	END_TIME=`date +"%m.%d.%Y_%H.%M.%S"`
	echo "$1 finished at $END_TIME" >> $2
}


QRM_DIE=exit

function qrm_die() {
	local msg="$1"
	local code="${2:-1}"

	echo "ERROR: $msg" > /dev/stderr
	$QRM_DIE $code	
}

function get_lib_deps() {
	BINARY=$1
	for COPYLIB in `ldd $BINARY | awk {' print $1 $2 $3 '} | cut -d'(' -f 1 | grep -v ld-linux`; do
		LIBRARY=`echo $COPYLIB | cut -d'>' -f 2`
		if [ ! -z $LIBRARY ] && [ -f $LIBRARY ]; then
			ALL_LIBRARY=`echo $LIBRARY | cut -d'.' -f 1 | cut -d'-' -f 1`
			LIB_DIR=`dirname $LIBRARY`
			echo "$ALL_LIBRARY"
		fi
	done
}


function qrm_cache() {
	TYPE=$1
	FILE=$2
	URL="$3"
	TIME_OUT=10
	RETRY=5
	
	if [ ! -f "$QRM_CACHE_DIR/src/$FILE" ]; then
		if [ "$TYPE" == "URL" ]; then
			mkdir -p $QRM_CACHE_DIR/src
			
			for REPOSITORY in $URL; do
				if wget --passive-ftp -T $TIME_OUT -t $RETRY -O $QRM_CACHE_DIR/src/$FILE $REPOSITORY; then
					break;
				fi
			done
			
		elif [ "$TYPE" == "FILE" ]; then
			if [ -f "$URL" ]; then
				for REPOSITORY in $URL; do
					if /bin/cp $REPOSITORY $QRM_CACHE_DIR/src/$FILE; then
						break;
					fi
				done
				
			elif [ -n "$QRM_SERVER_BASE_DIR" ] && [ -f "$QRM_SERVER_BASE_DIR/$URL" ]; then
				for REPOSITORY in $URL; do
					if /bin/cp ${QRM_SERVER_BASE_DIR}/${REPOSITORY} $QRM_CACHE_DIR/src/$FILE; then
						break;
					fi
				done

			fi
		fi
	fi
	FILE_SIZE=`du -sb $QRM_CACHE_DIR/src/$FILE | awk {' print $1 '}`
	if (( $FILE_SIZE == 0 )); then
		rm -f $QRM_CACHE_DIR/src/$FILE
		echo UNSUCCESSFULL
		return 1
	else
		echo "$QRM_CACHE_DIR/src/$FILE";
	fi 
}

function qrm_unpack() {
	PACKAGE=$1
	LOCATION=$2
	PACKAGE_TYPE=`file -bL $PACKAGE`

	export UNPACKED_PACKAGE=$PACKAGE

	mkdir -p $LOCATION

	if echo $PACKAGE | grep -q "src.rpm"; then
		cd $LOCATION
		SRC_PKG=`basename $PACKAGE .src.rpm`
		cat $PACKAGE | rpm2cpio | cpio -i --no-absolute-filenames
		PACKAGE="$SRC_PKG.*"
		if ! ls $PACKAGE 1>/dev/null 2>&1; then
			PACKAGE=`ls -Sr | tail -n1`
		fi
		PACKAGE_TYPE=`file -bL $PACKAGE`
	fi

	if echo $PACKAGE_TYPE | grep -q "tar archive" || echo $PACKAGE | grep -q '\.tar' || echo $PACKAGE | grep -q '\.tgz' ; then
		TAR_OPTIONS="-x"
		if echo $PACKAGE_TYPE | grep -q "gzip"; then
			TAR_OPTIONS="-z $TAR_OPTIONS"
		elif echo $PACKAGE_TYPE | grep -q "bzip2"; then
			TAR_OPTIONS="-j $TAR_OPTIONS"
		fi
		tar -C $LOCATION $TAR_OPTIONS -f $PACKAGE
		unset UNPACKED_PACKAGED
	fi # put other package type processings here

	if [ -n "$SRC_PKG" ]; then
		rm -fv $PACKAGE
	fi

}

function qrm_compile() {
	NAME=$1
	PACKAGE=$2
	BINS=`echo $3 | tr ':' ' '`
	
	qrm_unpack $PACKAGE $QRM_BUILD_DIR/$NAME

	cd $QRM_BUILD_DIR/$NAME/*/

	export PATH="$QRM_ROOT_DIR/bin:$PATH"
	export CFLAGS="-I$QRM_ROOT_DIR/include $CFLAGS"
	export CXXFLAGS="-I$QRM_ROOT_DIR/include $CXXFLAGS"
	export LDFLAGS="-L$QRM_ROOT_DIR/lib $LDFLAGS"

	if [ -x "configure" ]; then
		#./configure --prefix=$QRM_ROOT_DIR $QRM_CONFIGURE_OPTIONS
		./configure $QRM_CONFIGURE_OPTIONS
	fi

	if [ -n "$QRM_PRE_MAKE_CMD" ]; then
		$QRM_PRE_MAKE_CMD
	fi

	make $QRM_MAKE_OPTIONS

	if [ $? != 0 ]; then
		qrm_die "Failed building $NAME" 1
	fi

	if [ -n "$QRM_POST_MAKE_CMD" ]; then
		$QRM_POST_MAKE_CMD
	fi

	## modified "make install" ?
	mkdir -p $QRM_CACHE_DIR/$NAME/
	for BIN in $BINS; do
		install -D $BIN $QRM_CACHE_DIR/$NAME/$BIN
	done

}


#
# Build a package for qrm
# 
# Called with the following parameters:
# CONF - the package config file (e.g. busybox.conf)

function build_package() {
	CONF=$1
	PACKAGE_MODE=${PACKAGE_MODE:-"source"}
	if [ ! -f "$CONF" ]; then
		qrm_die "No such file $CONF"  1
	fi
	. $CONF
	
	# check if binaries are installed
	unset NEED_BUILD
	for BIN in `echo $BINS | tr ':' ' '`; do
		if [ ! -f "$QRM_CACHE_DIR/$PACKAGE_NAME/$BIN" ]; then
			NEED_BUILD=1
			break
		fi
	done
	if [ "$NEED_BUILD" != "1" ]; then
		echo "Package $PACKAGE_NAME already installed"
		return
	fi

	if [ "$NOBIN" == "$PACKAGE_NAME" ]; then
		echo "WARNING: No binary package available! Building $PACKAGE_NAME from the sources"
		export PACKAGE_MODE=source
	elif [ "$NOUSER" == "$PACKAGE_NAME" ]; then
		echo "WARNING: $PACKAGE_NAME is not installed ! Trying binary package-mode"
		export PACKAGE_MODE=binary
	fi
	
	echo "Providing package $PACKAGE_NAME using package-mode $PACKAGE_MODE"
	case "$PACKAGE_MODE" in
		source)
			echo "Building $PACKAGE_NAME from the sources"
			echo "Compiling package $PACKAGE_NAME"
			PACKAGE=`qrm_cache URL $FILE "$SOURCE"`
			if [ "$PACKAGE" == "UNSUCCESSFULL" ]; then
				qrm_die "Could not download Qrm-component from $SOURCE" 1
			fi
			qrm_compile $PACKAGE_NAME $PACKAGE $BINS
			;;
		
		binary)
			echo "Using $PACKAGE_NAME from pre-compiled binaries/rpm's/deb's"
			# find out arch / distribution / version
			DISTRIBUTION=`get_linux_distribution`
			eval BINARY_PACKAGE_URL=\$BINARY_${DISTRIBUTION}_${ARCH}
			if [ ! -z "$BINARY_PACKAGE_URL" ]; then
				BINARY_PACKAGE_FILE=`basename $BINARY_PACKAGE_URL`
				# binary package exist, download and install it
				# currently only RPM is supported
				PACKAGE_LOCATION=`qrm_cache URL $BINARY_PACKAGE_FILE "$BINARY_PACKAGE_URL"`
				if [ "$PACKAGE_LOCATION" == "UNSUCCESSFULL" ]; then
					qrm_die "Could not download Qrm-component from $SOURCE" 1
				fi
				echo "NOTICE: Installing package $PACKAGE_NAME from $PACKAGE_LOCATION!"
				echo "Testing if we can install the package ....."
				if ! rpm -Uhv --test $PACKAGE_LOCATION; then
					qrm_die "Install-test for $PACKAGE_LOCATION failed!" 1
				fi
				echo "Looks good, installing $PACKAGE_NAME from $PACKAGE_LOCATION now"
				rpm -Uhv $PACKAGE_LOCATION
			elif [ ! -z "$BINARY_DEFAULT" ]; then
				# binary default package exist, download and install it
				# currnetly only tarballs are supported
				FILE=`basename $BINARY_DEFAULT`
				PACKAGE_LOCATION=`qrm_cache URL $FILE "$BINARY_DEFAULT"`
				if [ "$PACKAGE_LOCATION" == "UNSUCCESSFULL" ]; then
					qrm_die "Could not download Qrm-component from $SOURCE"  1
				fi
				echo "NOTICE: Unpacking package $PACKAGE_NAME from $PACKAGE_LOCATION!"
				qrm_unpack $PACKAGE_LOCATION  $QRM_CACHE_DIR/$NAME
			else
				# no binary package is available, build from the sources
				export NOBIN=$PACKAGE_NAME
				build_package $CONF
			fi
			;;

		userctl)
			echo "Using already installed package $PACKAGE_NAME"
			# find out arch / distribution / version
			DISTRIBUTION=`get_linux_distribution`
			BINARY_PACKAGE_URL=`cat $CONF | grep $DISTRIBUTION | grep $ARCH | sed -e "s/.*=//" | sed -e "s/\"//g"`
			BINARY_PACKAGE_FILE=`basename $BINARY_PACKAGE_URL`
			BINARY_PACKAGE_NAME=`echo $BINARY_PACKAGE_FILE | sed -e "s/-[0-9].*//"`
			echo "Checking if $PACKAGE_NAME / $BINARY_PACKAGE_NAME is installed"
			if rpm -q $BINARY_PACKAGE_NAME; then
				echo "NOTICE: Package $PACKAGE_NAME / $BINARY_PACKAGE_NAME is installed"
			else
				# if not build it.
				echo "$PACKAGE_NAME is not installed"
				export NOUSER=$PACKAGE_NAME
				build_package $CONF
			fi
			;;

			*)
				qrm_die "No such package-mode $PACKAGE_MODE"
			;;		
	esac
	


}



# function to set the plugins to enabled/disabled
function qrm_plugin_set_install() {
	PLUGIN=$1
	STATUS=$2
	PLUGIN_NAME=`echo $PLUGIN | sed 's/^QRM_PLUGIN_//'`
	QRM_SERVER_CONFIG="$QRM_SERVER_BASE_DIR/qrm/etc/qrm.ini"

	TMPFILE=`mktemp -q /tmp/XXXXXX` || return 1
	# handle Plugin_ fields
	if grep -qi '^Plugin_$PLUGIN_NAME' $QRM_SERVER_CONFIG; then
		cat $QRM_SERVER_CONFIG | sed -e "s/Plugin_$PLUGIN_NAME.*/Plugin_$PLUGIN_NAME=\"$STATUS\";/gI" > $TMPFILE
	elif grep -qi "\=$PLUGIN_NAME" $QRM_SERVER_CONFIG; then
		# new plugin format. plugin exists in config
		if echo $STATUS | grep -qi "enabled"; then
			cat $QRM_SERVER_CONFIG | sed -e "s/;\(.*\)=\($PLUGIN_NAME\)/\1=\2/I" > $TMPFILE
		else
			cat $QRM_SERVER_CONFIG | sed -e "s/;*\(.*\)=\($PLUGIN_NAME\)/;\1=\2/I" > $TMPFILE
		fi
	else
		# add plugin with new format. XXX: not implemented yet
		qrm_die "Unknown plugin" 1
	fi
	/bin/mv $TMPFILE $QRM_SERVER_CONFIG
	chmod 777 $QRM_SERVER_CONFIG
}


function qrm_set_ini_value() {
	FILE=$1
	SECTION=$2
	KEY=$3
	VALUE=$4
	
	if [ ! -f $FILE ]; then
		qrm_error "ERROR: Unable to find ini file $FILE"
		return 1
	fi

	LINE=`cat $FILE | sed -n "/^\[$SECTION\]/,/^\[/s/^\([^\[;].\+\)=\(.*\)/\1=\2/p" | grep $KEY | tr [:lower:] [:upper:]`
	if [ "${LINE/*=/}" == "$VALUE" ]; then
		# already set
		return 0
	elif [ -z "$LINE" ]; then
		# add key=value to section
		cat $FILE | awk "
BEGIN { in_section = 0 }
in_section == 0 { print; if (index(\$0,\"[$SECTION]\")) { in_section = 1; next } }
in_section == 1 { if (NF == 0) { print \"$KEY=$VALUE\\n\"; in_section = 2; next }; print; if (substr(\$0,1,1) == \"[\") { in_section = 2; next } }
in_section == 2 { print }
END { if (in_section == 1) { print \"$KEY=$VALUE\\n\" } }
" > ${FILE}.new
		if [ -s ${FILE}.new ]; then
			mv -f ${FILE}.new $FILE
		fi
	else
		# change in place
		cat $FILE | awk "
BEGIN { in_section = 0 }
in_section == 0 { print; if (index(\$0,\"[$SECTION]\")) { in_section = 1; next } }
in_section == 1 { sub(\"^$KEY=.*\",\"$KEY=$VALUE\"); print; if (substr(\$0,1,1) == \"[\") { in_section = 2; next } }
in_section == 2 { print }
" > ${FILE}.new
		if [ -s ${FILE}.new ]; then
			mv -f ${FILE}.new $FILE
		fi
	fi

}

#function to control a plugin
function qrm_plugin() {
	if [ $# -lt 2 ];then
		echo "Usage: $(basename $0) <plugin name> <command>"
		echo "common commands are: install, uninstall, start, stop, run_once"
		return 0
	fi
	local plugin=$1
	local command=$2
	shift 2
	
	local PLUGIN=$(echo $plugin | tr '[:lower:]-' '[:upper:]_')
	eval export QRM_${PLUGIN}_BASE_DIR=\${QRM_${PLUGIN}_BASE_DIR:-${QRM_SERVER_BASE_DIR}/qrm/plugins/${plugin}\}
	eval export QRM_PLUGIN_BASE_DIR=\$QRM_${PLUGIN}_BASE_DIR
	local plugin_functions=${QRM_PLUGIN_BASE_DIR}/include/${plugin}-functions

	if . ${plugin_functions}; then
		local prefix=$(echo ${plugin} | tr '-' '_')
		${prefix}_${command} "$@"
		local rc=$?
		case ${command} in 
			install)
				[ "$rc" == 0 ] && qrm_plugin_enable ${plugin}
				;;
			uninstall)
				qrm_plugin_disable ${plugin}
				;;
		esac
	fi
	unset QRM_PLUGIN_BASE_DIR
	return $rc
}

function _qrm_plugin_enable() {
	PLUGIN=$1
	FILE=$QRM_SERVER_BASE_DIR/qrm/plugins/$PLUGIN/etc/$PLUGIN.ini
	SECTION=Plugin
	KEY=enabled
	VALUE=$2
#	if [ ! -f $FILE ]; then
#		{ mkdir -p $(dirname $FILE) && echo "[$SECTION]" > $FILE ; } || return 1
#	fi
	qrm_set_ini_value $FILE $SECTION $KEY $VALUE
}

function qrm_plugin_enable() {
	_qrm_plugin_enable $1 true
}
function qrm_plugin_disable() {
	_qrm_plugin_enable $1 false
}

function qrm_create_plugin_template() {
	local plugins_base=$1
	echo -n "Please enter the name of the plugin: "
	while [ "$plugin_name" == "" ]; do
		read plugin_name
	done
	local fixed_name=`echo $plugin_name | tr '-' '_'`
	local plugin_dir=${plugins_base}/${plugin_name}
	if [ -e $plugin_dir ]; then
		echo "$plugin_dir already exists" > /dev/stderr
		exit 1;
	fi

	local ini_file=${plugins_base}/${plugin_name}/etc/${plugin_name}.ini
	mkdir -p $(dirname ${ini_file})
	cat > ${ini_file} <<EOF
[Plugin]
name=
version=
description=
minimum_qrm_version=
supported_platforms=<comma_delimited_list of \`uname -m\`, or "all">
required_plugins=<comma delimited list of plugins that should be enabled for
                           this plugin to work>
copyright=
maintainer_url=
EOF

	local manage_file=${plugins_base}/${plugin_name}/include/${plugin_name}-functions
        mkdir -p $(dirname ${manage_file})
	
	cat > ${manage_file} <<EOF
${dummy}function ${fixed_name}_install() {
	echo "Installing ${plugin_name}"	
}

${dummy}function ${fixed_name}_uninstall() {
	echo "Uninstalling ${plugin_name}"
}

${dummy}function ${fixed_name}_run_once() {
	: # code that will run once by the server
}

${dummy}function ${fixed_name}_start() {
	echo "Starting ${plugin_name}"
}

${dummy}function ${fixed_name}_stop() {
	echo "Stopping ${plugin_name}"
}

EOF



}


IS_REQUIRED="REQUIRED"

function qrm_is_declared() {
	eval test -n \"\${!$1[*]}\"
}

function qrm_to_upper() {
	echo "$1" | tr '[:lower:]' '[:upper:]'
}

function qrm_is_valid_value() {
	local value=$1 && shift
	local values="$@"
	expr match "$value" "$values" > /dev/null 2>&1
}

function qrm_get_param() {
	local plugin=$1 && shift
	local param=$1 && shift
	local default="$1" && shift
	local description="$1" && shift
	local values="$1" && shift
	local values_str="$1" && shift	

	plugin=$(echo $plugin | tr '-' '_')
	local variable=$(qrm_to_upper "QRM_${plugin}_${param}")
	if qrm_is_declared $variable; then
		local value="$(eval echo \$$variable)"
		if ! qrm_is_valid_value "$value" "${values[@]}"; then	
			echo ERROR: "$value is not valid" 1>&2
			return 2;
		fi
		return 0
	fi

	local interactive="$QRM_IS_INTERACTIVE$(qrm_to_upper QRM_$plugin_INTERACTIVE)"
	local required=$(test "$default" == "$IS_REQUIRED" && echo true)
	if [ -n "$interactive" ]; then 
		if [ -n "$values_str" ]; then
			local list="(${values_str})"
		else
			local list=${values:+"($values)"}
		fi
		
		unset IFS
		local def=${default:+"[$default]"}
		echo -n "Please enter a value for the ${description} $list $def: "
		unset IFS
		while :; do
			{ ! read $variable && [ -z "$required" ]; } && break; 

			local value="$(eval echo \$$variable)"
			
			if [[ -z "$value" && -z "$required" ]]; then
				eval $variable=\"$default\"
				break;
			fi
			qrm_is_valid_value "$value" "${values[@]}" && break;	
			eval unset $variable
			echo -n "Please enter a valid value: "
		done
		
	else
		if [ -n "$required" ]; then
			echo "ERROR: $param is not defined in .ini or environment" 1>&2
			return 1		
		fi

	fi
	
}

