#!/bin/sh
#
#  Copyright (c) 2009-2012 Samuel Lidén Borell <samuel@kodafritt.se>
# 
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#  
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#  
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.
#

prefixSet=""
prefix="/usr/local"
execprefix=""

multiarch="`gcc -print-multiarch 2>/dev/null`"
otherlibdir=""
if ( [ ! -h /usr/lib64 ] && [ -f /usr/lib64/libc.so ] && [ ! -d /usr/lib32 ] ) ||
   ( [ ! -h /lib64 ] && [ -f /lib64/libc.so.6 ] && [ ! -d /usr/lib32 ] ); then
    # RedHat etc.
    multilib="lib64"
elif [ -n "$multiarch" ]; then
    # New Debian with multiarch
    multilib="lib/$multiarch"
    otherlibdir="lib" # for packages that are not yet multiarch
else
    # Old Debian and 32-bit RedHat
    multilib="lib"
fi

libdir=""
libexecdir=""
datadir=""
docdir=""
localedir=""
mandir=""

pluginPathSet=""
if [ -n "$otherlibdir" ]; then
    # check non-multiarch path also
    paths="/usr/$multilib/mozilla/plugins /usr/$otherlibdir/mozilla/plugins"
    pluginPaths=""
    for path in $paths; do
        if [ -d "$path" ]; then
            pluginPaths="$pluginPaths $path"
        fi
    done
    
    if [ -z "$pluginPaths" ]; then
        pluginPaths="/usr/$otherlibdir/mozilla/plugins"
    fi
else
    pluginPaths="/usr/$multilib/mozilla/plugins"
fi

userPluginPath="$HOME/.mozilla/plugins"
userPrefix="$HOME/.local"

enable_pkcs11=""
optional_pkcs11="0"
pkcs11Module="/usr/$multilib/opensc-pkcs11.so"
# check non-multiarch path also
if [ ! -e "$pkcs11Module" -a -n "$otherlibdir" -a -e "/usr/$otherlibdir/opensc-pkcs11.so" ]; then
    pkcs11Module="/usr/$otherlibdir/opensc-pkcs11.so"
fi

gtkversion="auto"

error=""

basedir=`dirname "$0"`

getconfig() {
    printf '#define CALLED_FROM_CONFIGURE\n#include "%s"\n%s\n' "$basedir/common/defines.h" "$1" | cpp - | sed 's/#.*$//g' | tr -d '\n' | sed 's/" "//g' | tr -d '\"'
}

while [ "$#" != "0" ]; do
    flag="$1"
    shift
    case "$flag" in
    --help)
        echo "Usage: $0 [options]

This script creates a build configuration. The default options are to
install system-wide, into $prefix, and use $pluginPaths
as the plugin directory.

Options:

    --help                Shows this help.
    --prefix=PATH         Sets the installation prefix. [$prefix]
    --exec-prefix=PATH    Sets the installation prefix for executable files.
                          The default is to use the same prefix for all files.
    --libdir=PATH         Sets the directory for libraries. [EPREFIX/$multilib]
    --libexecdir=PATH     Sets the directory for internal executables. [LIBDIR]
    --datadir=PATH        Sets the directory for architecture-independent
                          data. [PREFIX/share]
    --docdir=PATH         Sets the directory for documentation and test
                          scripts. [DATADIR/doc]
    --localedir=PATH      Sets the directory for translations [DATADIR/locale]
    --mandir=PATH         Sets the directory for man pages. [DATADIR/man]
    --plugin-path=PATH    Sets the NPAPI plugin path [$pluginPaths]
                          This option may be repeated if you want to create
                          plugin links in several places.
    --pkcs11-module=PATH  Path to PKCS#11 module [$pkcs11Module]
    --disable-pkcs11      Disable building PKCS#11 smartcard support
    --enable-pkcs11       Force building PKCS#11 smartcard support
    --optional-pkcs11     Detect PKCS#11 module availability at runtime
    --with-gtk=VERSION    Selects between GTK version 2 and 3.
    --current-user        Selects a per-user installation. Equivalent to:
                              --prefix=$userPrefix
                              --plugin-path=$userPluginPath
