#!/bin/sh
# /usr/lib/ddnsmngr/ddns_url_lib.sh
#
# Shared helpers to parse and rebuild the authority (scheme/host/port) of a
# ddns provider update URL. Sourced by ddnsmngr_updater.sh AND exercised by
# test/parse_servers.sh so the two can never drift.
#
# Authority model (must match the C parser in src/dynamicdnsmngr.c):
#   scheme://[userinfo@]host[:port][/path][?query]
#   - scheme    : http | https            -> use_https
#   - userinfo  : optional, may contain [USERNAME]:[PASSWORD] placeholders;
#                 preserved verbatim on rebuild
#   - host      : ServerAddress
#   - port      : ServerPort (defaults: http=80, https=443)
# Anything that is not an http(s) URL (e.g. a script-based provider) has no
# authority: the parse returns non-zero and rebuild echoes the input unchanged.

# ddns_parse_authority <url>
# On success (return 0) sets globals: SCHEME HOST PORT
# Returns: 1 = not an http(s) url, 2 = bad/empty host, 3 = bad port
ddns_parse_authority() {
	local url="$1" rest auth hostport
	SCHEME=""; HOST=""; PORT=""

	case "$url" in
		http://*)  SCHEME="http" ;;
		https://*) SCHEME="https" ;;
		*) return 1 ;;
	esac

	rest=${url#*://}
	auth=${rest%%[/?]*}				# strip path/query
	case "$auth" in *@*) hostport=${auth##*@};; *) hostport=$auth;; esac

	host=${hostport%%:*}
	case "$hostport" in
		*:*) PORT=${hostport##*:} ;;
		*)   [ "$SCHEME" = "https" ] && PORT=443 || PORT=80 ;;
	esac
	HOST=$host

	case "$HOST" in ""|*[!a-zA-Z0-9.-]*) return 2 ;; esac	# reject empty / IPv6-literal / junk
	case "$PORT" in ""|*[!0-9]*) return 3 ;; esac
	return 0
}

# ddns_rebuild_url <url> <override_use_https> <override_host> <override_port>
# Each override may be empty = keep the value parsed from <url>.
# Echoes the rebuilt url; userinfo and path/query are preserved verbatim.
# A non-http(s) url is echoed unchanged.
ddns_rebuild_url() {
	local url="$1" o_https="$2" o_host="$3" o_port="$4"
	local scheme rest auth pathq userinfo hostport host port defport portpart

	case "$url" in
		http://*)  scheme="http" ;;
		https://*) scheme="https" ;;
		*) echo "$url"; return 0 ;;
	esac

	rest=${url#*://}
	auth=${rest%%[/?]*}
	case "$rest" in
		"$auth") pathq="" ;;
		*) pathq=${rest#"$auth"} ;;			# remainder starts with / or ?
	esac

	case "$auth" in
		*@*) userinfo="${auth%@*}@"; hostport=${auth##*@} ;;
		*)   userinfo=""; hostport=$auth ;;
	esac
	case "$hostport" in
		*:*) host=${hostport%:*}; port=${hostport##*:} ;;
		*)   host=$hostport; port="" ;;
	esac

	[ -n "$o_host" ] && host="$o_host"
	if [ -n "$o_https" ]; then
		[ "$o_https" = "1" ] && scheme="https" || scheme="http"
	fi
	[ -n "$o_port" ] && port="$o_port"

	[ "$scheme" = "https" ] && defport=443 || defport=80
	portpart=""
	[ -n "$port" ] && [ "$port" != "$defport" ] && portpart=":$port"

	echo "${scheme}://${userinfo}${host}${portpart}${pathq}"
}
