#!/bin/sh
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Etersoft, Vitaly Lipatov <lav@etersoft.ru>
# Redistribution of this file is permitted under the terms of the
# Lesser GNU Public License (LGPL)

WINECONFDIR=/etc/wine
SYSCONFDIR=/etc/sysconfig
WINEDATADIR=/usr/share/wine
STATEDIR=/var/lib/wine
# used only on Gentoo
exec_prefix=@exec_prefix@
BINDIR=/usr/bin
# Forbid Windows application to see in TMPDIR (f.i. MySQL embedded)
unset TMPDIR

# Use ~/.wine by default
[ -z "$WINEPREFIX" ] && export WINEPREFIX=${HOME}/.wine

WINEADMGRP=wineadmin
export WINESPLASHPROGRESS=$WINEPREFIX/winesplash.progress
WINEDIAG=$BINDIR/winediag
ETERMSG=$BINDIR/eterx11msg
WINESERVER=wineserver

# Use /etc/wine/config for set UMASK or ATTACH_MODE
test -f $WINECONFDIR/config && . $WINECONFDIR/config
test -f ${HOME}/.config/wine && . ${HOME}/.config/wine
test -f $WINEPREFIX/config && . $WINEPREFIX/config

[ -z "$WINELOADER" ] && export WINELOADER=$BINDIR/wine-glibc

saved_WINEDLLOVERRIDES="$WINEDLLOVERRIDES"
unset WINEDLLOVERRIDES

# missed on FreeBSD
[ -z "$UID" ] && export UID=`id -u`

test -n "$UMASK" && umask $UMASK

# install is missed on Solaris
INSTALL=`which ginstall 2>/dev/null`
test -z "$INSTALL" && INSTALL=`which install 2>/dev/null`

stop_splash()
{
	rm -f "$WINESPLASHPROGRESS" 2>/dev/null
}

signal_handler() {
	local rc=$?
	trap - HUP PIPE INT TERM QUIT EXIT
	stop_splash
	exit $rc
}

fatal()
{
	echo "$@" >&2
#	stop_splash (called from signal_handler)
	exit 1
}

check_display()
{
	[ -n "$DISPLAY" ] || fatal "Wine needs be run in X environment with DISPLAY variable"
}

# trap signals to be able to correct exit from script
trap signal_handler HUP PIPE INT TERM QUIT EXIT

check_first_run()
{
	tty -s && return
	check_display
	# FIXME: add real checking if needed
	#check_process wineserver && return
	init_splash gray 10 1
	$WINELOADER wineboot.exe --only-first
	stop_splash
}

# run program with wine
run_wine()
{
	export WINEDLLOVERRIDES="$saved_WINEDLLOVERRIDES"
	# do not check DISPLAY here, console programs can be started without DISPLAY
	if tty -s ; then
		exec $WINELOADER "$@"
	else
		echo "$0: Running without console, disable input" >&2
		if false && [ -z "$WINELOGFILO" ] ; then
			exec $WINELOADER "$@" </dev/null >>$WINEPREFIX/wine.log 2>>$WINEPREFIX/wine.log
		else
			exec $WINELOADER "$@" </dev/null
		fi
	fi
	fatal "It is impossible to be here, after exec"
}

# color, overall_time, numstep
init_splash()
{
	[ -z "$WINEDISABLEETERSPLASH" ] || return
	i_progress=0
	echo $i_progress >$WINESPLASHPROGRESS
	local SPLASHFILE=$WINEDATADIR/wine-etersoft-splash.xpm
	[ -r "$SPLASHFILE" ] || SPLASHFILE=$WINEDATADIR/winesplash.xpm
	SPLASH_COLOR=$1
	SPLASH_YPOSITION=
	SPLASH_TIMEOUT=$2
	[ -r "$SPLASHFILE.conf" ] && . $SPLASHFILE.conf
	$BINDIR/winesplash $WINESPLASHPROGRESS $SPLASHFILE $SPLASH_COLOR $SPLASH_TIMEOUT $SPLASH_YPOSITION 2>/dev/null >/dev/null &
	STEPPROGRESS=$3
}

step_progress()
{
	[ -z "$WINEDISABLEETERSPLASH" ] || return
	i_progress=$(($i_progress+$STEPPROGRESS))
	if [ $i_progress -ge 100 ] ; then
		i_progress=99
	fi
	echo $i_progress >$WINESPLASHPROGRESS
}

