#! /bin/bash

# Use of bash is required because "upload_dir" is recursive and
# thus needs local variables.

set -eu

usage()
{
	printf "$0  <srcdir> <dstdir> <url>\n"
}

escape_url()
{
	perl -MURI::Escape -e \
		'print uri_escape shift, , q{^A-Za-z0-9\-._~/:}' -- "$1"
}

if [ $# != 3 ]
then
	usage >&2
	exit 1
fi

src="$1"
dir="$2"
url="$3"

echo Username: >&2
IFS= read -r user

if printf '%s' "$user" | grep -qe '[[:space:]]'
then
	echo Username cannot contain whitespaces >&2
	exit 1
fi

ttycfg=$(stty -g)
trap "stty $ttycfg" INT QUIT TERM EXIT
stty -echo
echo Password: >&2
IFS= read -r pwd
stty echo
# Force newline
echo

cookie="$(mktemp)"

cleanup()
{
    rm -f $cookie
}

slcl_mkdir()
{
	if ! curl --head \
			-f \
			--no-progress-meter \
			-s \
			-b "$cookie" \
			-o /dev/null \
			"$(escape_url "$url/user$2/$1/")"
	then
		curl -X POST \
			-f \
			-b "$cookie" \
			--data-urlencode "name=$1" --data-urlencode "dir=$2/" \
			"$url/mkdir"
	fi
}

trap cleanup EXIT

curl -X POST \
	-f \
	-c "$cookie" \
	--data-urlencode "username=$user" --data-urlencode "password=$pwd" \
	"$url/login"

level=0

upload_dir()
{
	local src="$1"
	local dir="$2"
	local n=$(cd "$1" && ls -A | wc -l)
	local i=1

	test $n -eq 0 && return

	level=$(($level + 1))

	while read f
	do
		for l in $(seq $level)
		do
			printf "-"
		done

		printf " [%d/%d] %s -> %s " "$i" "$n" "$f" "$dir$src/"

		if test -d "$src/$f"
		then
			printf "[entering directory]\n"
			slcl_mkdir "$f" "$dir$src"
			upload_dir "$src/$f" "$dir"
		elif ! test -f "$src/$f"
		then
			printf "[not a file]\n"
		elif curl --head \
			-f \
			--no-progress-meter \
			-s \
			-b "$cookie" \
			-o /dev/null \
			"$(escape_url "$url/user$dir$src/$f")"
		then
			printf "[skipping]\n"
		else
			while ! curl -X POST \
				-f \
				-b "$cookie" \
				-F dir="$dir$src/" \
				-F "file=@$src/$f;filename=$(basename -- "$f")" \
				"$(escape_url "$url/upload")"
			do
				printf "[retrying]"
				sleep 5
			done

			printf "[done]\n"
		fi

		i=$(($i + 1))
	done <<-EOF
	$(cd "$1" && ls -A)
	EOF

	level=$(($level - 1))
}

slcl_mkdir "$src" "$dir"
upload_dir "$src" "$dir"
