#!/bin/bash
# Etersoft, 2006, 2007, 2008, 2009, 2010
# 2010 (c) Vitaly Lipatov <lav@etersoft.ru>
# Без параметров - список полок
# с названием полки - список бутылок
# с полкой/бутылкой - вход, если есть.

# Переводит пользователя под пользователя wine
# Устанавливает авторизацию для доступа к Иксам
# Настраивает wine на соотв. рабочий каталог
# Использует sudo su - wine и xhost
# TODO: добавить поддержку chroot, внутренних скриптов настройки (монтирования), иксов
# TODO: добавить поиск
# TODO: добавить перемещение

PROGRAM_NAME="Etersoft's racks and bottles handler. (c) 2006-2010"

if [ "$UID" = "0" ]; then
	echo "It is not recommended to run swine as root"
	exit 1
fi

if [ "$LANG" != "ru_RU.UTF-8" ] ; then
	echo "Run me only in  ru_RU.UTF-8 locale"
	exit 1
fi

if [ "$1" = "-l" ] || [ "$1" = "--local" ] ; then
	shift
	LOCALRUN=1
fi

if [ "$1" = "-s" ] || [ "$1" = "--ssh" ] ; then
	shift
	SSHTUNNEL=1
fi

if [ "$1" = "-h" ] || [ "$1" = "--host" ] ; then
	shift
	if [ -z "$1" ] ; then
		echo "Missing host name"
		exit 1
	fi
	CELLARNAME=$1
	shift
fi
test -z "$CELLARNAME" && CELLARNAME=cellar

if [ "$1" = "--internal" ] ; then
	export CELLARNAME=`hostname -s`
else
	# Check for repeatable entry
	if [ -n "$ORIG_USER" ] && [ "$USER" = "wine" ] && [ `hostname -s` = "$CELLARNAME" ] ; then
		echo "You are already in wine '$CELLARNAME' :)"
		exit 1
	fi

	# Заходим локально
	if [ -n "$LOCALRUN" ] ; then
		export CELLARNAME=`hostname -s`
		# TODO: replace with xauth
		# read man xhost
		IP=+$HOSTNAME
		test -z "$IP" && IP=+localhost
		# if DISPLAY is local, allow for local
		echo $DISPLAY | grep -q "^:" && IP=local:
		xhost $IP

		echo "Local bottling to $CELLARNAME (allow X access for $IP)"
		sudo /bin/su - wine -c "CELLARNAME=$CELLARNAME swine --internal $USER --display $DISPLAY $*"
		exit $?
	# Заходим через ssh под wine@
	elif [ "$USER" != "wine" ] || [ `hostname -s` != "$CELLARNAME" ] ; then
		if ! ssh-add -l >/dev/null ; then
			#zenity --title "Запуск SWine" --error --text "У Вас не введён пароль к ключу SSH. Запустите в консоли ssh-add."
			echo "Please, run ssh-add and enter ssh password."
			#exit 1
		fi

		# FIXME: xhost contains some security issues
		#export ORIG_USER=$USER
		if [ -n "$SSHTUNNEL" ] ; then
			OURDISPLAY=NONE
			SSHOPTIONS="-Y -C"
		else
			xhost +$CELLARNAME
			OURDISPLAY=$DISPLAY
			HOSTFROM=${OURDISPLAY/:*/}
			[ -z "$HOSTFROM" ] && OURDISPLAY=`hostname`$OURDISPLAY
		fi
		ssh -t $SSHOPTIONS wine@$CELLARNAME swine --internal $USER --display $OURDISPLAY $@
		exit 0
	fi
fi

##########################################################################################

BOTPATH=~/bottles

# Internal entry on cellar host
if [ "$1" = "--internal" ] ; then
	shift
	export ORIG_USER=$1
	shift
else
	echo "Logical error. Direct run in cellar is unsupported."
	exit 1
fi

if [ "$1" = "--display" ] ; then
	shift
	if [ ! "$1" = "NONE" ] ; then
		export DISPLAY=$1
	fi
	shift
