#!/bin/bash
# Build the macOS installer for the token and command line tools.
#
# This is only tested and supported on macOS 10.10 or later, using Xcode 6.0.1.
# Building should also work on older macOS versions with slight changes; YMMV.

# You need to install the following packages from homebrew or macports or fink:
# autoconf automake libtool pkg-config help2man gengetopt

export MACOSX_DEPLOYMENT_TARGET="10.13"
FORCE_OPENSSL_BUILD="1"

set -ex
test -x ./configure || ./bootstrap
BUILDPATH=${PWD}

# keep in sync with MacOSX/notarize
while IFS='=' read -r key value; do
    # Skip empty or comment lines
    [[ -z "$key" || "$key" =~ ^# ]] && continue
    export "$key=$value"
done < $BUILDPATH/VERSION.mk

# keep in sync with MacOSX/notarize
export PACKAGE_VERSION=${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_FIX}
PREFIX=/Library/OpenSC
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig

if test "$FORCE_OPENSSL_BUILD" == "1" || ! pkg-config libcrypto --atleast-version=1.1.1; then
	# OpenSSL is not installed
	if ! test -e $BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig; then
		# Build OpenSSL manually, because Apple's binaries are deprecated
		sh $BUILDPATH/MacOSX/build-openssl-macos.sh -b $BUILDPATH -p $PREFIX
	fi
	PKGPREFIX="PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openssl_bin"
	export OPENSSL_CFLAGS="`env $PKGPREFIX pkg-config --static --cflags libcrypto`"
	export OPENSSL_LIBS="`  env $PKGPREFIX pkg-config --static --libs   libcrypto`"
	export CRYPTO_CFLAGS="$OPENSSL_CFLAGS"
	export CRYPTO_LIBS="$OPENSSL_LIBS"
fi

export CFLAGS="$CFLAGS -arch x86_64 -arch arm64"
export LDFLAGS="$LDFLAGS -arch x86_64 -arch arm64"
export OBJCFLAGS=$CFLAGS

if ! test -e $BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig; then
	if ! test -e openpace; then
		git clone --depth=1 https://github.com/frankmorgner/openpace.git -b 1.1.3
	fi
	cd openpace
	autoreconf -vis
	CFLAGS="${CFLAGS} -DOPENSSL_SUPPRESS_DEPRECATED" ./configure --disable-shared --prefix=$PREFIX HELP2MAN=/usr/bin/true
	touch src/cvc-create.1 src/cvc-print.1
	make DESTDIR=$BUILDPATH/openpace_bin install
	cd ..
fi
PKGPREFIX="PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig:$BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openpace_bin"
export OPENPACE_CFLAGS="`env $PKGPREFIX pkg-config --static --cflags libeac` $OPENSSL_CFLAGS"
export OPENPACE_LIBS="`  env $PKGPREFIX pkg-config --static --libs   libeac` $OPENSSL_LIBS"

if ! test -e ${BUILDPATH}/target/$PREFIX/lib/pkgconfig; then
	./configure --prefix=$PREFIX \
		--sysconfdir=$PREFIX/etc \
		--enable-cvcdir=$PREFIX/etc/cvc \
		--enable-x509dir=$PREFIX/etc/x509 \
		--enable-openssl-secure-malloc=65536 \
		--disable-dependency-tracking \
		--enable-shared \
		--disable-static \
		--enable-strict \
		--disable-assert \
		--enable-sm # TODO: remove this (must be sensible default in master)

	# always make clean
	make clean

	# compile
	make -j 4

	# copy files
	rm -rf ${BUILDPATH}/target
	make install DESTDIR=${BUILDPATH}/target

	# remove garbage
	rm -f ${BUILDPATH}/target/$PREFIX/lib/*.la

	# generate .bundle (required by Adobe Acrobat)
	./MacOSX/libtool-bundle ${BUILDPATH}/target/$PREFIX/lib/opensc-pkcs11.so ${BUILDPATH}/target/$PREFIX/lib
fi


if ! test -e NotificationProxy; then
	git clone https://github.com/frankmorgner/NotificationProxy.git
fi
if test -n "${CODE_SIGN_IDENTITY}" -a -n "${DEVELOPMENT_TEAM}"; then
	xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/OpenSC/ MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \
		CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" OTHER_CODE_SIGN_FLAGS="--timestamp --options=runtime" CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO CODE_SIGN_STYLE=Manual
else
	xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/OpenSC/ MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}
fi
mkdir -p "$BUILDPATH/target/Applications/Utilities"
osacompile -o "$BUILDPATH/target/Applications/Utilities/OpenSC Notify.app" "MacOSX/OpenSC_Notify.applescript"
if test -n "${CODE_SIGN_IDENTITY}"; then
	codesign --force --sign "${CODE_SIGN_IDENTITY}" --entitlements MacOSX/OpenSC_applescripts.entitlements --deep --timestamp --options runtime "$BUILDPATH/target/Applications/Utilities/OpenSC Notify.app"
fi


imagedir=$(mktemp -d)

# Prepare target root
mkdir -p ${BUILDPATH}/target/usr/local/bin
cp MacOSX/opensc-uninstall ${BUILDPATH}/target/usr/local/bin

# Prepare startup root
mkdir -p ${BUILDPATH}/target_startup/Library/LaunchAgents
cp src/tools/org.opensc-project.mac.pkcs11-register.plist ${BUILDPATH}/target_startup/Library/LaunchAgents
cp src/tools/org.opensc-project.mac.opensc-notify.plist   ${BUILDPATH}/target_startup/Library/LaunchAgents

# Build OpenSCToken if possible
if test -e OpenSCToken -a -n "${CODE_SIGN_IDENTITY}" -a -n "${DEVELOPMENT_TEAM}"; then
	cd OpenSCToken
	# make sure OpenSCToken builds with the same dependencies as before
	if ! test -e OpenSC; then
		git clone --depth=1 file://$PWD/../../OpenSC
	else
		cd OpenSC && git pull && cd ..
	fi
	mkdir -p build
	if ! test -e build/openssl; then
		# build/openssl/lib/libcrypto.a is hardcoded in OpenSCToken
		ln -sf $BUILDPATH/openssl_bin/$PREFIX build/openssl
		# in OpenSCToken's variant of OpenSC we still use OpenSSL flags from above
	fi
	if ! test -e build/openpace; then
		# build/openpace/lib/libeac.a is hardcoded in OpenSCToken
		ln -sf $BUILDPATH/openpace_bin/$PREFIX build/openpace
		# in OpenSCToken's variant of OpenSC we still use OpenPACE flags from above
	fi
	BP=${BUILDPATH}
	. ./bootstrap
	BUILDPATH=${BP}
	xcodebuild -target OpenSCTokenApp -configuration Debug -project OpenSCTokenApp.xcodeproj install DSTROOT=${BUILDPATH}/target_token \
		CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" OTHER_CODE_SIGN_FLAGS="--timestamp --options=runtime" CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO CODE_SIGN_STYLE=Manual
	cd ..

	COMPONENT_TOKEN="--component-plist MacOSX/target_token.plist"
else
	# if no OpenSCToken is checked out, then we create a dummy package
	mkdir -p ${BUILDPATH}/target_token
fi

if test -n "${CODE_SIGN_IDENTITY}"; then
	for d in ${BUILDPATH}/target/Library/OpenSC/bin ${BUILDPATH}/target/Library/OpenSC/lib
	do
		# find executable files and run codesign on them
		find ${d} -type f -perm +111 -print -exec \
			codesign --force --sign "${CODE_SIGN_IDENTITY}" --entitlements MacOSX/OpenSC_binaries.entitlements --deep --timestamp --options runtime {} \;
	done
fi


# Build package
pkgbuild --root ${BUILDPATH}/target --component-plist MacOSX/target.plist --scripts MacOSX/scripts --identifier org.opensc-project.mac --version ${PACKAGE_VERSION} --install-location / OpenSC.pkg
pkgbuild --root ${BUILDPATH}/target_token $COMPONENT_TOKEN --identifier org.opensc-project.mac.opensctoken --version ${PACKAGE_VERSION} --install-location / OpenSCToken.pkg
pkgbuild --root ${BUILDPATH}/target_startup --component-plist MacOSX/target_startup.plist --identifier org.opensc-project.startup --version ${PACKAGE_VERSION} --install-location / OpenSC-startup.pkg

# Build product
productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC ${PACKAGE_VERSION}.pkg"

# Sign installer
if test -n "${INSTALLER_SIGN_IDENTITY}"; then
	productsign --sign "${INSTALLER_SIGN_IDENTITY}" "${imagedir}/OpenSC ${PACKAGE_VERSION}.pkg" "${BUILDPATH}/OpenSC ${PACKAGE_VERSION}.pkg"
	mv "${BUILDPATH}/OpenSC ${PACKAGE_VERSION}.pkg" "${imagedir}/OpenSC ${PACKAGE_VERSION}.pkg"
fi

# Build "Uninstaller"
osacompile -o "${imagedir}/OpenSC Uninstaller.app" "MacOSX/OpenSC_Uninstaller.applescript"
if test -n "${CODE_SIGN_IDENTITY}"; then
	codesign --force --sign "${CODE_SIGN_IDENTITY}" --entitlements MacOSX/OpenSC_applescripts.entitlements --deep --timestamp --options runtime "${imagedir}/OpenSC Uninstaller.app"
fi

# Create .dmg
rm -f OpenSC-${PACKAGE_VERSION}.dmg
i=0
while ! hdiutil create -srcfolder "${imagedir}" -volname "${PACKAGE_NAME}" -fs JHFS+ OpenSC-${PACKAGE_VERSION}.dmg
do
	i=$[$i+1]
	if [ $i -gt 2 ]
	then
		exit 1
	fi
done
rm -rf ${imagedir}