map_drive()
{
	test -d "${DEV}" || { echo "Dosdevices dir '${DEV}' does not exists" >&2; return 1; }
	test "$3" = "force" || test -e "$1" || { echo "Target '$1' does not exists. Skip '$2' device creating." >&2; return 1; }
	#test -e ${DEV}/$2 && { echo "    SKIP: Device '$2' already mapped as '$(readlink ${DEV}/$2)'"; return 0; }
	test -e ${DEV}/$2 && return 0;
	ln -sf "$1" ${DEV}/$2 && echo "Device '$2' created as link for '$1' target." || echo "Skipped $2"
	return 0
}

remove_printers()
{
	echo "Removing registry entries about printer drivers..."
	$WINELOADER regedit /D "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Print\\Environments\\Windows 4.0\\Drivers"
	$WINELOADER regedit /D "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Print\\Environments\\Windows NT x86\\Drivers"
	$WINELOADER regedit /D "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Print\\Printers"
}

# returns FALSE if var is missed
get_winevar()
{
	WINEENVVAR=`$WINELOADER cmd /C echo "%$1%"`
	echo $WINEENVVAR
	test "%$1%" != "$WINEENVVAR"
}

print_help()
{
	$WINELOADER
	echo "       wine --update                 Update WINE tree (registry and so on)"
	echo "       wine --attach [DIR]           Attach user wine to shared dir"
	echo "       wine --admin [DIR]            Create admin setup in shared dir (only for $WINEADMGRP group)"
	echo "       wine --removeprinters         Remove printer related registry entries"
	echo "       wine --workdir DIR            cd to DIR (in C:\\Program\ Files or /path/to form) before execute command"
}

