#!/bin/sh
## debconf config script for ddclient
##
## This script runs before copying the files of the package to the correct
## locations in the system.
##
## It gets the appropriate configuration values and stores them in the debconf
## database. If necessary it asks the user about some needed information.
##
## This file is human readable by using "grep '#' <thisfile>"
#

set -e

fatal() { printf %s\\n "$0: $*" >&2; exit 1; }

. /usr/share/debconf/confmodule
db_version 2.0 || fatal "need DebConf 2.0 or later"

# Usage: hosts=`download_hostlist USER PASSWORD`
# Retrieves the DynDNS hosts of given user
download_hostlist() {
  local username="$1" password="$2"
  db_get ddclient/proxy && proxy=$RET || proxy=
  # FIXME: protect against wget not installed
  http_proxy="$proxy" https_proxy="$proxy" wget -q -O - \
    "http://$username:$password@update.dyndns.com/text/gethostlist" \
    | awk -F \: '{print $2, $4}' | sed -e "N;s/ \n/,/g" | sed -e "s/,/, /g"
}

# Retrieve the list of DynDNS hosts of the user's account from the DynDNS
# server and let the user select which hosts to update.
retrieve_dyndns_hostlist() {
  db_go
  db_get ddclient/username && username="$RET"
  db_get ddclient/password && password="$RET"

  hostslist=`download_hostlist "$username" "$password"`

  # add the list to our multichoice template, then prompt the user
  db_subst ddclient/hostslist choices "$hostslist"
  db_input critical ddclient/hostslist || true

  # set names using the host list to write it to the config file later
  db_go
  db_get ddclient/hostslist
  hostslist=`echo "$RET" | sed -e "s/, /,/g"`
  db_set ddclient/names "$hostslist"

  # if the hostslist was blank, let the user know some possible reasons
  if [ -z "$hostslist" ]; then
    db_input high ddclient/blankhostslist || true
  fi
}

web_choices() {
  cat <<EOF
dyndns              http://checkip.dyndns.org/
freedns             https://freedns.afraid.org/dynamic/check.php
googledomains       https://domains.google.com/checkip
he                  http://checkip.dns.he.net/
ip4only.me          http://ip4only.me/api/
ip6only.me          http://ip6only.me/api/
ipify-ipv4          https://api.ipify.org/
ipify-ipv6          https://api6.ipify.org/
loopia              http://dns.loopia.se/checkip/checkip.php
myonlineportal      https://myonlineportal.net/checkip
noip-ipv4           http://ip1.dynupdate.no-ip.com/
noip-ipv6           http://ip1.dynupdate6.no-ip.com/
nsupdate.info-ipv4  http://ipv4.nsupdate.info/myip
nsupdate.info-ipv6  http://ipv6.nsupdate.info/myip
zoneedit            http://dynamic.zoneedit.com/checkip.html
EOF
}

set_web_default() {
  choices=$1
  preferred=$2
  default=ipify-ipv4
  db_get ddclient/web; old=${RET}
  new=${preferred:-${old}}
  # Give debconf-set-selections pre-seeding priority over the preferred choice.
  db_fget ddclient/web seen
  [ "${RET}" = false ] || new=${old:-${preferred}}
  new=${new:-${default}}
  new=${new%% *}
  if [ "${new}" != other ]; then
    # Expand shorthand (e.g., noip-ipv4) to the full line
    new=$(printf %s\\n "${choices}" | grep -m 1 "^${new} ") || {
      # The user pre-seeded an unsupported choice. Force a re-pick.
      db_fset ddclient/web seen false
      new=$(printf %s\\n "${choices}" | grep -m 1 "^${default} ")
    }
  fi
  db_set ddclient/web "${new}"
}

