#!/bin/bash -e

# tpkg_proxy 0.1
# written by Sam Watkins, 2009

# Run tpkg_proxy from inetd, e.g. in /etc/inetd.conf:
# 444	stream	tcp	nowait	someuser	/usr/bin/tpkg_proxy	tpkg_proxy

# make sure /etc/hosts.allow contains the line:
# ALL: LOCAL

# You need to mkdir "$work_dir" and touch "$log_file", they should be owned by "someuser"

# tpkg_proxy uses wget, tpkg, rsync, fsh

# method:

# is the package installed?  check -e /var/lib/dpkg/info/FOO.list
# dpkg-repack the package

# subroutine, for a more general upgrade script, tpkg-update
# run tpkg on the package
# connect to the server
# fetch the package file on the server
# run tpkg on the server's package
# use rsync to sync the two tpkgs
# untar the tpkg
# run its tunpkg
# return the deb to apt!

# TODO consider Replaces: dpkg header?
# TODO do we need to support HTTP 1.1 ?

# One problem is that the debian packages are not identical in their packaging,
# although the files should be identical, so there might be problems with
# signatures.

work_dir="/var/lib/tpkg_proxy"
log_file="/var/log/tpkg_proxy"
server="pi.nipl.net"
server_work_dir="$work_dir"
#RSYNC_RSH=fsh
# proxy over ptunnel for reliability :/
retry_max=16
export SSH=`which fsh`
#export RSYNC_RSH="$SSH"
rsync_server="$server"
#rsync_server="localhost"
#export RSYNC_RSH='ssh -p 2222'

if [ ! -w "$log_file" -o ! -d "$work_dir" -o ! -w "$work_dir" ]; then
	echo HTTP/1.0 500 Internal Server Error
	echo Content-Type: text/plain
	echo
	echo "tpkg_proxy's working dir / log file are not writable."
	exit
fi

exec 2>>"$log_file"

error() {
	cat "$errors" >>"$log_file"
	echo >>"$log_file"
	echo HTTP/1.0 500 Internal Server Error
	echo Content-Type: text/plain
	echo
	cat "$errors"
#	rm "$errors"
	exit
}

cd "$work_dir"

read line
req=${line%% *}
line=${line#* }
addy=${line%% *}
proto=${line#* }

perl -ne '/^[\r\n]*$/ && exit'

# work out filename
file="$addy"
test="${file#*://}"
test1="${test%/*}"
if [ "$test" = "$test1" ]; then
	file="$file/"
fi
case "$file" in
*/)
	file="${file}index.html"
	;;
esac

retry() {
	local fails=0
	while true; do
		if "$@"; then
			return $?
		else
			status=$?
			fails=$(($fails+1))
			echo >&2 failed $fails: "$@"
			if [ $fails -ge $retry_max ]; then
				return $status
			fi
		fi
	done
}

update_pkg() {
	deb=`ls -t "$pkg"_*.deb | head -n1`
	if [ -z "$deb" -o ! -e "$deb" ]; then
		sudo dpkg-repack "$pkg" 1>&2 || error
	fi
	deb=`ls -t "$pkg"_*.deb | head -n1`
	fakeroot tpkg "$pkg.tpkg" "$deb" || error
	[ -e "$pkg.tpkg.old" ] || cp -a "$pkg.tpkg" "$pkg.tpkg.old"
#	rm -f "$deb"
	retry sshc "$server:$server_work_dir" wget -q -c "$file" || error
	retry sshc "$server:$server_work_dir" tpkg "$pkg.tpkg" "$base" || error
#	rsync --quiet --archive --compress --partial --inplace "$server:$server_work_dir/$pkg.tpkg" "$pkg.tpkg" || error
	retry rsync --archive --compress --partial --inplace --progress --verbose "$rsync_server:$server_work_dir/$pkg.tpkg" "$pkg.tpkg" 1>&2 || error
#	sshc "$server:$server_work_dir" rm "$base" "$pkg.tpkg" &
	  # XXX or leave it in the cache?
	fakeroot tar xf "$pkg.tpkg" || error
#	rm "$pkg.tpkg" "$pkg.tpkg.old"
	fakeroot ./tunpkg.$pkg.sh || error
}

fetch_new_pkg() {
	# could go via the server and recompress but not really worth it
	wget -q -c "$file" || error
}

get_package() {
	errors=".$pkg.errors.$$"
	exec 2>"$errors"

	if [ -e $base ]; then
		echo >&2 package "$base" is already downloaded
	elif [ -e /var/lib/dpkg/info/$pkg.list ]; then
		update_pkg
	else
		fetch_new_pkg
	fi

	[ -e "$base" ] || error
	size=`stat -c %s "$base"`

	echo "HTTP/1.0 200 OK
Connection: close
Date: `date`
Server: tpkg_proxy
Content-Length: $size
Content-Type: application/x-debian-package
"

	cat < "$base"
	
#	rm "$base"
}

case "$file" in
http://*.deb|ftp://*.deb) # no https at the moment
	dir="`dirname "$file"`"
	base="`basename "$file"`"
	pkg="${base%%_*}"

	lockfile-create "$pkg"
	lockfile-touch "$pkg" &
	BADGER="$!"

	get_package

	kill "${BADGER}"
	lockfile-remove "$pkg"
	;;
*)
	echo HTTP/1.0 403 Forbidden
	echo
	;;
esac

cat "$errors" >>"$log_file"
echo >>"$log_file"
#rm "$errors"

exit
