#!/bin/sh

. /usr/share/debconf/confmodule

log() {
	logger -t net-retriever "$@"
}
error() {
	log "error: $@"
	exit 1
}

db_get mirror/protocol
protocol="$RET"
db_get mirror/$protocol/hostname
hostname="$RET"
db_get mirror/$protocol/directory
directory="$RET"
db_get mirror/$protocol/proxy
proxy="$RET"
if [ -n "$proxy" ]; then
	if [ "$protocol" = http ]; then
		export http_proxy="$proxy"
	elif [ "$protocol" = ftp ]; then
		export ftp_proxy="$proxy"
	fi
fi
if db_get apt-setup/security_host; then
	sechostname="$RET"
else
	# TODO: hardcoding, since apt-setup might not be installed yet
	sechostname=security.ubuntu.com
fi
keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg

fetch() {
	url="${protocol}://$1$2/$3"
	iters=0
	while [ $iters -lt 3 ]; do
		if [ ! -e "$4" ]; then
			wget -q "$url" -O "$4"
			return $?
		else
			# busybox wget can sometimes become confused while 
			# resuming, so if it fails, restart
			if wget -c -q "$url" -O "$4"; then
				return 0
			else
				wget -q "$url" -O "$4"
				return $?
			fi
		fi
		iters=$(($iters + 1))
	done
}

checkmatch() {
	release="$1"
	packages="$2"
	pkgmd5="$3"
	pkgsize="$4"

	set -e
	sed -n '/^MD5Sum:$/ b LOOP; b; : PRINT; /:$/q; p; : LOOP; n; b PRINT' \
	       "$release" | (
		while read md5 size file; do
			if [ "$file" = "$packages" ]; then
				if [ "$md5" != "$pkgmd5" ]; then
					error "MD5 mismatch for $packages ($md5 != $pkgmd5)."
				fi
				if [ "$size" != "$pkgsize" ]; then
					error "Size mismatch for $packages ($size != $pkgsize)."
				fi
				return 0
			fi
		done
		error "$packages not found in $release."
	)
	set +e
}

read_gpg_status() {
	while read prefix keyword rest; do
		[ "$prefix" = '[GNUPG:]' ] || continue
		if [ "$keyword" = VALIDSIG ]; then
			exit 0
		fi
	done
	exit 1
}

cmd="$1"
shift

case "x$cmd" in
	xretrieve)
		fetch "$hostname" "$directory" "$@"
		exit $?
	;;

	xpackages)
		rm -f "$1"
		touch "$1"

		# Setting codename to a suite is not very nice, but can do no harm
		if ! db_get mirror/udeb/suite || [ -z "$RET" ]; then
			db_get mirror/codename
		fi
		codename="$RET"

		# TODO: Ubuntu-specific hack to fetch -updates and
		# -security; is there any way to make this more generic?
		for codename_extra in "$codename" "$codename-updates" "$codename-security"; do
			if [ "$codename_extra" = "$codename-security" ]; then
				thishost="$sechostname"
				thisdir=/ubuntu
			else
				thishost="$hostname"
				thisdir="$directory"
			fi
			if $0 packages_one "$thishost" "$thisdir" "$1" "$codename_extra"; then
				:
			else
				ret=$?
				if [ "$codename_extra" = "$codename" ]; then
					exit $ret
				else
					# ignore errors from secondary suites
					continue
				fi
			fi
		done
		exit 0
	;;

	xpackages_one)
		codename="$4"
		Release="/tmp/net-retriever-$$-Release"
		fetch "$1" "$2" "dists/$codename/Release" "$Release" || exit $?
		# If gpgv and a keyring are installed, authentication is
		# mandatory.
		if type gpgv >/dev/null && [ -f "$keyring" ]; then
			if ! fetch "$1" "$2" "dists/$codename/Release.gpg" "$Release.gpg"; then
				error "dists/$codename/Release is unsigned."
			fi
			if ! log-output -t net-retriever --pass-stdout \
			     gpgv --status-fd 1 --keyring "$keyring" \
			     --ignore-time-conflict \
			     "$Release.gpg" "$Release" | read_gpg_status; then
				error "Bad signature on $Release."
			fi
		fi

		ARCH=`udpkg --print-architecture`
		components="`grep ^Components: $Release | cut -d' ' -f2-`"
		ret=1
		if [ -z "$components" ]; then
			error "No components listed in $Release."
		fi
		for comp in $components; do
			# TODO: Ubuntu-specific hack to avoid pulling in
			# udebs from unsupported components; is there any
			# way to make this more generic?
			if [ "$comp" != main ] && [ "$comp" != restricted ]; then
				continue
			fi
			for ext in '.gz' ''; do
				pkgfile="$comp/debian-installer/binary-$ARCH/Packages$ext"
				line=`grep $pkgfile\$ $Release 2>/dev/null`
				if [ $? != 0 ]; then
					continue
				fi
				Packages="/tmp/net-retriever-$$-Packages"
				rm -f "$Packages"
				fetch "$1" "$2" "dists/$codename/$pkgfile" "$Packages" || continue
				checkmatch "$Release" "$pkgfile" \
					"$(md5sum "$Packages" | cut -d' ' -f1)" \
					"$(wc -c < "$Packages" | tr -d ' ')"
				if [ "$ext" = '' ]; then
					cat "$Packages" >> "$3"
				elif [ "$ext" = .gz ]; then
					zcat "$Packages" >> "$3"
				fi
				ret=0
				break
			done
		done
		exit $ret
	;;

	xerror)
		T="retriever/net/error"
		db_set "$T" "Retry"
		db_input critical "$T" || true

		if ! db_go; then
			exit 2
		fi
		db_get "$T"
		if [ "$RET" = "Retry" ]; then
			exit 0
		elif [ "$RET" = "Change mirror" ]; then
			choose-mirror || true
			exit 0
		elif [ "$RET" = Cancel ]; then
			exit 2
		fi
	;;

	*)
		# unknown command
		 exit 1
esac
