#!/bin/bash

if [ -z "${1}" ]; then
  echo "Keine Download-URL angegeben."
  exit 1
fi

# URL zerlegen
#
# Zunchst Protokoll entfernen, wenn vorhanden
Url=${1#ftp://}

# Servernamen und Dateipfad auftrennen
Server=${Url%%/*}
InFile=/${Url#*/}
OutFile=${InFile##*/}

# Benutzernamen und Passwort abtrennen, wenn vorhanden
if [ -z "${Server/*@*}" ]; then
  UserPass=${Server%@*}
  Hostname=${Server##*@}
else
  UserPass=""
  Hostname=${Server}
fi

# Benutzer und Passwort aufteilen
if [ -z "${UserPass/*:*}" ]; then
  User=${UserPass%%:*}
  Pass=${UserPass#*:}
else
  User=${UserPass}
fi

function GetResponseCode
{
  Response="   -"
  while
    read -ru 6 Response && [ "${Response:3:1}" = "-" ];
  do
    # echo ${Response} >&2
    :
  done
  # echo ${Response} >&2
  echo ${Response:0:3}
}

function SetPassive
{
  echo "PASV" >&5
  while
    read -ru 6 Response && [ "${Response:3:1}" = "-" ];
  do
    :
  done

  if [ "${Response:0:3}" = "227" ]; then
    # IP-Adresse und Port stehen in Klammern -- den Rest wegwerfen
    Response=${Response##*\(}
    Response=${Response%%\)*}
    # Die einzelnen Felder von Adresse und Port sind mit Kommas getrennt
    IFS=",{$IFS}"
    set -- $Response
    IP="${1}.${2}.${3}.${4}"
    PortHi=${5}
    PortLo=${6}
    # IP und Port-Nummer auswerten
    echo "${IP} $((${PortHi}*256+${PortLo}))"
  else
    # Fehler, keine passive Verbindung mglich
    echo ""
  fi
}

FifoDir=$(mktemp -d /tmp/${0##*/}-${$}_XXXXXXXX)
mkfifo ${FifoDir}/5 ${FifoDir}/6
exec 5<>${FifoDir}/5
exec 6<>${FifoDir}/6

nc ${Hostname} 21 <&5 >&6 &
ControlPid=$!

# Zunchst Server-Greeting einlesen
if [ "$(GetResponseCode)" != "220" ]; then
  echo "Keine Begrung, kein FTP-Daemon? -- Abbruch."
  exit 1
fi

# Anmelden
echo "USER ${User:-anonymous}" >&5

while true; do
  ResponseCode=$(GetResponseCode)
  if [ "${ResponseCode}" = "331" ]; then
    # Passwort senden
    echo "PASS ${Pass:-nobody@nowhere.net}" >&5
  elif [ "${ResponseCode}" = "230" ]; then
    break
  else
    echo "Login fehlgeschlagen."
    exit 1
  fi
done

# Datenverbindung ffnen
DataCon=$(SetPassive)

nc ${DataCon%% *} ${DataCon##* } >${OutFile} &
DataPid=$!

# Datei herunterladen
echo "TYPE I" >&5
GetResponseCode >/dev/null

echo "RETR ${InFile}" >&5
GetResponseCode >/dev/null
GetResponseCode >/dev/null

# Ausloggen
echo "QUIT" >&5
GetResponseCode >/dev/null

# Verbindung schlieen
exec 5>&-
exec 6>&-
kill ${DataPid} ${ControlPid} 2>/dev/null
