#!/bin/sh
#
# Configuration script for Services.
#
# IRC Services is copyright (c) 1996-2001 Andrew Church.
#     E-mail: <achurch@achurch.org>
# Parts copyright (c) 1999-2000 Andrew Kempe and others.
# This program is free but copyrighted software; see the file COPYING for
# details.

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

# Nifty handy functions.

echo2 () {
	$ECHO2 "$*$ECHO2SUF"	# these are defined later
}

log () {
	echo >&3 "$MODE: $*"
}

run () {
	echo >&3 "$MODE: >>> $*"
	($*) >&3 2>&3 </dev/null
	xxres=$?
	if [ $xxres -ne 0 ] ; then
		echo >&3 "$MODE: *** Command failed (exit code $xxres)"
	fi
	return $xxres
}

exists () {			# because some shells don't have test -e
	if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then
		return 0
	else
		return 1
	fi
}

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

# Test for the presence of a given include file or function.  If the
# variable TEST is non-empty, it contains code to be placed at the end of
# main(), and should return 0 if everything is okay, else 1.
#
# For includes: Pass the include filename as an argument.  The variable
# HAVE_include_name, where "include_name" is the name of the include file
# with letters uppercased and non-alphanumerics replaced by underscores, is
# set to 1 if the include file is present, else 0.
#
# For functions: Pass the return type, function name, and prototype as
# arguments.  The variable HAVE_function, where "function" is the name
# of the function with letters uppercased, is set to 1 if the function is
# available, else 0.
#
# For both: The result code of the function will be 0 (true) if the entity
# is present, else 1 (false).

test_include () {
	include="$1"
	inc2="`echo $include | sed 'y+abcdefghijklmnopqrstuvwxyz/.-+ABCDEFGHIJKLMNOPQRSTUVWXYZ___+'`"
	if [ -f "/usr/include/$include" ] ; then
		eval "HAVE_${inc2}=1"
		log "found $include in /usr/include"
		return 0
	fi
	cat >tmp/test.c <<EOT
#include <$include>
int main() { return 0; }
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		eval "HAVE_${inc2}=1"
		log "found $include"
		return 0
	else
		eval "HAVE_${inc2}=0"
		log "didn't find $include"
		return 1
	fi
}