fi

# If DISPLAY is broken
if ! xset -b ; then
	echo "Error: you have no access to your X server from $CELLARNAME. Check with ps -ax | grep X for nolisten tcp. Check local DISPLAY variable."
	echo "You can use swine without direct DISPLAY with --ssh option"
	exit 1
fi

if [ -n "$1" ] ; then
case "$1" in
#	-*)
	--*)
		echo "$PROGRAM_NAME"
		echo "Check http://winehq.org.ru/swine for description in Russian"
		echo "Usage:"
		echo "swine [options] [rackname][/][bottle name]"
		echo "      --remove          remove the bottle"
		#echo "      --search [-s] name     search for bottle"
		echo "      --clone [-o] rackname [privatebottle]       clone the bottle to private bottle"
		#echo "      --move  rack/bottle rack/bottle   move  the bottle to other rack"
		echo "      --private [-p] privatebottle       use private bottle"
		echo "      --local [-l]             use local host instead remote cellar"
		echo "      --recursive [-r]         recursive bottle list"
		echo "      --force                  force login to used bottle"
		echo "      --ssh [-s]               use ssh tunnel instead direct DISPLAY"
		echo "      --create [-c]            create the bottle"
		echo "      --quiet [-q]             make silent output"
		echo " $ swine [rackname] -- lists available racks & bottles"
		exit 0
esac
fi

