#! /bin/bash # Use of bash is required because "upload_dir" is recursive and # thus needs local variables. set -eu usage() { printf "$0 \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 \ --fail-with-body \ --no-progress-meter \ -s \ -b "$cookie" \ -o /dev/null \ "$(escape_url "$url/user$2/$1/")" then curl -X POST \ --fail-with-body \ -b "$cookie" \ --data-urlencode "name=$1" --data-urlencode "dir=$2/" \ "$url/mkdir" fi } trap cleanup EXIT curl -X POST \ --fail-with-body \ -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 \ --fail-with-body \ --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 \ --fail-with-body \ -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"