# update or first run
update_wine()
{
	# Kill all wine processes for any conflicts
	$WINESERVER -k 2>/dev/null
	if [ "$?" = "3" ] ; then
		$ETERMSG -count
		exit 1
	fi

	####### WINE dir preparing ########
	export DEVDIR=${WINEPREFIX}/dosdevices
	mkdir -p ${WINEPREFIX} ${DEVDIR}/unc
	export SYSDRIVE="c:"
	PROFILES=users
	WINTEMP=windows/temp
	INFDIR=windows/inf
	SYSREG=$INFDIR/system.reg
	USERDEFREG=$INFDIR/userdef.reg
	export CROOT=${DEVDIR}/$SYSDRIVE
	export WINEETERSOFTUPDATE=yes

	check_display
	init_splash gray 20 3
	ETERWINEVERSION=$($WINELOADER --version 2>/dev/null | head -n1)
	[ -n "$ETERWINEVERSION" ] || ETERWINEVERSION="WINE@Etersoft 2.0.0-eter1"
	echo "Using WINEPREFIX=$WINEPREFIX with $ETERWINEVERSION"
	$WINELOADER --version 2>/dev/null >>$WINEPREFIX/install.log
	date >>$WINEPREFIX/install.log

	if [ "$ATTACH_MODE" = "yes" ] || [ "$ATTACH_MODE" = "1" ] ; then
		# jump in attach not for --update
		[ "$1" = "--update" ] || WINEMODE="--attach"
	fi

	# get initialize mode from parameter
	if [ "$1" = "--admin" ] || [ "$1" = "--attach" ] ; then
		WINEMODE=$1
		shift
		WINEADMIN=$1
	fi

	if [ -n "$WINEMODE" ] ; then
		[ -z "$WINEADMIN" ] && WINEADMIN=default || shift
	fi

	if [ ! -e $WINEDIAG ] ; then
		fatal "Package wine-etersoft-* is missed"
	fi

	# Tune admin setup
	if [ "$WINEMODE" = "--admin" ]; then
		[ `basename $WINEADMIN` = "$WINEADMIN" ] && WINEADMIN=$STATEDIR/$WINEADMIN
		[ -z "$WINEADMIN" ] && fatal "Use --admin with path to shared C:"

		# create shared dir and set permissions
		mkdir -p $WINEADMIN/$PROFILES $WINEADMIN/$WINTEMP $WINEADMIN/$INFDIR
		chgrp $WINEADMGRP $WINEADMIN 2>/dev/null && chmod 2775 $WINEADMIN || fatal "Shared dir $WINEADMIN cannot be accessed. Check you are in $WINEADMGRP group."
		chmod a+rwxt "$WINEADMIN/$PROFILES/" 2>/dev/null
		# Set tmp permission
		chgrp $WINEADMGRP "$WINEADMIN/$WINTEMP" 2>/dev/null && chmod a+rwxt "$WINEADMIN/$WINTEMP" 2>/dev/null

		# create empty registry files
		echo "WINE REGISTRY Version 2" > "$WINEADMIN/$SYSREG" && chgrp $WINEADMGRP "$WINEADMIN/$SYSREG" 2>/dev/null
		echo "WINE REGISTRY Version 2" > "$WINEADMIN/$USERDEFREG" && chgrp $WINEADMGRP "$WINEADMIN/$USERDEFREG" 2>/dev/null

		# create shared win.ini (see eterbug #4285)
		touch $WINEADMIN/windows/win.ini
		chmod a+rw $WINEADMIN/windows/win.ini
	fi

	# Attach user to the directory
	if [ "$WINEMODE" = "--attach" ]; then
		[ -d $STATEDIR/$WINEADMIN ] && WINEADMIN=$STATEDIR/$WINEADMIN
		[ ! -d /$WINEADMIN ] && fatal "Prepared dir $WINEADMIN is not found"
		[ ! -f $WINEADMIN/$SYSREG ] && fatal "Dir $WINEADMIN is not prepared dir"
	fi

	export WINEMODE
	export WINEADMIN

	# Attach shared dir
	if [ -n "$WINEADMIN" ] ; then
		echo "Using shared WINE tree in $WINEADMIN"
		export DEV=${DEVDIR}
		# Make C: link to shared dir
		map_drive $WINEADMIN $SYSDRIVE
		# attach to shared registry
		ln -sf dosdevices/$SYSDRIVE/$SYSREG "$WINEPREFIX/system.reg"
		ln -sf dosdevices/$SYSDRIVE/$USERDEFREG "$WINEPREFIX/userdef.reg"
	fi

	WINDIR=$CROOT/windows

	if [ ! "$WINEMODE" = "--attach" ] ; then
		# Workaround for dir renaming:
		if test -d "$WINDIR/fonts" && ! test -d "$WINDIR/Fonts" ; then
			mv -f $WINDIR/fonts $WINDIR/Fonts
		fi

		#MS.NET is needed for some damaged program (see eterbug #1530)
		# TODO: use wineprefixcreate
		# Follows for each cycle is copied from wineprefixcreate
		echo "Creating default file tree..."
		for i in \
		    "$WINDIR/command" \
		    "$WINDIR/Fonts" \
		    "$WINDIR/inf" \
		    "$WINDIR/inf/catalog" \
		    "$WINDIR/system32" \
		    "$WINDIR/system32/color" \
		    "$WINDIR/system32/drivers" \
		    "$WINDIR/system32/spool" \
		    "$WINDIR/system32/spool/PRINTERS" \
		    "$WINDIR/system32/spool/drivers" \
		    "$WINDIR/system32/spool/drivers/color" \
		    "$WINDIR/Microsoft.NET/Framework/v1.1.4322" \
		    "$WINDIR/temp"
		do
		    mkdir -p "$i"
		done

		# Make link for compatibility
		[ -e "$CROOT/windows/system" ] || ln -s system32 $CROOT/windows/system
	fi

	# Fix profile permission (only for new Wine bottle instance)
	if [ ! -d $WINDIR/profiles ] ; then
		mkdir -p "${CROOT}/$PROFILES/$USER"
		chmod go-rwx "${CROOT}/$PROFILES/$USER"
	fi

	[ -w $CROOT/$WINTEMP/ ] || fatal "Broken environment. We need writable $CROOT/$WINTEMP/"

	step_progress

	# Copy .reg files to CROOT (if writable)
	if [ -w "$CROOT/$INFDIR/" ] ; then
		# Apply additional reg files from /etc
		find ${WINECONFDIR}/reg.d -maxdepth 1 -name "*.reg" | sort | xargs -r cat > "${CROOT}/$INFDIR/vendor.reg" || fatal "Can't collate registry. Possible xargs is broken."
		find ${WINECONFDIR}/reg.d -maxdepth 1 -name "*.reg.after" | sort | xargs -r cat > "${CROOT}/$INFDIR/vendor_after.reg" || fatal "Can't collate registry (after). Possible xargs is broken."
	fi

find_type()
{
		find ./ -type $1 | sed -e "s|^\./||g"
}

	# Copying from datadir if we have some prepared tree there
	if [ ! "$WINEMODE" = "--attach" ] ; then
		echo "Copying prepared tree from '${WINEDATADIR}/skel-copy' and '${WINEDATADIR}/skel' ..."
		XARGS="xargs -IQQQ"
		echo | $XARGS 2>/dev/null || XARGS="xargs -iQQQ"

		if cd ${WINEDATADIR}/skel-copy 2>/dev/null ; then
			find_type d | $XARGS $INSTALL -m 2775 -d "${CROOT}/QQQ" || fatal "Can't copy libraries. Possible xargs is broken."
			# remove possible targets (for do not use unportable cp --remove-destination)
			find_type f | $XARGS rm -f "${CROOT}/QQQ"
			find_type f | $XARGS cp -f "${WINEDATADIR}/skel-copy/QQQ" "${CROOT}/QQQ" || fatal "Can't copy skel files. Possible xargs is broken."
		fi

		if cd ${WINEDATADIR}/skel 2>/dev/null ; then
			find_type d | $XARGS $INSTALL -m 2775 -d "${CROOT}/QQQ" || fatal "Can't copy libraries. Possible xargs is broken."
			# remove possible targets (for do not use unportable cp --remove-destination)
			find_type f | $XARGS rm -f "${CROOT}/QQQ"
			if [ -n "$WINECOPYSKEL" ] ; then
				find_type f | $XARGS cp -f "${WINEDATADIR}/skel/QQQ" "${CROOT}/QQQ" || fatal "Can't copy skel files. Possible xargs is broken."
			else
				find_type f | $XARGS ln -sf "${WINEDATADIR}/skel/QQQ" "${CROOT}/QQQ" || fatal "Can't symlink skel files. Possible xargs is broken."
			fi
		fi

		cd - >/dev/null
	fi

	if [ ! "$WINEMODE" = "--attach" ] && [ ! -e $CROOT/.windows-serial ] ; then
		# $RANDOM does not work in dash (Ubuntu default shell) so /dev/urandom is used
		# echo is used to remove space at the beginning of od output
		echo $(od -t x4 -A n -N 4 /dev/urandom) > $CROOT/.windows-serial
	fi

	# jump to C: before run internal wine programs
	cd "$CROOT/$WINTEMP"
	step_progress

	$WINELOADER --version >/dev/null || fatal "$WINELOADER is broken on this system. Check for use appropriate OS distribution"

	echo "Run ${WINECONFDIR}/script.d/*.sh.pre scripts..."
	export DEV=${DEVDIR}
	for i in `ls -1 ${WINECONFDIR}/script.d/*.sh.pre 2>/dev/null | sort` ; do
		[ -r $i ] && . $i ${DEVDIR}
	done

	# Create initial registry
	if [ ! -r ${WINEPREFIX}/user.reg ] ; then
		echo "Initialize registry and environments..."
		"${WINELOADER}" wineboot.exe --init 2>>$WINEPREFIX/install.log
	else
		echo "Update registry and environments..."
	fi
	# Force update (--init do not perform registry update)
	"${WINELOADER}" wineboot.exe --update 2>>$WINEPREFIX/install.log

	# load registry files BEFORE script.d executing
	test -r "$CROOT/$INFDIR/vendor.reg" && ${WINELOADER} regedit.exe "$CROOT/$INFDIR/vendor.reg"
	step_progress

	# check for correct environment (see eterbug #1993)
	get_winevar PATH >/dev/null || fatal "System registry is broken: PATH env. variable is not defined"
	get_winevar SYSTEMDRIVE >/dev/null || fatal "System registry is broken: SYSTEMDRIVE env. variable is not defined"

	# check for locking if network version
	WINELOCKTEST=$BINDIR/winelocktest
	if [ ! "$UID" = "0" ] && [ -e $WINELOCKTEST ] && ! "$WINELOCKTEST" >/dev/null ; then
		echo "Check for correct file locking..."
		$WINELOCKTEST
		echo "Error: Lock test is not passed for `pwd`. Wait troubles..."
	fi

	echo "Run ${WINECONFDIR}/script.d/*.sh scripts..."
	export DEV=${DEVDIR}
	for i in `ls -1 ${WINECONFDIR}/script.d/*.sh 2>/dev/null | sort` ; do
		[ -r $i ] && . $i ${DEVDIR}
		step_progress
	done

	# load registry files AFTER script.d executing
	test -r "$CROOT/$INFDIR/vendor_after.reg" && ${WINELOADER} regedit.exe "$CROOT/$INFDIR/vendor_after.reg"

	${WINELOADER} regsvr32.exe >/dev/null 2>>$WINEPREFIX/install.log || fatal "Wine does not run any programs, check your installation or license..."
	# TODO: for better years
	# Tune WINE apps autostart during X login
	# mkdir -p ~/.xsession.d
	# test -f ~/.xsession.d/wineboot || ln -sf $BINDIR/wineboot ~/.xsession.d

	# for usability
	if [ ! -d ${HOME}/wine_c ] && [ ! -f ${HOME}/wine_c ] ; then
		rm -f ${HOME}/wine_c
		ln -s ${CROOT} ${HOME}/wine_c || :
	fi

	# Test for libwine-etersoft installed
	[ -e $WINEDIAG ] && ( echo "Please do not change this file." ; $WINELOADER --version 2>/dev/null ) >${WINEPREFIX}/.etersoft-release

	cd - >/dev/null
	stop_splash
	unset WINEETERSOFTUPDATE
	unset WINEDLLOVERRIDES
	$WINESERVER -k
	echo "Done."
}