get_runfile()
{
	echo $HOME/tmp/run-${RACK//\//_}-$BOTTLE
}

get_holder()
{
	#local BOTTLE=$1
	head -n 1 $TPBOTTLE | cut -d " " -f 2
	# TODO: print out name of the person
}

print_comment()
{
	local COMFILE="$1/comment"
	if [ -r "$COMFILE" ] ; then
		head -n1 < "$COMFILE" | cat
	fi
}

# Save comment to
set_comment()
{
	local COMFILE="$1/comment"
	shift
	local COMMENT="$@"
	if [ -n "$COMMENT" ] ; then
		touch "$COMFILE"
		if [ -w "$COMFILE" ] ; then
			echo "Just update comment: '$COMMENT'"
		else
			echo "Error: can't write comment"
			return 1
		fi
		echo "$COMMENT" | cat > "$COMFILE" || return 1
	else
		return 1
	fi
	return 0
}

print_creator()
{
	local COMFILE="$1/creator"
	if [ -r "$COMFILE" ] ; then
		echo -n ", created by "
		head -n1 < "$COMFILE" | cat
	fi
}

set_creator()
{
	local COMFILE="$1/creator"
	shift
	echo "$ORIG_USER" > "$COMFILE" || return 1
	return 0
}

# Print list racks and bottles, call print_list RACK [step N]
print_list()
{
	local LB RACK=$1 RACKCOM BOTCOM STEP=0
	shift
	if [ "$1" = "step" ] ; then
		shift
		STEP=$1
		shift
	else
		if [ -z "$QUIET" ] ; then
			if [ -z "$RACK" ] ; then
				echo "List of available racks on $CELLARNAME:"
			else
				RACKCOM=$(print_comment "$BOTPATH/$RACK")
				[ -n "$RACKCOM" ] && RACKCOM=" ($RACKCOM)"
				echo "List of available bottles in the '$RACK'$RACKCOM rack:"
			fi
		fi
	fi

	# List available racks
	LD=`(cd $BOTPATH ; find $RACK -maxdepth 1 -type d 2>/dev/null | grep -v "^$RACK\$" | grep -v "^\.\$" | grep -v "\.wine" | sort | sed -e "s|^\./||g")`
	for INRA in $LD ; do
		if [ -n "$QUIET" ] ; then
			echo "$INRA"
		else
			RACKCOM=$(print_comment "$BOTPATH/$INRA")
			printf "%-${STEP}s" ""
			printf "  %-30s %s\n" "[R] $(basename $INRA)" "$RACKCOM"
		fi
		if [ -n "$RECURSIVE" ]  ; then
			print_list "$INRA" step $(($STEP + 4))
			[ "$STEP" = "0" ] && [ -z "$QUIET" ] && echo
		fi
	done

	# List available bottles
	LB=`(cd $BOTPATH ; find $RACK -maxdepth 1 -type d -name ".wine-*" 2>/dev/null | grep -v "^$RACK\$" | sort)`
	for FD in $LB ; do
		BOTTLE=$(echo $FD | sed 's|.*\.wine-||g')

		if [ -n "$QUIET" ] ; then
			echo "$RACK/$BOTTLE"
		else
			TPBOTTLE=$(get_runfile)
			PROGNAME="$BOTTLE"
			[ -e "$TPBOTTLE" ] && PROGNAME+="  (USED by $(get_holder))"
			BOTCOM=$(print_comment "$BOTPATH/$RACK/.wine-$BOTTLE")
			BOTCRE=$(print_creator "$BOTPATH/$RACK/.wine-$BOTTLE")
			printf "%-${STEP}s" ""
			printf "  %-$((30 - $STEP))s %s\n" "$PROGNAME" "$BOTCOM$BOTCRE"
		fi
	done

	# Print if the rack is empty
	if [ -z "$LB$LD" ] && [ -n "$RACK" ] && [ -z "$QUIET" ] ; then
		printf "%-${STEP}s" ""
		echo "  empty"
		return
	fi

}

# Check for rack part (check real dir exists too)
get_rack()
{
	local DN=$(dirname "$1")
	if [ -d "$BOTPATH/$1" ] || echo "$1" | grep '.*/$' >/dev/null; then
		echo "$1" | sed 's|/$||g'
		return
	fi
	if [ "$DN" = "." ] ; then
		echo "$1" | sed 's|/.*||g'
	else
		echo "$DN"
	fi
}

# Check for bottle part (check real dir exists too)
get_bottle()
{
	local BN=$(basename "$1")
	if [ -d "$BOTPATH/$1" ] || echo "$1" | grep '.*/$' >/dev/null; then
		echo ""
		return
	fi
	if [ "$BN" = "$1" ] || [ "$BN/" = "$1" ] ; then
		echo ""
	else
		echo "$BN"
	fi
}

# FIXME: do it more correctly
FORCE=
REMOVE=
CREATE=
PRIVATE=
RECURSIVE=
QUIET=

if [ "$1" = "--force" ] ; then
	shift
	FORCE=yes
fi

if [ "$1" = "-c" ] ; then
	shift
	CREATE=yes
fi

if [ "$1" = "-p" ] || [ "$1" = "-private" ] ; then
	shift
	PRIVATE=yes
fi

if [ "$1" = "-q" ] || [ "$1" = "--quiet" ] ; then
	shift
	QUIET=yes
fi

if [ "$1" = "-r" ] || [ "$1" = "--recursive" ] ; then
	shift
	RECURSIVE=yes
fi

# need twice for hack -q -r and -r -q order
if [ "$1" = "-q" ] || [ "$1" = "--quiet" ] ; then
	shift
	QUIET=yes
fi

if [ "$1" = "-o" ] || [ "$1" = "--clone" ] ; then
	shift
	CLONE=yes
fi

if [ "$1" = "--remove" ] ; then
	shift
	REMOVE=yes
fi

COMNAME=$1
shift

if [ "$1" = "-c" ] ; then
	CREATE=yes
	shift
fi

if [ "$1" = "--force" ] ; then
	FORCE=yes
	shift
fi

if [ "$1" = "-p" ] || [ "$1" = "-private" ] ; then
	shift
	PRIVATE=yes
fi

if [ "$1" = "-r" ] || [ "$1" = "--recursive" ] ; then
	shift
	RECURSIVE=yes
fi

if [ "$1" = "-q" ] || [ "$1" = "--quiet" ] ; then
	shift
	QUIET=yes
fi

if [ "$1" = "-o" ] || [ "$1" = "--clone" ] ; then
	shift
	CLONE=yes
fi

if [ "$1" = "--remove" ] ; then
	shift
	REMOVE=yes
fi

# run without args: lists available racks
if [ -z "$COMNAME" ] ; then
	if [ -n "$PRIVATE" ] ; then
		RACK="peoples/$ORIG_USER"
	else
		RACK=""
	fi
	print_list "$RACK"
	exit 0
fi

[ -z "$QUIET" ] || echo "$PROGRAM_NAME"

RACK=$(get_rack "$COMNAME")
BOTTLE=$(get_bottle "$COMNAME")

if [ -n "$PRIVATE" ] ; then
	RACK="peoples/$ORIG_USER"
	BOTTLE="$COMNAME"
fi

##################################################################3
# Run with rack name only
if [ -z "$BOTTLE" ] ; then

	# Create rack if needed
	if [ -n "$CREATE" ] ; then
		if [ -e "$BOTPATH/$RACK" ] ; then
			echo "$BOTPATH/$RACK already exists."
			set_comment "$BOTPATH/$RACK" "$@"
			exit $?
		fi
		echo Create "$BOTPATH/$RACK"
		mkdir -p "$BOTPATH/$RACK" || exit 1
		set_comment "$BOTPATH/$RACK" "$@"
		exit 0
	fi

	# List bottles
	if [ -d "$BOTPATH/$RACK" ] ; then
		print_list "$RACK"
	else
		echo "'$RACK' rack is not exists. You can create it with command 'swine $RACK -c [Rack description]'"
	fi
	exit 0
fi


################################################################
# Run with full path to bottle
export WINEPREFIX="$BOTPATH/$RACK/.wine-$BOTTLE"

TPBOTTLE=$(get_runfile)
COMNAME="$RACK/$BOTTLE"

if [ -n "$CLONE" ] ; then
	if [ -d "$WINEPREFIX" ] ; then
		LOCALBOTTLE="$BOTPATH/peoples/$ORIG_USER"
		echo "Copying `basename $WINEPREFIX` to peoples/$ORIG_USER"
		mkdir -p "$LOCALBOTTLE"
		# -v
		cp -a "$WINEPREFIX" "$LOCALBOTTLE"
	else
		echo "Bottle $BOTTLE is missed"
	fi
	exit 0
fi

if [ -n "$FORCE" ] ; then
	rm -f "$TPBOTTLE"
fi

if [ -f "$TPBOTTLE" ] ; then
	BOTTLEUSER=$(cat "$TPBOTTLE")
	if [ "$BOTTLEUSER" = "$ORIG_USER" ] ; then
		echo "Note: you already entered anywhere"
	else
		echo "Error: $COMNAME bottle is already used by $(get_holder). You can override it with --force key"
		exit 1
	fi
fi

if [ -n "$REMOVE" ] ; then
	chmod u+rwX "$WINEPREFIX" -R
	rm -rf "$WINEPREFIX" || exit 1
	echo "Bottle $RACK/$BOTTLE succesfully removed"
	exit 0
fi

# Set we use this bottle
echo "$ORIG_USER" > "$TPBOTTLE" || exit 1

if [ -d "$WINEPREFIX" ] ; then
	if [ -n "$CREATE" ] ; then
		set_comment "$WINEPREFIX" "$@"
		rm -f "$TPBOTTLE"
		exit 0
	fi
else
	if [ -n "$CREATE" ] ; then
		# initial wine creating
		wine
		set_comment "$WINEPREFIX" "$@"
		set_creator "$WINEPREFIX" "$@"
	else
		echo "Error: '$COMNAME' bottle does NOT exist, run with -c key for create"
		rm -f "$TPBOTTLE"
		exit 1
	fi
fi

echo "Your are on `hostname` host in '$COMNAME' Wine bottle$(print_creator $WINEPREFIX)..."
cd "$WINEPREFIX" && PS1="<wine@$CELLARNAME bottle $COMNAME>\$ " bash
rm -f "$TPBOTTLE"
