# Name Canonicalization
#
# This function is used to transform any RFC822/976 address into a
# well-defined form, namely
#
#	something '@' '<' next-host '>' something
#
# which lets the caller know what the immediately relevant next-host in
# the address is.  The address is first parsed and the appropriate
# next-host focused on, and then that hostname is canonicalized.
#
# The return value is the focused (i.e. including <>) and canonicalized
# (i.e. the focused-on hostname is in canonical form) address.

provide canonicalize

canonicalize (address) {
	sift "$address" in
	# preliminaries
	<>		echo @ ; return ;;		# turn into magic token
	:include:.+	echo $address ; return ;;	# pass through
	(.*)<(.*)>(.*)	address=\1\2\3 ;;		# defocus

	# Reversed JANET addresses...
#	(.*)@uk.ac.(.*)	address="\1@$(revdomain uk.ac.\2)";
#			address=$(canonicalize $address);
#			echo $address; return;;
#	(.*)@UK.AC.(.*)	address="\1@$(revdomain UK.AC.\2)";
#			address=$(canonicalize $address);
#			echo $address; return;;

	in%(.*)		echo "<in%>\1" ; return ;; # in%".." cludge
	IN%(.*)		echo "<in%>\1" ; return ;; # in%".." cludge
	In%(.*)		echo "<in%>\1" ; return ;; # in%".." cludge

	# disambiguate strange route syntax
	(.*)::(.*)	address=\2@\1 ; continue ;;	# decnet
	# mail to uucpneighbour!...@notuucpneighbour gets sent to uucpneighbour
	#([^!])!(.*)@([^@:!]+)
	#		if [ $(ldotsys \1) ]; then
	#			address=@\1:\2@\3
	#		fi ;;

	# canonicalize source routes
	@(.+),(.+)	address=@\1:\2 ; continue ;;
	@(.+):(.+:.+)	address=@\1,\2 ; continue ;;
	# focus source routes
	@([^,:]+)([,:].+)
			focus "<@\1>\2" ; return ;;

	# more miscellaneous cleanup
	(.+)@(.+)	address="\1<@\2>" ;;		# focus on domain
	(.+)<(.+)@(.+)>	address="\1\2<@\3>" ; continue ;;# move gaze right
	(.+<@.+>)	focus "\1" ; return ;;		# already canonical

	# convert old-style addresses to a domain-based address,
	# order determines prec.
	([^!]+)!(.+)	focus "\2<@\1.uucp>" ; return ;;	# uucp syntax
	(.+)%([^%]+)	focus "\1<@\2>" ; return ;;	# official %-kludge
	([^:]+):(.+)	focus "\2<@\1>" ; return ;;	# berknet syntax
	(.)\=(.+)	focus "\2<@\1.bitnet>" ; return ;;# bitnet kludge
	tfis
	echo "$address"
}	# end of canonicalize

focus (address) {
	local domain tmp seenuucp

	domain=''
	seenuucp=false
	sift "$address" in
	(.*)<@>(.*)	canonicalize "\1\2" ; return ;; # degenerate case
	(.+)<@(.+)%(.+)>(.*)
			address="\1%\2<@\3>\4" ; continue ;;	# ripple % to @
	(.+)%(.+)<@($orgdomains)>(.*)
			address="\1<@\2>\4" ; continue ;;
	(.*)<@\[(.)\]>(.*)
			break ;;
	(.*)<@(.+)\.uucp>(.*)
			address="\1<@\2>\3" ; seenuucp=true ; continue ;;
	(.*)<@(.)>([,:])?(.*)
			if [ "\2" = "$uucpname" ]; then
				canonicalize "\1\4" ; return
			elif [ $seenuucp = false ]; then
				domain=$(canon \2)
			fi
			;;
	(.*)<@(.+)>(.*)	tmp=\2
			[ "$domain" ] ||
			sift "$tmp" in
			.+\.($toplevels).?
				domain="$tmp" ; break ;;
			.*	if [ $seenuucp = false ]; then
					domain=$(canon "$tmp")
				fi ;;
			tfis
			[ "$domain" ] && address="\1<@$domain>\3"
			;;
	(.*)<@(.)>(.*)	if [ $seenuucp = true ]; then
				address="\1<@\2.uucp>\3"
			fi ;;
	tfis
	echo $address
}	# end of focus

case "$(type canon)" in
*"not found")
	canon () {
		echo $@
	} ;;
esac