if [ "$1" = "--help" ] ; then
	print_help
	exit 0
fi

if [ "$UID" = "0" ] && [ -z "$ONECLICKDESKTOP" ] ; then
	fatal "It is not recommended to run WINE as root"
fi

if [ "$1" = "--update" ]; then
	echo -n "Updating... "
	update_wine $@
	exit 0
fi

if [ -r ${WINEPREFIX}/user.reg ] ; then
    if [ "$1" = "--admin" ] || [ "$1" = "--attach" ] ; then
        fatal "WINE $WINEPREFIX directory is already exists. Move it before attach to shared C drive."
    fi
else
	echo -n "First running... "
	update_wine $@

	echo "`${WINELOADER} --version 2>/dev/null` has been configured for the first time."
	if [ -z "$1" ] || [ "$1" = "--admin" ] || [ "$1" = "--attach" ] ; then
		echo "Use ${HOME}/wine_c as WINE C:\\ disk."
		echo "Copy your program into and install it."
		echo
		exit 0
	fi
fi

# Disable due lazy write to registry files
#SYSREGSIZE=`cat ${WINEPREFIX}/system.reg | wc -c`
#if [ "$SYSREGSIZE" -le 100000 ] ; then
#	echo "ERROR: You have broken system.reg (it has $SYSREGSIZE bytes, fewer than 100000 bytes)" >&2
#	echo "Check your WINE installation or ask your support company" >&2
#	fatal ""
#fi