#----------------------------------------------------------------------------
# create_new_config() - create a new config from scratch
#----------------------------------------------------------------------------
create_new_config()
{
  web=
  services="\
no-ip.com protocol=noip web=noip-ipv4
freedns.afraid.org protocol=freedns web=freedns
duckdns.org protocol=duckdns
domains.google protocol=googledomains web=googledomains
www.dyndns.com protocol=dyndns2 web=dyndns
www.easydns.com protocol=easydns
www.dslreports.com protocol=dslreports1
www.zoneedit.com protocol=zoneedit1 web=zoneedit
"
  services_comma=$(printf %s "${services}" | awk -v ORS=', ' '{print$1}')
  db_subst ddclient/service choices "${services_comma%, }"
  db_input critical ddclient/service || true
  db_go
  db_get ddclient/service; service=${RET}
  if [ "${service}" != other ] &&
      svcdef=$(printf %s "${services}" | grep -m 1 "^${service} "); then
    eval "${svcdef#* }"
    db_set ddclient/protocol "$protocol"
    db_set ddclient/server ""  # use the default server
  else
    # If this case is reached and ${service} != other, the question was
    # previously answered (e.g., with debconf-set-selections) with a value that
    # is either invalid or no longer supported. Either way, treat it as if the
    # user chose "other".
    db_input critical ddclient/protocol || true
    db_go
    db_get ddclient/protocol; protocol=${RET}
    if [ "${protocol}" = other ]; then
        db_input critical ddclient/protocol-other || true
        db_go
        db_get ddclient/protocol-other; protocol=${RET}
        db_set ddclient/protocol "${protocol}"
    fi
    db_subst ddclient/server protocol "${protocol}"
    # Usually the protocol's default server is acceptable, but if the user
    # picked "other" in ddclient/service and then picked a protocol used by one
    # of the well-known services returned from get_services, then we can be
    # confident that the user chose "other" because the protocol's default
    # server is not suitable. This is particularly true for the dyndns2
    # protocol (many dynamic DNS service providers use the dyndns2 protocol).
    server_priority=critical
    printf %s "${services}" | grep -q " protocol=${protocol}\\( .*\\)*\$" \
      || server_priority=low
    db_input "${server_priority}" ddclient/server || true
  fi

  db_input low ddclient/proxy || true

  db_input critical ddclient/username || true
  while true; do
    db_input critical ddclient/password || true
    db_input critical ddclient/password-repeat || true
    db_go
    db_get ddclient/password
    password="$RET"
    db_get ddclient/password-repeat
    if [ "$password" = "$RET" ]; then
      break
    fi
    db_fset ddclient/password seen false
    db_fset ddclient/password-repeat seen false
    db_fset ddclient/password-mismatch seen false
    db_input critical ddclient/password-mismatch || true
  done

  db_input critical ddclient/method || true
  daemon=true
  db_go
  db_get ddclient/method
  case ${RET} in
    "Web-based IP discovery service")
      choices=$(web_choices) || exit 1
      choices_comma=$(printf %s "${choices}" | awk -v ORS=', ' '1')
      db_subst ddclient/web choices "${choices_comma%, }"
      set_web_default "${choices}" "${web}"
      db_input medium ddclient/web || true
      db_go
      db_get ddclient/web; web=${RET%% *}
      case ${web} in
        other) db_input critical ddclient/web-url || true;;
        # Use ddclient's built-in shorthands.
        *) db_set ddclient/web-url "";;
      esac
      ;;
    "Network interface")
      db_input critical ddclient/interface || true

      # set the default mode ddclient should run in (ip-up | daemon),
      # depending on the entered interface (XpppX or other)
      db_go
      db_get ddclient/interface
      case ${RET} in
        *ppp*) default_run_mode="On PPP connect";;
        *) default_run_mode="As a daemon";;
      esac
      db_fget ddclient/run_mode seen
      [ "${RET}" = true ] || db_set ddclient/run_mode "${default_run_mode}"

      # maybe ask the user to override the default values
      db_input medium ddclient/run_mode || true

      db_go
      db_get ddclient/run_mode
      [ "${RET}" = "As a daemon" ] || daemon=false
      ;;
    *) fatal "unsupported IP discovery method: ${RET}";;
  esac

  # if ddclient should run in daemon mode we ask for the update interval
  if [ "${daemon}" = true ]; then
    db_input medium ddclient/daemon_interval || true
  fi

  if [ "${service}" = "www.dyndns.com" ] && command -v wget >/dev/null; then
    db_input critical ddclient/fetchhosts || true
  else
    db_set ddclient/fetchhosts Manually
  fi
  db_go
  db_get ddclient/fetchhosts
  if [ "${RET}" = "From list" ]; then
    retrieve_dyndns_hostlist
  else
    db_input critical ddclient/names || true
  fi

  db_go
}

if [ "$1" = "configure" ]; then
  if [ ! -f /etc/ddclient.conf ]; then
    create_new_config
    exit 0
  fi
  exit 0
elif [ "$1" = "reconfigure" ]; then
  create_new_config
  rm -f /etc/ddclient.conf /etc/default/ddclient
fi