"
        exit 0
        ;;
    --prefix=*)
        prefix=${flag#--prefix=}
        prefixSet=1
        ;;
    --exec-prefix=*)
        execprefix=${flag#--exec-prefix=}
        ;;
    --libdir=*)
        libdir=${flag#--libdir=}
        ;;
    --libexecdir=*)
        libexecdir=${flag#--libexecdir=}
        ;;
    --datadir=*)
        datadir=${flag#--datadir=}
        ;;
    --docdir=*)
        docdir=${flag#--docdir=}
        ;;
    --localedir=*)
        localedir=${flag#--localedir=}
        ;;
    --mandir=*)
        mandir=${flag#--mandir=}
        ;;
    --plugin-path=*)
        path=${flag#--plugin-path=}
        path=${path%/}
        if [ -z "$pluginPathSet" ]; then
            pluginPathSet=1
            pluginPaths="$path"
        else
            pluginPaths="$pluginPaths $path"
        fi
        ;;
    --pkcs11-module=*)
        pkcs11Module=${flag#--pkcs11-module=}
        ;;
    --pkcs11-engine=*)
        # Deprecated alias for --pkcs11-module
        pkcs11Module=${flag#--pkcs11-engine=}
        ;;
    --disable-pkcs11|--enable-pkcs11=no)
        enable_pkcs11="0"
        ;;
    --enable-pkcs11)
        enable_pkcs11="1"
        ;;
    --optional-pkcs11)
        optional_pkcs11="1"
        ;;
    --with-gtk=*)
        gtkversion=${flag#--with-gtk=}
        if [ "x$gtkversion" != xauto -a "x$gtkversion" != x2 -a "x$gtkversion" != x3 ]; then
            echo "Invalid GTK version: $flag. Must be 2, 3 or auto."
            error=1
        fi
        ;;
    --current-user)
        if [ -z "$prefixSet" ]; then
            prefix="$userPrefix"
        fi
        
        if [ -z "$pluginPathSet" ]; then
            pluginPathSet=1
            pluginPaths="$userPluginPath"
        else
            pluginPaths="$pluginPaths $userPluginPath"
        fi
        ;;
    --internal--get-define=*)
        name=${flag#--internal--get-define=}
        [ ! -r "$basedir/common/config.h" ] && exit 1 # Exit if not configured yet
        getconfig "$name"
        exit 0
        ;;
    --internal--get-pc-cflags|--internal--get-pc-libs)
        [ ! -r "$basedir/common/config.h" ] && exit 1
        gtk2libs=$([ "x`getconfig WITH_GTK2`" = "x1" ] && echo "gtk+-2.0 gdk-2.0")
        gtk3libs=$([ "x`getconfig WITH_GTK3`" = "x1" ] && echo "gtk+-3.0")
        pkcs11libs=$([ "x`getconfig ENABLE_PKCS11`" = "x1" ] && echo "libp11")
        if [ "x$flag" = "x--internal--get-pc-cflags" ]; then
            flags="--cflags"
        else
            flags="--libs --cflags"
        fi
        pkg-config $flags glib-2.0 gthread-2.0 libcrypto $gtk2libs $gtk3libs $pkcs11libs
        exit
        ;;
    --internal--list-extra-objects)
        [ ! -r "$basedir/common/config.h" ] && exit 1
        [ "x`getconfig ENABLE_PKCS11`" = "x1" ] && echo "pkcs11.o"
        exit 0
        ;;
    --internal--remove-link)
        link="$1"
        target="$2"
        shift 2
        [ ! -h "$link" ] || [ "`readlink "$link"`" != "$target" ] || rm -f "$link"
        exit 0
        ;;
    # Some tools (e.g. Debian package tools) expect "configure" to be a
    # true autoconf script and implement its options. These options are safely
    # ignored by this build system.
    --disable-dependency-tracking)
        # Dependencies are hard-coded in the Makefile anyway
        ;;
    --disable-maintainer-mode|--enable-maintainer-mode)
        # No files are written to except common/config.h
        ;;
    --bindir=*|--includedir=*|--infodir=*|--localstatedir=*|--oldincludedir=*|--sbindir=*|--sharedstatedir=*|--sysconfdir=*|--htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
        # These are standard GNU directory options. They are not used by FriBID
        ;;
    *)
        echo "Invalid option: $flag"
        error=1
        ;;
    esac
done

if [ ! -r "$basedir/common/defines.h" ]; then
    echo "ERROR: Source code not found." >&2
    error=1
fi

if [ -n "$error" ]; then
    exit 2
fi


### Prefixes
prefixPath="$prefix"

if [ -z "$execprefix" ]; then
    execPath="$prefix"
else
    execPath="$execprefix"
fi

echo
echo "    Prefix:            $prefixPath"
if [ -n "$execprefix" ]; then
    echo "    Executable prefix: $execPath"
fi

### Specific directories
if [ -z "$libdir" ]; then
    libdir="$execPath/$multilib"
fi

if [ -z "$libexecdir" ]; then
    libexecdir="$libdir"
fi

if [ -z "$datadir" ]; then
    datadir="$prefixPath/share"
fi

if [ -z "$docdir" ]; then
    docdir="$datadir/doc"
fi

if [ -z "$localedir" ]; then
    localedir="$datadir/locale"
fi

if [ -z "$mandir" ]; then
    mandir="$datadir/man"
fi


### Plugin paths
hasPaths=""
for path in $pluginPaths; do
    hasPaths="1"
    if [ "$path" = "${path%/plugins}" ]; then
        echo "    WARNING: Plugin path $path doesn't end with /plugins." >&2
    elif [ -d "$path" ]; then
        echo "    Plugin path:       $path"
    else
        echo "    WARNING: Plugin path $path doesn't exist!" >&2
        if [ -z "$pluginPathSet" ]; then
            echo "    You may need to change it with the --plugin-path=... option." >&2
        fi
    fi
done

if [ -z "$hasPaths" ]; then
    echo "    No plugin paths specified."
fi

echo