if [ -e "$WINEDIAG" ] ; then
	# Only if libwine-etersoft present
	$WINEDIAG --lite >/dev/null 2>&1 || echo "Warning: there are some errors in winediag output. Run winediag command and check it." >&2
	if [ ! -f ${WINEPREFIX}/.etersoft-release ] ; then
		echo "ERROR: Your WINE dir ($WINEPREFIX) is obsoleted. It can cause some problems." >&2
		echo "It is recommended to rename (remove) old $WINEPREFIX and set new WINE environment." >&2
		fatal
	else
		# FIXME
		# check for version consistency
		CURLINE=`head -n2 < ${WINEPREFIX}/.etersoft-release | tail -n1`
		NEWLINE=`$WINELOADER --version | head -n1`
		if false && [ "$CURLINE" != "$NEWLINE" ] && [ ! -r ${WINEPREFIX}/.noautoupdate ] ; then
			echo "Run autoupdate due version changed to $NEWLINE"
			update_wine
			remove_printers
		fi
	fi
fi

# If wine without params was called
if [ -z "$1" ] ;  then
	print_help
	exit 0
fi

if [ "$1" = "--version" ] || [ "$1" = "--help" ] ; then
	run_wine "$@"
fi

if [ "$1" = "--removeprinters" ] ; then
	remove_printers
	exit 0
fi

check_first_run

if [ "$1" = "--workdir" ] ; then
	WINEWORKDIRPATH=$($WINELOADER winepath "$2")
	shift 2
fi

if [ -n "$WINEWORKDIRPATH" ] ; then
	cd "$WINEWORKDIRPATH"
fi

STARTCOM=
# if file is exists in Unix or Wine notation
WINEPROGRAMUNIXPATH=$($WINELOADER winepath "$1")
if [ -n "$1" ] && [ -f "$WINEPROGRAMUNIXPATH" ] ; then
	TRNAME="$(echo $1 | tr [a-z] [A-Z])"

	# if file is not executable, run it with start
	TRNAME0=$(basename "$TRNAME" .EXE.SO)
	TRNAME1=$(basename "$TRNAME" .EXE)
	TRNAME2=$(basename "$TRNAME")
	if [ "$TRNAME1" = "$TRNAME2" ] && [ "$TRNAME0" = "$TRNAME2" ] ; then
		STARTCOM="start"
	fi
fi

run_wine $STARTCOM "$@"