test_function () {
	rettype="$1"
	func="$2"
	proto="$3"
	if [ ! "$rettype" -o ! "$func" ] ; then
		log "test_function: missing parameter(s)"
		return 1
	fi
	if [ ! "$proto" ] ; then
		proto="(...)"
	fi
	func2=`echo $func | tr '[a-z]' '[A-Z]'`
	if [ ! "$TEST" ] ; then
		TEST="return 0;"
	fi
	cat >tmp/test.c <<EOT
	int main() {
		extern int $func$proto;
		$TEST
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test && (run tmp/test) 2>&1 ; then
		eval "HAVE_${func2}=1"
		log "found $func"
		return 0
	else
		eval "HAVE_${func2}=0"
		log "didn't find $func"
		return 1
	fi
}

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

# If something happens that really shouldn't:

whoa_there () {
	echo ""
	echo ""
	echo "*** WHOA THERE! ***"
	echo ""
	echo "We suddenly couldn't compile using the C compiler we already tested!"
	echo "The command line we used was:"
	echo "     $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test"
	echo "Please try to fix this; if you can't, mail achurch@achurch.org"
	echo "with information about your system, the output from this script,"
	echo "and the "\`"configure.log' file generated by this script."
	echo ""
	exit 4
}

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

# Create a temporary directory for our use.

if [ -d tmp ] ; then
	rm -rf tmp
fi
if mkdir tmp ; then : ; else
	echo "Failed to create temporary directory!  Exiting."
	exit 2
fi
if chmod u+rwx tmp ; then : ; else
	echo "Cannot write to temporary directory!  Exiting."
	exit 2
fi

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

# Variable initialization.

PROGRAM=services
BINDEST=/usr/local/sbin
DATDEST=/usr/local/lib/services

RUNGROUP=
UMASK=
NETWORK_DOMAIN=
IRCTYPE="no default"
IRCTYPE_DEF=
IRCTYPE_DEF2=
IRCTYPE_DEF3=
ENCRYPTION=
BROKEN_MD5_COMPAT=
STATISTICS=
DUMPCORE=

INSTALL=
CP_ALL=

CC=
CC_FLAGS=bonkle
CC_LFLAGS=bonkle
CC_LIBS=bonkle

TYPE_INT16=
TYPE_INT32=

HAVE_STRINGS_H=
HAVE_SYS_SELECT_H=
HAVE_SYS_SYSPROTO_H=

HAVE_STRERROR=
HAVE_SYS_ERRLIST=0

HAVE_SNPRINTF=
BAD_SNPRINTF=
HAVE_STRTOK=
HAVE_STRICMP=
HAVE_STRCASECMP=
HAVE_STRDUP=
HAVE_STRSPN=
HAVE_STRSIGNAL=
HAVE_GETTIMEOFDAY=
HAVE_SETGRENT=
HAVE_UMASK=
HAVE_FORK=
MISSING=bonkle

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

# How can we echo something without going to the next line?

ECHO2SUF=''
if [ "`echo -n a ; echo -n b`" = "ab" ] ; then
	ECHO2='echo -n'
elif [ "`echo 'a\c' ; echo 'b\c'`" = "ab" ] ; then
	ECHO2='echo' ; ECHO2SUF='\c'
elif [ "`printf 'a' 2>&1 ; printf 'b' 2>&1`" = "ab" ] ; then
	ECHO2='printf "%s"'
else
	# oh well...
	ECHO2='echo'
fi
export ECHO2 ECHO2SUF

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

# Command-line parsing.

IGNORE_CACHE= ; NO_DIR_CHECK= ; USE_LOCAL_FUNCS=
USER_CC= ; USER_CC_FLAGS=bonkle ; USER_CC_LFLAGS=bonkle ; USER_CC_LIBS=
export IGNORE_CACHE NO_DIR_CHECK USE_LOCAL_FUNCS
export USER_CC USER_CC_FLAGS USER_CC_LFLAGS USER_CC_LIBS

while [ $# -gt 0 ] ; do
	if [ "$1" = "-ignore-cache" ] ; then
		IGNORE_CACHE=bonkle
	elif [ "$1" = "-no-dir-check" ] ; then
		NO_DIR_CHECK=bonkle
	elif [ "$1" = "-use-local-funcs" ] ; then
		USE_LOCAL_FUNCS=bonkle
	elif [ "$1" = "-os2" ] ; then
		PROGRAM=services.exe
	elif [ "$1" = "-cc" ] ; then
		shift
		USER_CC=$1
	elif [ "$1" = "-cflags" ] ; then
		shift
		USER_CC_FLAGS=$1
	elif [ "$1" = "-lflags" ] ; then
		shift
		USER_CC_LFLAGS=$1
	elif [ "$1" = "-libs" ] ; then
		shift
		USER_CC_LIBS=$1
	else
		if [ "$1" != "-help" -a "$1" != "-h" -a "$1" != "--help" ]; then
			echo >&2 Unknown option/parameter: "$1"
			exitval=1
		else
			exitval=0
		fi
		cat >&2 <<EOT
Available options:
	-ignore-cache     Don't use cache file if it exists
	-no-dir-check     Don't check for existence of install directories
	-use-local-funcs  Force the use of compatibility functions over system
	                      library functions (for debugging)
	-os2              Indicate that this is an OS/2 system.
	-cc               Specify C compiler to use (overrides cache and check)
	-cflags           Specify compilation flags (defaults: -O2 for gcc,
	                      -O for other compilers; overrides cache/check)
	-lflags           Specify link flags for C compiler (default: none)
	-libs             Specify extra link libraries to use (default: none)
EOT
		exit $exitval
	fi
	shift
done

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

echo ""
echo "Beginning IRC Services configuration."
echo ""

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

# First, test for the presence of a config.cache file.  If found, either
# don't use it (-ignore-cache), or let the user know how to not use it and
# then use it.

if [ -f config.cache -a -r config.cache -a ! "$IGNORE_CACHE" ] ; then
	cat <<EOT
Using defaults from config.cache.  To ignore, either remove config.cache or
give the command-line option "-ignore-cache".

EOT
	. config.cache
	if [ ! "$HAVE_SNPRINTF" \
			-o ! "$BAD_SNPRINTF" \
			-o ! "$HAVE_STRTOK" \
			-o ! "$HAVE_STRICMP" \
			-o ! "$HAVE_STRCASECMP" \
			-o ! "$HAVE_STRDUP" \
			-o ! "$HAVE_STRSPN" \
			-o ! "$HAVE_STRSIGNAL" ] ; then
		MISSING=bonkle
	fi
fi

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

# Ask the user anything we need to know ahead of time.

export ok INPUT

####

ok=0
echo "In what directory do you want the binaries to be installed?"
echo "Press Return for the default, or enter a new value."
while [ $ok -eq 0 ] ; do
	echo2 "[$BINDEST] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$BINDEST
	fi
	if echo "$INPUT" | grep -q \[\'\"\\\] ; then
		echo 'Please use a pathname without the characters: '\'' " \'
	elif [ ! "$NO_DIR_CHECK" -a ! -d "$INPUT" ] ; then
		if exists "$INPUT" ; then
			echo "$INPUT exists, but is not a directory!"
		else
			echo "$INPUT does not exist.  Create it?"
			echo2 "[y] "
			read YN
			if [ "$YN" != "n" ] ; then
				if mkdir -p $INPUT ; then
					ok=1
				fi
			fi
		fi
	elif exists "$INPUT/services.h" ; then
		echo "You cannot use the Services source directory as a target directory."
	else
		ok=1
	fi
done
BINDEST=$INPUT
echo ""

####

ok=0
echo "Where do you want the data files to be installed?"
while [ $ok -eq 0 ] ; do
	echo2 "[$DATDEST] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$DATDEST
	fi
	if echo "$INPUT" | grep -q \[\'\"\\\] ; then
		echo 'Please use a pathname without the characters: '\'' " \'
	elif [ ! "$NO_DIR_CHECK" -a ! -d "$INPUT" ] ; then
		if exists "$INPUT" ; then
			echo "$INPUT exists, but is not a directory!"
		else
			echo "$INPUT does not exist.  Create it?"
			echo2 "[y] "
			read YN
			if [ "$YN" != "n" ] ; then
				if mkdir $INPUT ; then
					ok=1
				fi
			fi
		fi
	elif exists "$INPUT/services.h" ; then
		echo "You cannot use the Services source directory as a target directory."
	else
		ok=1
	fi
done
DATDEST=$INPUT
echo ""

####

ok=0
OLD_RUNGROUP="$RUNGROUP"
if [ "$RUNGROUP" ] ; then
  echo "Which group should all Services data files be owned by?  (If Services"
  echo "should not force files to be owned by a particular group, type "\"none\"
  echo "(without the quotes) and press Return.)"
else
  echo "Which group should all Services data files be owned by?  (If Services"
  echo "should not force files to be owned by a particular group, just press"
  echo "Return.)"
fi
while [ $ok -eq 0 ] ; do
	echo2 "[$RUNGROUP] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	ok=1
	if echo "$INPUT" | grep -q \[\'\"\\\] ; then
		echo 'Please use a group name without the characters: '\'' " \'
		ok=0
	elif [ "$INPUT" ] ; then
		if [ "$INPUT" = "none" ] ; then
			RUNGROUP=""
		else
			RUNGROUP="$INPUT"
		fi
	fi
done
echo ""

####

if [ ! "$UMASK" -o "$RUNGROUP" != "$OLD_RUNGROUP" ] ; then
	if [ "$RUNGROUP" ] ; then
		UMASK=007
	else
		UMASK=077
	fi
fi

ok=0
echo "What should the default umask for data files be (in octal)?"
echo "(077 = only accessible by owner; 007 = accessible by owner and group)"
while [ $ok -eq 0 ] ; do
	echo2 "[$UMASK] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$UMASK
	fi
	if [ `echo "$INPUT" | grep -c '[^0-7]'` -gt 0 ] ; then
		echo "$UMASK is not a valid octal number!"
	else
		if [ "`echo $INPUT | cut -c1`" != "0" ] ; then
			INPUT=0$INPUT
		fi
		ok=1
	fi
done
UMASK=$INPUT
echo ""

####

echo "If all of your servers run under a common domain name, what is that"
echo "domain name?  (For example:  All EsperNet servers have names ending in"
echo \`.esper.net\', so \`esper.net\' "would be entered here.)  If your servers"
echo "do not all share a common domain name, just press Return."
echo2 "[$NETWORK_DOMAIN] "
if read INPUT ; then : ; else echo "" ; exit 1 ; fi
if [ "$INPUT" ] ; then
	NETWORK_DOMAIN=`echo $INPUT`
fi
echo ""

####

# XXX ircu 2.10 commented out because it doesn't seem to work

ok=0
echo "Which of the following is closest to the type of server on your IRC"
echo "network?"
echo "     1) Base irc2 distribution (RFC 1459 compliant)"
echo "     2) irc2 with TS8 protocol"
echo "    11) Undernet 2.9.32 or earlier"
#echo "    12) Undernet 2.10.x (version 9 protocol support required)"
echo "    21) DALnet prior to 4.4.15"
echo "    22) DALnet 4.4.15 or later (Dreamforge)"
echo "    23) Bahamut 1.4.23 or later"
echo "    31) Unreal (EXPERIMENTAL)"
while [ $ok -eq 0 ] ; do
	echo2 "[$IRCTYPE] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$IRCTYPE
	fi
	case $INPUT in
		no\ default)
			echo "You must specify your IRC server type in order for Services to function"
			echo "correctly."
			;;
		1)
			IRCTYPE_DEF="IRC_CLASSIC"
			ok=1
			;;
		2)
			IRCTYPE_DEF="IRC_TS8"
			ok=1
			;;
		11)
			IRCTYPE_DEF="IRC_UNDERNET"
			ok=1
			;;
#		12)
#			IRCTYPE_DEF="IRC_UNDERNET"
#			IRCTYPE_DEF2="IRC_UNDERNET_NEW"
#			ok=1
#			;;
		21)
			IRCTYPE_DEF="IRC_DALNET"
			ok=1
			;;
		22)
			IRCTYPE_DEF="IRC_DALNET"
			IRCTYPE_DEF2="IRC_DAL4_4_15"
			ok=1
			;;
		23)
			IRCTYPE_DEF="IRC_DALNET"
			IRCTYPE_DEF2="IRC_DAL4_4_15"
			IRCTYPE_DEF3="IRC_BAHAMUT"
			ok=1
			;;
		31)
			IRCTYPE_DEF="IRC_DALNET"
			IRCTYPE_DEF2="IRC_DAL4_4_15"
			IRCTYPE_DEF3="IRC_UNREAL"
			ok=1
			;;
		*)
			echo "Please enter a valid option number."
			;;
	esac
done
IRCTYPE=$INPUT
echo ""

####

if [ "$ENCRYPTION" = "ENCRYPT_MD5" ] ; then
	DEF=yes
else
	DEF=no
fi

ok=0
echo "Do you want to use the MD5 message-digest algorithm to encrypt passwords?"
echo "(Selecting "\"yes\"" protects your passwords from being stolen if someone"
echo "gains access to the Services databases, but makes it impossible to recover"
echo "forgotten passwords.)"
echo "WARNING: Once you run Services with encryption enabled you cannot go back!"
while [ $ok -eq 0 ] ; do
	echo2 "[$DEF] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$DEF
	fi
	case $INPUT in
		n*|N*)
			ENCRYPTION=
			ok=1
			;;
		y*|Y*)
			ENCRYPTION=ENCRYPT_MD5
			ok=1
			;;
		*)
			echo 'Please enter "yes" or "no".'
			;;
	esac
done
echo ""

####

if [ "$ENCRYPTION" = ENCRYPT_MD5 ] ; then
	if [ "$BROKEN_MD5_COMPAT" = 0 ] ; then
		DEF=no
	else
		DEF=yes
	fi
	ok=0
	cat <<EOT
Do you want to support MD5-encrypted passwords from Services 4.4.x and
earlier?  These versions had a bug which caused the encrypted passwords
to be wrongly generated.  Saying "no" here will cause passwords from
those versions to become unreadable; however, saying "yes" may reduce
the security of your passwords.
EOT
	while [ $ok -eq 0 ] ; do
		echo2 "[$DEF] "
		if read INPUT ; then : ; else echo "" ; exit 1 ; fi
		if [ ! "$INPUT" ] ; then
			INPUT=$DEF
		fi
		case $INPUT in
			y*|Y*)
				BROKEN_MD5_COMPAT=1
				ok=1
				;;
			n*|N*)
				BROKEN_MD5_COMPAT=0
				ok=1
				;;
			*)
				echo 'Please enter "yes" or "no".'
				;;
		esac
	done
	echo ""
else
	BROKEN_MD5_COMPAT=0
fi # ENCRYPT_MD5

####

if [ "$STATISTICS" = 1 ] ; then
	DEF=yes
else
	DEF=no
fi

ok=0
echo "Do you want IRC Services to maintain detailed statistics about the"
echo "network, its users and its servers? Enabling this option on large"
echo "networks may decrease the performance of IRC Services."
echo "NOTICE: this should be considered an EXPERIMENTAL feature."
while [ $ok -eq 0 ] ; do
	echo2 "[$DEF] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$DEF
	fi
	case $INPUT in
		n*|N*)
			STATISTICS=0
			ok=1
			;;
		y*|Y*)
			STATISTICS=1
			ok=1
			;;
		*)
			echo 'Please enter "yes" or "no".'
			;;
	esac
done
echo ""

####

if [ "$DUMPCORE" = 1 ] ; then
	DEF=yes
else
	DEF=no
fi

ok=0
echo "Do you want IRC Services to generate a core file if a segmentation fault"
echo "occurs? Core files are extremely useful when submitting bug reports as"
echo "they show which line of code caused Services to crash. However, it is"
echo "recommended that you only enable this option if you are experiencing"
echo "problems with Services and are attempting to debug the problem."
while [ $ok -eq 0 ] ; do
	echo2 "[$DEF] "
	if read INPUT ; then : ; else echo "" ; exit 1 ; fi
	if [ ! "$INPUT" ] ; then
		INPUT=$DEF
	fi
	case $INPUT in
		n*|N*)
			DUMPCORE=0
			ok=1
			;;
		y*|Y*)
			DUMPCORE=1
			ok=1
			;;
		*)
			echo 'Please enter "yes" or "no".'
			;;
	esac
done
echo ""

####

echo "End of interactive configuration."
echo ""

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

# Set up log file for automated tests, so we have a clue what's going on if
# something dies.

exec 3>configure.log

MODE="                "
TEST=""
export MODE TEST

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

# Search for a compiler.

MODE="find_cc         "
echo2 "Searching for a suitable compiler... "
if [ "$USER_CC" ] ; then
	CC="$USER_CC"
	echo "(supplied) using $CC."
	log user supplied \`"$USER_CC'"
elif [ "$CC" ] ; then
	echo "(cached) using $CC."
	log cache supplied \`"$CC'"
elif run gcc --version ; then
	echo "great, found gcc!"
	CC=gcc
	DEF_CC_FLAGS=-O2
	log using \`gcc\'
else
	echo "gcc not found."
	echo2 "    Looking for alternatives... "
	echo >tmp/test.c "int main(){return 1;}"
	if run cc tmp/test.c -o tmp/test ; then
		CC=cc
	elif run c89 tmp/test.c -o tmp/test ; then
		CC=c89
	else
		echo "no C compiler found!"
		echo "    Use the -cc command line option to specify your C compiler."
		log "automatic tests failed"
		exit 2
	fi
	# See if it handles ANSI.
	cat >tmp/test.c <<EOT
	int main(int argc, char **argv) {
		extern void foo(int bar);
	}
EOT
	log "test for ANSI..."
	if run $CC tmp/test.c -o tmp/test ; then
		echo "using $CC."
		log using \`"$CC'"
	else
		echo "found $CC, but it's not ANSI-compliant!"
		echo "    Use the -cc command line option to specify your C compiler."
		log \`"$CC' not ANSI-compliant"
		exit 2
	fi
	DEF_CC_FLAGS=-O
fi


# Test compiler options.

MODE="find_ccopts     "
if [ "$USER_CC_FLAGS" != bonkle ] ; then
	CC_FLAGS="$USER_CC_FLAGS"
	echo "Compiler flags supplied: $CC_FLAGS"
	log user supplied flags: \`"$CC_FLAGS'"
elif [ "$CC_FLAGS" != bonkle ] ; then
	echo "Compiler flags: (cached) $CC_FLAGS"
	log cache supplied flags: \`"$CC_FLAGS'"
else
	CC_FLAGS=$DEF_CC_FLAGS
	echo2 "Testing default compiler flags ($CC_FLAGS)... "
	cat >tmp/test.c <<EOT
	int main(int argc, char **argv) {
		extern void foo(int bar);
	}
EOT
	if run $CC $CC_FLAGS -c tmp/test.c -o tmp/test.o ; then
		echo "looks good."
	else
		echo "no luck!  Using no flags."
		echo "    If you know what flags you want, use the -cflags option to configure."
		CC_FLAGS=
	fi
	log using flags: \`"$CC_FLAGS'"
fi

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

# Set linker flags.

MODE="find_lflags     "
if [ "$USER_CC_LFLAGS" != "bonkle" ] ; then
	CC_LFLAGS=$USER_CC_LFLAGS
	log user supplied \`"$CC_LFLAGS'"
elif [ "$CC_LFLAGS" != "bonkle" ] ; then
	log cache supplied \`"$CC_LFLAGS'"
else
	log using no flags
	CC_LFLAGS=""
fi

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

# See what libraries we have that we might need.

MODE="find_libs       "
echo2 "Let's see what libraries are lying around... "
if [ "$CC_LIBS" != bonkle ] ; then
	if [ "$CC_LIBS" ] ; then
		echo "(cached) $CC_LIBS"
	else
		echo "(cached) none"
	fi
	log cache supplied \`"$CC_LIBS'"
else
	CC_LIBS=
	if run $CC $CC_FLAGS tmp/test.c -lnsl -o tmp/test ; then
		CC_LIBS="$CC_LIBS -lnsl"
		echo2 "-lnsl "
	fi
	if run $CC $CC_FLAGS tmp/test.c -lsocket -o tmp/test ; then
		CC_LIBS="$CC_LIBS -lsocket"
		echo2 "-lsocket "
	fi
	if run $CC $CC_FLAGS tmp/test.c -lresolv -o tmp/test ; then
		CC_LIBS="$CC_LIBS -lresolv"
		echo2 "-lresolv "
	fi
	if run $CC $CC_FLAGS tmp/test.c -lbsd -o tmp/test ; then
		CC_LIBS="$CC_LIBS -lbsd"
		echo2 "-lbsd "
	fi
	echo ""
	CC_LIBS="`echo $CC_LIBS | sed 's/^ +//'`"
fi
if [ "$USER_CC_LIBS" ] ; then
	CC_LIBS="$CC_LIBS $USER_CC_LIBS"
	echo "Additional user-supplied libraries: $USER_CC_LIBS"
	log user added \`"$USER_CC_LIBS'"
fi

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

# See what sizes various types are.

MODE="check_int16     "
echo2 "Looking for a 16-bit integer type... "
if [ "$TYPE_INT16" ] ; then
	echo "(cached) $TYPE_INT16"
	log "cache supplied $TYPE_INT16"
else
	cat >tmp/test.c <<EOT
	int main() {
		int a;
		short b;
		printf("%d %d", sizeof(a), sizeof(b));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		log "test program output (sizeof(int) sizeof(short)): $a"
		if [ ! "$a" ] ; then
			echo "test program failed!  Assuming short."
			log "assuming short"
			TYPE_INT16=short
		else
			size_int=`echo $a | cut -d\  -f1`
			size_short=`echo $a | cut -d\  -f2`
			if [ $size_int = 2 ] ; then
				echo int
				log "int is 16 bits"
				TYPE_INT16=int
			elif [ $size_short = 2 ] ; then
				echo short
				log "short is 16 bits"
				TYPE_INT16=short
			else
				echo "none found?!  Assuming short."
				log "no 16-bit type found, assuming short"
				TYPE_INT16=short
			fi
		fi
	else
		whoa_there
	fi
fi

MODE="check_int32     "
echo2 "Looking for a 32-bit integer type... "
if [ "$TYPE_INT32" ] ; then
	echo "(cached) $TYPE_INT32"
	log "cache supplied $TYPE_INT32"
else
	cat >tmp/test.c <<EOT
	int main() {
		int a;
		long b;
		printf("%d %d", sizeof(a), sizeof(b));
		return 0;
	}
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
		a="`tmp/test`"
		log "test program output (sizeof(int) sizeof(long)): $a"
		if [ ! "$a" ] ; then
			echo "test program failed!  Assuming long."
			log "assuming long"
			TYPE_INT32=long
		else
			size_int=`echo $a | cut -d\  -f1`
			size_long=`echo $a | cut -d\  -f2`
			if [ $size_int = 4 ] ; then
				echo int
				log "int is 32 bits"
				TYPE_INT32=int
			elif [ $size_long = 4 ] ; then
				echo long
				log "long is 32 bits"
				TYPE_INT32=long
			else
				echo "none found?!  Assuming long."
				log "no 32-bit type found, assuming long"
				TYPE_INT32=long
			fi
		fi
	else
		whoa_there
	fi
fi

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

# Look for include files that might or might not be here.
echo "Checking for presence of include files (it's okay if some aren't there):"

MODE="check_strings   "
echo2 "    strings.h... "
if [ "$HAVE_STRINGS_H" ] ; then
	if [ "$HAVE_STRINGS_H" = 1 ] ; then
		echo "(cached) present"
		log "cache says present"
	else
		echo "(cached) not present"
		log "cache says not present"
	fi
else
	if test_include strings.h ; then
		echo "present"
	else
		echo "not present"
	fi
fi

MODE="check_sysselect "
echo2 "    sys/select.h... "
if [ "$HAVE_SYS_SELECT_H" ] ; then
	if [ "$HAVE_SYS_SELECT_H" = 1 ] ; then
		echo "(cached) present"
		log "cache says present"
	else
		echo "(cached) not present"
		log "cache says not present"
	fi
else
	if test_include sys/select.h ; then
		echo "present"
	else
		echo "not present"
	fi
fi

MODE="check_sysproto  "
echo2 "    sys/sysproto.h... "
if [ "$HAVE_SYS_SYSPROTO_H" ] ; then
	if [ "$HAVE_SYS_SYSPROTO_H" = 1 ] ; then
		echo "(cached) present"
		log "cache says present"
	else
		echo "(cached) not present"
		log "cache says not present"
	fi
else
	if test_include sys/sysproto.h ; then
		echo "present"
	else
		echo "not present"
	fi
fi

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

# AIX workaround.

MODE="check_aix_intNN "
echo2 "Seeing if your system defines int16/int32... "
res="`run egrep int16\|int32 /usr/include/sys/systypes.h`"
if [ "$res" ] ; then
	echo "found."
	echo "    (This is bad, but we can work around it.)"
	log "int16/int32 types found, enabling workaround"
	INTTYPE_WORKAROUND=1
else
	echo "not found (this is good)."
	log "int16/int32 types not found"
	INTTYPE_WORKAROUND=0
fi

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

# Look for missing/broken built-in routines, and similar compatibility
# stuff.

MODE="check_strerror  "
if [ "$USE_LOCAL_FUNCS" ] ; then
	log "not checking (-use-local-funcs)"
	echo "Not checking for presence of strerror (-use-local-funcs specified)."
	HAVE_STRERROR=0
	HAVE_SYS_ERRLIST=0
else
	echo2 "How to complain when something goes wrong... "
	if [ "$HAVE_STRERROR" ] ; then
		if [ "$HAVE_STRERROR" = 1 ] ; then
			echo "(cached) strerror()."
			log "cache supplied strerror()"
		elif [ "$HAVE_SYS_ERRLIST" = 1 ] ; then
			echo "(cached) sys_errlist."
			log "cache supplied sys_errlist"
		else
			HAVE_SYS_ERRLIST=0	# just in case... you never know.
			echo "(cached) pseudo sys_errlist."
			log "cache supplied pseudo sys_errlist"
		fi
	else
		cat >tmp/test.c <<EOT
		int main() {
			extern void strerror(void);
			strerror();
		}
EOT
		if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
			HAVE_STRERROR=1
			echo "ah, strerror() is here."
			log "using strerror()"
		else
			HAVE_STRERROR=0
			echo "no strerror()."
			cat >tmp/test.c <<EOT
			int main() {
				extern char *sys_errlist[];
				char *s;
				s = sys_errlist[0];
			}
EOT
			log "trying sys_errlist..."
			if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then
				HAVE_SYS_ERRLIST=1
				echo "    But you have sys_errlist, which will do nicely."
				log "using sys_errlist"
			else
				HAVE_SYS_ERRLIST=0
				echo "    You don't have sys_errlist either, so we'll have to make do."
				log "using pseudo sys_errlist"
			fi
		fi
	fi
fi  # -use-local-funcs


MODE="check_compat    "

if [ "$USE_LOCAL_FUNCS" ] ; then
	echo "Enabling compatibility functions: snprintf strtok str[n]icmp strdup str[c]spn strsignal"
	HAVE_SNPRINTF=0
	BAD_SNPRINTF=0
	HAVE_STRTOK=0
	HAVE_STRICMP=0
	HAVE_STRCASECMP=0
	HAVE_STRDUP=0
	HAVE_STRSPN=0
	HAVE_STRSIGNAL=0
fi

echo2 "Looking for other routines we want that you don't have... "

if [ "$MISSING" != bonkle -a ! "$USE_LOCAL_FUNCS" ] ; then
	if [ ! "$MISSING" ] ; then
		echo "(cached) none"
		log "cache supplied: (none)"
	else
		echo "(cached)$MISSING"
		log "cache supplied:$MISSING"
	fi
else

	if [ "$USE_LOCAL_FUNCS" ] ; then

		MISSING=" snprintf strtok str[n]icmp strdup str[c]spn strsignal"

	else

		MISSING=

		MODE="check_snprintf  "
		TEST='char buf[16];
			int res;
			buf[0] = 0;
			res = snprintf(buf, 8, "%d", 123456789);
			if (strcmp(buf, "1234567") != 0) {
				printf("test: snprintf broken (bad result in buffer: wanted 1234567, got \"%s\")\n", buf);
				if (strlen(buf) > 7)
					printf("test: your snprintf does not check buffer size!\n");
				return 1;
			} else if (res != 7) {
				printf("test: snprintf broken (wrong return value: wanted 7, got %d)\n", res);
				return 1;
			} else
				return 0;'
		if test_function int snprintf "(char *, int, const char *, ...)" ; then
			BAD_SNPRINTF=0
		else
			tmp="`tmp/test 2>&1`"
			res="`echo $tmp | cut -d\  -f10 2>&1`"
			if [ "$res" = "-1)" ] ; then
				BAD_SNPRINTF=1
				log "found, but returns -1 if string too long"
			elif [ "$res" = "9)" ] ; then
				BAD_SNPRINTF=2
				log "found, but returns large value if string too long"
			else
				BAD_SNPRINTF=0
				MISSING="$MISSING snprintf"
				echo2 "snprintf "
			fi
		fi

		MODE="check_strtok    "
		TEST='	char buf1[1];
			char buf2[] = "1 2 3";
			char buf3[] = "4 5 6";
			buf1[0] = 0;
			buf3[0] = 0;
			if (strtok(buf1, " ") != (char *)0)
				return 1;
			if (strtok((char *)0, " ") != (char *)0)
				return 2;
			if (strtok(buf2, " ") != buf2)
				return 3;
			if (strtok((char *)0, " ") != buf2+2)
				return 4;
			if (strtok(buf3, " ") != (char *)0)
				return 5;
			if (strtok((char *)0, " ") != (char *)0)
				return 6;
			return 0;'
		if test_function "char *" strtok "(char *, const char *)" ; then : ; else
			MISSING="$MISSING strtok"
			echo2 "strtok "
		fi

		MODE="check_stricmp   "
		TEST='extern int strnicmp(const char *, const char *, int); return stricmp("ABC","abc")==0 && strnicmp("ABC","abd",2)==0 ? 0 : 1;'
		if test_function int stricmp "(const char *, const char *)" ; then
			HAVE_STRCASECMP=0	# doesn't really matter
		else
			TEST='extern int strncasecmp(const char *, const char *, int); return strcasecmp("ABC","abc")==0 && strncasecmp("ABC","abd",2)==0 ? 0 : 1;'
			if test_function int strcasecmp "(const char *, const char *)"
			then : ; else
				MISSING="$MISSING str[n]icmp"
				echo2 "str[n]icmp "
			fi
		fi

		MODE="check_strdup    "
		TEST='char *s, *t;
			s = "ABC";
			t = strdup(s);'"
			return (t != (char *)0 && t[0]=='A' && t[1]=='B' && t[2]=='C' && t[3]==0) ? 0 : 1;"
		if test_function "char *" strdup "(const char *)" ; then : ; else
			MISSING="$MISSING strdup"
			echo2 "strdup "
		fi

		MODE="check_strspn    "
		TEST='extern int strcspn(const char *, const char *);
			return (strspn("ABCBA","BA")==2 && strspn("123","123")==3
			     && strcspn("ABCBA","C")==2 && strcspn("123","4")==3) ? 0 : 1;'
		if test_function int strspn "(const char *, const char *)" ; then : ; else
			MISSING="$MISSING str[c]spn"
			echo2 "str[c]spn "
		fi

		MODE="check_strsignal "
		TEST="(void) strsignal(1); return 0;"
		if test_function "char *" strsignal "(int)" ; then : ; else
			MISSING="$MISSING strsignal"
			echo2 "strsignal "
		fi

	fi  # -use-local-funcs

	MODE="check_gettimeofday"
	TEST="char buf[256]; (void) gettimeofday((void *)buf, (void *)buf); return 0;"
	if test_function "char *" gettimeofday "(void *, void *)" ; then : ; else
		MISSING="$MISSING gettimeofday"
		echo2 "gettimeofday "
	fi

	MODE="check_setgrent  "
	TEST="(void) setgrent(); return 0;"
	if test_function int setgrent "(void)" ; then : ; else
		MISSING="$MISSING setgrent"
		echo2 "setgrent "
	fi

	MODE="check_umask     "
	TEST="(void) umask(1); return 0;"
	if test_function int umask "(int)" ; then : ; else
		MISSING="$MISSING umask"
		echo2 "umask "
	fi

	MODE="check_fork      "
	TEST="(void) fork(); return 0;"
	if test_function int fork "(void)" ; then : ; else
		MISSING="$MISSING fork"
		echo2 "fork "
	fi

	MODE="check_gethostbyname"
	TEST='(void) gethostbyname("localhost"); return 0;'
	if test_function "struct hostent *" gethostbyname "(const char *)" ; then : ; else
		MISSING="$MISSING gethostbyname"
		echo2 "gethostbyname "
	fi

	echo ""
fi

if [ $HAVE_GETHOSTBYNAME = 0 ] ; then
	cat <<EOT

*** Notice: Your system does not seem to have the gethostbyname() function.
*** This function is used to translate hostnames into IP addresses.  Since
*** you don't have it (or we can't find it), you will need to use IP
*** addresses instead of hostnames when setting the uplink server address
*** in services.conf.

EOT
fi

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

MODE="check_install   "
echo2 "Checking how to install files... "

if [ "$INSTALL" -a "$OLD_RUNGROUP" = "$RUNGROUP" ] ; then
	if [ "`echo $INSTALL | cut -c1`" = "." ] ; then
		echo '(cached) using our own "install".'
		log "cache says use our own"
	else
		echo '(cached) this system'\''s "install" works.'
		log "cache says use regular "\`"install'"
	fi
else
	cat >tmp/test.c <<EOT
	int main() { return 0; }
EOT
	if run $CC $CC_FLAGS tmp/test.c $CC_LIBS -o tmp/test ; then : ; else
		whoa_there
	fi
	if run cp -p tmp/test tmp/test3 ; then : ; else
		echo ""
		echo ""
		echo "*** WHOA THERE! ***"
		echo ""
		echo "A simple "\`"cp -p' failed!"
		echo "Are you out of disk space?"
		exit 4
	fi

	if run install -m 500 tmp/test tmp/test2 && test -f tmp/test && run cmp tmp/test tmp/test2 ; then
		echo 'looks like "install" will work.'
		if [ "$RUNGROUP" ] ; then
			INSTALL="install -g $RUNGROUP -m 750"
		else
			INSTALL="install -m 700"
		fi
	elif run cp -p tmp/test3 tmp/test ; run install -c -m 500 tmp/test tmp/test2 && test -f tmp/test && run cmp tmp/test tmp/test2 ; then
		echo 'looks like "install -c" will work.'
		if [ "$RUNGROUP" ] ; then
			INSTALL="install -c -g $RUNGROUP -m 750"
		else
			INSTALL="install -c -m 700"
		fi
	elif run cp -p tmp/test3 tmp/test ; run ginstall -m 500 tmp/test tmp/test2 && test -f tmp/test && run cmp tmp/test tmp/test2 ; then
		echo 'looks like "ginstall" will work.'
		if [ "$RUNGROUP" ] ; then
			INSTALL="ginstall -g $RUNGROUP -m 750"
		else
			INSTALL="ginstall -m 700"
		fi
	else
		echo \"install\"" doesn't seem to work."
		echo "    But we can still use cp and friends, so we'll roll our own "\"install\".
		if [ "$RUNGROUP" ] ; then
			INSTALL="./install-script -g $RUNGROUP -m 750"
		else
			INSTALL="./install-script -m 700"
		fi
	fi
	log "using: $INSTALL"
fi

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

MODE="check_copy_recur"
echo2 "Checking how to copy directories... "

if [ "$CP_ALL" ] ; then
	echo "(cached) $CP_ALL"
	log "cache supplied $CP_ALL"
else
	sysname=`/bin/uname -s 2>&1`
	log "sysname: $sysname"
	case $sysname in
		Linux) CP_ALL="/bin/cp -dpr";
		       log "guessing: cp -dpr";;
		*)     CP_ALL="/bin/cp -pr";
		       log "guessing: cp -pr";;
	esac
	if [ ! -f tmp/test2 ] ; then
		run cp tmp/test tmp/test2
	fi
	if run /bin/mkdir tmp/testA && run /bin/mkdir tmp/testB && run /bin/mv tmp/test2 tmp/testA
	then : ; else
		echo ""
		echo ""
		echo "*** WHOA THERE! ***"
		echo ""
		echo "A few simple mkdir's and mv's failed!"
		echo "Are you out of disk space?"
		exit 4
	fi
	if run $CP_ALL tmp/testA/* tmp/testB && run cmp tmp/testA/test2 tmp/testB/test2 ; then
		echo "$CP_ALL"
		log \`"$CP_ALL' works"
	else
		log \`"$CP_ALL' doesn't work"
		run /bin/rm -rf tmp/testB/*
		if run sh -c '/bin/tar -Ccf tmp/testA - . | /bin/tar -Cxf tmp/testB -' ; then
			echo "tar (yuck)"
			CP_ALL="./cp-recursive -t"
			log "using tar"
		else
			log "tar failed(!)"
			echo ""
			echo "    Neither cp nor tar work!  I give up."
			exit 2
		fi
	fi
fi

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

# Create files.

echo2 "Creating sysconf.h... "
cat >sysconf.h <<EOT
/*
 * This file is generated automatically by "configure".  Any changes made
 * to it will be erased next time "configure" is run.
 */

#define SERVICES_BIN		"$BINDEST/services"
#define SERVICES_DIR		"$DATDEST"
EOT
if [ "$RUNGROUP" ] ; then cat >>sysconf.h <<EOT
#define RUNGROUP		"$RUNGROUP"
EOT
fi
cat >>sysconf.h <<EOT
#define DEFUMASK		$UMASK
EOT
if [ "$NETWORK_DOMAIN" ] ; then cat >>sysconf.h <<EOT
#define NETWORK_DOMAIN		"$NETWORK_DOMAIN"
EOT
fi
cat >>sysconf.h <<EOT
#define $IRCTYPE_DEF
EOT
if [ "$IRCTYPE_DEF2" ] ; then cat >>sysconf.h <<EOT ; fi
#define $IRCTYPE_DEF2
EOT
if [ "$IRCTYPE_DEF3" ] ; then cat >>sysconf.h <<EOT ; fi
#define $IRCTYPE_DEF3
EOT
if [ "$DUMPCORE" = 1 ] ; then cat >>sysconf.h <<EOT ; fi
#define DUMPCORE
EOT
if [ "$STATISTICS" = 1 ] ; then cat >>sysconf.h <<EOT ; fi
#define STATISTICS
EOT
if [ "$ENCRYPTION" ] ; then cat >>sysconf.h <<EOT ; fi
#define USE_ENCRYPTION
#define $ENCRYPTION
EOT
if [ "$BROKEN_MD5_COMPAT" = 1 ] ; then cat >>sysconf.h <<EOT ; fi
#define BROKEN_MD5_COMPAT
EOT

cat >>sysconf.h <<EOT

typedef   signed $TYPE_INT16  int16;
typedef unsigned $TYPE_INT16 uint16;
typedef   signed $TYPE_INT32  int32;
typedef unsigned $TYPE_INT32 uint32;

#define HAVE_STRINGS_H		$HAVE_STRINGS_H
#define HAVE_SYS_SELECT_H	$HAVE_SYS_SELECT_H
#define HAVE_SYS_SYSPROTO_H	$HAVE_SYS_SYSPROTO_H

#define HAVE_STRERROR		$HAVE_STRERROR
#define HAVE_SYS_ERRLIST	$HAVE_SYS_ERRLIST
#define HAVE_SNPRINTF		$HAVE_SNPRINTF
#define BAD_SNPRINTF		$BAD_SNPRINTF
#define HAVE_STRTOK		$HAVE_STRTOK
#define HAVE_STRICMP		$HAVE_STRICMP
#define HAVE_STRCASECMP		$HAVE_STRCASECMP
#define HAVE_STRDUP		$HAVE_STRDUP
#define HAVE_STRSPN		$HAVE_STRSPN
#define HAVE_STRSIGNAL		$HAVE_STRSIGNAL
#define HAVE_GETTIMEOFDAY	$HAVE_GETTIMEOFDAY
#define HAVE_SETGRENT		$HAVE_SETGRENT
#define HAVE_UMASK		$HAVE_UMASK
#define HAVE_FORK		$HAVE_FORK
#define HAVE_GETHOSTBYNAME	$HAVE_GETHOSTBYNAME
EOT
echo "done."

echo2 "Creating Makefile.inc... "
cat >Makefile.inc <<EOT
# This file is generated automatically by "configure".  Any changes made
# to it will be erased next time "configure" is run.

CC=$CC
BASE_CFLAGS=$CC_FLAGS
LFLAGS=$CC_LFLAGS
LIBS=$CC_LIBS
EOT
if [ $HAVE_SNPRINTF = 0 -a $BAD_SNPRINTF = 0 ];then cat >>Makefile.inc <<EOT;fi

VSNPRINTF_C=vsnprintf.c
VSNPRINTF_O=vsnprintf.o
EOT
cat >>Makefile.inc <<EOT

PROGRAM=$PROGRAM
BINDEST=$BINDEST
DATDEST=$DATDEST

INSTALL=$INSTALL
CP_ALL=$CP_ALL
RUNGROUP=$RUNGROUP
EOT
echo "done."

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

# Save results in cache for next time around.

echo2 "Saving configuration results in config.cache... "

cat <<EOT >config.cache
PROGRAM="$PROGRAM"
BINDEST="$BINDEST"
DATDEST="$DATDEST"

INSTALL="$INSTALL"
CP_ALL="$CP_ALL"

RUNGROUP="$RUNGROUP"
UMASK=$UMASK
NETWORK_DOMAIN="$NETWORK_DOMAIN"
IRCTYPE=$IRCTYPE
ENCRYPTION="$ENCRYPTION"
BROKEN_MD5_COMPAT=$BROKEN_MD5_COMPAT
STATISTICS=$STATISTICS
DUMPCORE=$DUMPCORE


CC="$CC"
CC_FLAGS="$CC_FLAGS"
CC_LFLAGS="$CC_LFLAGS"
CC_LIBS="$CC_LIBS"

TYPE_INT16=$TYPE_INT16
TYPE_INT32=$TYPE_INT32

HAVE_STRINGS_H=$HAVE_STRINGS_H
HAVE_SYS_SELECT_H=$HAVE_SYS_SELECT_H
HAVE_SYS_SYSPROTO_H=$HAVE_SYS_SYSPROTO_H

HAVE_STRERROR=$HAVE_STRERROR
HAVE_SYS_ERRLIST=$HAVE_SYS_ERRLIST

HAVE_SNPRINTF=$HAVE_SNPRINTF
BAD_SNPRINTF=$BAD_SNPRINTF
HAVE_STRTOK=$HAVE_STRTOK
HAVE_STRICMP=$HAVE_STRICMP
HAVE_STRCASECMP=$HAVE_STRCASECMP
HAVE_STRDUP=$HAVE_STRDUP
HAVE_STRSPN=$HAVE_STRSPN
HAVE_STRSIGNAL=$HAVE_STRSIGNAL
HAVE_GETTIMEOFDAY=$HAVE_GETTIMEOFDAY
HAVE_SETGRENT=$HAVE_SETGRENT
HAVE_UMASK=$HAVE_UMASK
HAVE_FORK=$HAVE_FORK
HAVE_GETHOSTBYNAME=$HAVE_GETHOSTBYNAME
MISSING="$MISSING"
EOT

echo "done."

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

# Delete the temporary directory we created.

rm -rf tmp

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

cat <<EOT
All done!  Now edit config.h to your liking, and run "make" (or possibly
"gmake") to compile Services.  See the README and FAQ if you have any
problems.
EOT
exit 0