if [ -z "$enable_pkcs11" ] && pkg-config --exists libp11; then
    enable_pkcs11=1
fi

### Detect GTK version
if [ $gtkversion = auto ]; then
    if pkg-config --exists "gtk+-3.0"; then
        gtkversion=3
    else
        gtkversion=2
    fi
fi

echo "    GTK version:       $gtkversion"
if [ $gtkversion = 2 ]; then
    with_gtk2=1
    with_gtk3=0
else
    with_gtk2=0
    with_gtk3=1
fi
echo

### Check that the PKCS#11 module exists
depError=""
if [ $with_gtk3 = 1 ]; then
    pkgconfigDeps="gtk+-3.0;glib-2.0;libcrypto;x11"
else
    pkgconfigDeps="gtk+-2.0 >= 2.18;gdk-2.0;glib-2.0;libcrypto;x11"
fi
if [ "$enable_pkcs11" = 1 ]; then
    if [ "$optional_pkcs11" = 0 ]; then
        echo "    PKCS#11 smartcard support enabled"
    else
        echo "    PKCS#11 smartcard support enabled (optional mode)"
    fi
    
    pkgconfigDeps="$pkgconfigDeps;libp11"
    echo "    PKCS#11 module:    $pkcs11Module"
    if [ ! -f "$pkcs11Module" ]; then
        # PKCS#11 module not found
        errorType="    WARNING"
        if [ "$optional_pkcs11" = 0 ]; then
            depError=1
            errorType="ERROR"
        fi
        echo >&2
        echo "$errorType: PKCS#11 module not found" >&2
        
        if [ "x${pkcs11Module%opensc-pkcs11.so}" != "x$pkcs11Module" ]; then
            echo "Make sure that you have installed OpenSC!" >&2
        fi
    elif type readelf grep > /dev/null 2> /dev/null && \
	 echo 'A_a' | grep -q 'B_b\|A_a'; then
        # Check that it's actually a PKCS#11 module
        if ! readelf -s "$pkcs11Module" | grep -q 'C_Initialize\|C_GetFunctionList'; then
            echo >&2
            echo "ERROR: $pkcs11Module is not a PKCS#11 module" >&2
            echo "Normally you should use the file opensc-pkcs11.so from OpenSC." >&2
        fi
    fi
else
    echo "    PKCS#11 smartcard support disabled"
fi

### Check dependencies
utilities="make pkg-config msgfmt cc cpp install"
if ! type $utilities > /dev/null 2> /dev/null; then
    echo
    echo "ERROR: Missing commands:" >&2
    for utility in $utilities; do
        if ! type "$utility" > /dev/null 2> /dev/null; then
            case "$utility" in
                msgfmt)
                    echo "  msgfmt  (a part of gettext)" >&2;;
                cc)
                    echo "  cc      (C compiler)" >&2;;
                cpp)
                    echo "  cpp     (C preprocessor)" >&2;;
                install)
                    echo "  install (under Linux it's included in coreutils)" >&2;;
                *)
                    echo "  $utility" >&2
            esac
            depError=1
        fi
    done
fi

oldifs=IFS
IFS=";"
if ! pkg-config --exists $pkgconfigDeps; then
    echo
    echo "ERROR: Unsatisfied dependencies: " >&2
    for dep in $pkgconfigDeps; do
        pkg-config --exists $dep || {
            case "$dep" in
                libcrypto)
                    echo "  libcrypto (a part of OpenSSL)" >&2;;
                x11)
                    echo "  x11 (X11 library)" >&2;;
                *)
                    echo "  $dep" >&2;;
            esac
        }
    done
    depError=1
fi
IFS=oldifs

if [ -n "$depError" ]; then
    echo
    exit 1
fi

### Write configuration
CONFFILE="$basedir/common/config.h"

cat <<EOT >"$CONFFILE"
/* This file is automatically generated.
   Run the configure script to change the configuration. */

#define CONFIGVERSION 3

#define PREFIX "$prefixPath"
#define EPREFIX "$execPath"

#define LIBDIR     "$libdir"
#define LIBEXECDIR "$libexecdir"
#define DATADIR    "$datadir"
#define DOCDIR     "$docdir"
#define LOCALEDIR  "$localedir"
#define MANDIR     "$mandir"

#define NPAPI_PLUGIN_PATHS "$pluginPaths"

#define DEFAULT_PKCS11_MODULE "$pkcs11Module"

#define ENABLE_PKCS11 ${enable_pkcs11:-0}
#define OPTIONAL_PKCS11 ${optional_pkcs11:-0}
#define WITH_GTK2 ${with_gtk2}
#define WITH_GTK3 ${with_gtk3}
EOT

### Display success message
cancreate() {
    if [ -w "$1" ]; then
        return 0
    elif [ ! -e "$1" ]; then
        cancreate `dirname "$1"`
        return $?
    else
        return 1
    fi
}

if cancreate "$prefixPath" && cancreate "$execPath"; then
    INSTALLCMD="make install"
else
    INSTALLCMD="sudo make install"
fi

echo
echo "Type \"make\" to compile, and then \"$INSTALLCMD\" to install."

