#! /bin/ksh
USAGE="USAGE: expand_alias [ -r max_recursion ] [ -t ] [ -tt ] [ -d ] alias...
   Recursively expand the sendmail alias.  Through use of 'telnet host 25'
   and the expn command, each alias is recursively expanded into its 
   destination(s).  Indentation is used to show each level of recurstion.
   Because of the recursive use of telnet, expand_alias is slow.

   max_recursion defaults to 10.  After max_recursion expansions, no
   further expansion is attempted.

   If -t is specified, only the terminal aliases will be displayed.

   -tt is similar to -t except that if a terminal line has a pipe, its
   printing is suppressed and the previous level of expansion is printed
   instead.

   If -d is specified, the initial domain is taken to be everything
   after the "@" character.  Normally, expand_alias takes the initial
   domain to be everything after the first dot, e.g for
   coulter@hpclmac.cup.hp.com, the domain is cup.hp.com.  For an alias
   such as coulter@cup.hp.com, -d should be specified.  -d should not
   be needed with the latest version of expand_alias.

   Examples:
	expand_alias root
	expand_alias root@hpclisp
	expand_alias root@hpclisp.cup.hp.com
	expand_alias root@cup.hp.com
"
# AUTHOR: Michael Coulter; Kudos to John Stafford for the telnet | awk trick.
# 03/07/92
# 920708  Added -tt option contributed by Chip Chapin to suppress printing
#	  pipes.
# 921106  Rewrote it to use the 220 line output to set the domain.  This
#         eliminated the need for the -d option.  The script should really
#	  be re-written, but who has the time.
# 921202  Enhanced -tt to print a specific error string for pipe errors.
# 921204  Fixed deblanking problem.
#	  Fixed problem with tacking a domain onto a domain in recursion.
#	  Fixed problem with telnet lines coming out on s300.

# just in case this is set, unset it.  If set, it will cause a hang.
set +o monitor

# process the arguments

    MAX_RECURSION="10"
    OPT_DOMAIN=""
    OPT_TERMINAL=""
    NOPIPES=""
    DONE_WITH_OPTS="FALSE"
    while [ "$DONE_WITH_OPTS" = "FALSE" ]
    do
	case "$1" in 

	  -d )  shift
		OPT_DOMAIN="-d"
		;;
	  
	  -r )	shift
		MAX_RECURSION="$1"
		shift
		;;

	  -t )	OPT_TERMINAL="-t"
	        shift
	        ;;

	  -tt ) OPT_TERMINAL="-tt"
		NOPIPES="nein danke"
		shift
		;;

	  * )   DONE_WITH_OPTS="TRUE"
		;;
	esac
    done
    
    if [ $# -gt 1 ]
    then
	RET_VAL=0
	for ALIAS in $*
	do
	    expand_alias $OPT_TERMINAL -r "$MAX_RECURSION" "$ALIAS"
	    STATUS=$?
	    if [ "$STATUS" -ne 0 ]
	    then
		RET_VAL="$STATUS"
	    fi
	done
	exit $RET_VAL
    fi

    if [ $# -ne 1 ]
    then
	echo "Improper number of arguments ( $# )." 1>&2
	echo "$USAGE" 1>&2
	exit 1
    fi

    if [ "$1" = "-?" ]
    then
	echo "$USAGE" 1>&2
	exit 1
    fi
    ALIAS="$1"; shift

    # DOMAIN is everything after the first dot (possibly nothing) or everything
    # past the "@" character.

    if [ "$OPT_DOMAIN" = "" ]
    then
	DOMAIN="${ALIAS#*.}"
	if [ "$DOMAIN" = "$ALIAS" ]
	then
	    DOMAIN=""
	fi
    else
	DOMAIN="${ALIAS#*@}"
	if [ "$DOMAIN" = "$ALIAS" ]
	then
	    DOMAIN=""
	fi
    fi

    # HOST is everything between the first @ and the first dot.
    # If HOST is not provided, use the current hostname.

    HOST="${ALIAS%%.*}"
    HOST="${HOST#*@}"
    if [ "$HOST" = "$ALIAS" ]
    then
	HOST=`hostname`
    fi


# set up variables and parameters

    # SHIFT holds the number of spaces to indent expanded lines.
    typeset -i COUNT
    ERROR_STRING="!!!ERROR!!!"
    PIPE_ERROR_STRING="!!!PIPE_ERROR!!!"
    SHIFT="    "
    TIMEOUT=15

# set up the trap statement to remove temporary files


    ATEND="/tmp/expend$$"
    EXPANSION="/tmp/expexp$$"
    TEMP1="/tmp/exptmpa$$"
    trap "rm -f $ATEND $EXPANSION $TEMP1 2> /dev/null" 0 1 2 3 15


# Make sure we don't exceed the recursion level

    MAX_RECURSION=`expr "$MAX_RECURSION" - 1`
    if [ "$MAX_RECURSION" -lt 1 ]
    then
	echo "$SHIFT" "max_recursion limit reached for this alias"
	exit 0
    fi

# Expand the alias on the requested host.  We have to jump through hoops
# to keep telnet from terminating before we get our response.


    if [ "$DOMAIN" = "" ]
    then
	TELNET="${HOST}"
    else
	if [ "$OPT_DOMAIN" = "" ]
	then
	    TELNET="${HOST}.${DOMAIN}"
	else
	    TELNET="$DOMAIN"
	fi
    fi
    (
	    echo "expn $ALIAS"
	    echo "quit"
	    while test ! -r $ATEND
		do 
		    sleep 1
		    ((COUNT=COUNT+1))
		    if [ $COUNT -gt $TIMEOUT ]
		    then
			# stop waiting after TIMEOUT seconds.
			break 
		    fi
		done
    )  |
	    2>&1 telnet "$TELNET" 25 |
	    awk '
		 /^Trying/ {continue}
		 /^Connected/ {continue}
		 /^Escape/ {continue}
		 /^.*closing connection.*$/ {continue}
		 /^telnet>.*$/ {continue}
		 /^220 .*$/ {print $0; continue}
		 /^Connection closed/ { 
		     print "At connection closed" >"'$ATEND'"
		     print '$$' >"'$ATEND'"; exit
		 }
		 {print}
	    ' > $EXPANSION

# Print out the expansion of this alias.  Each line must be indented by
# $SHIFT characters.
    
    cat "$EXPANSION" 2> /dev/null | while read EXP_LINE
	do
	    case "$EXP_LINE" in
	      250* )
		    # NEW_ADDR is the stuff between < and >
		    # We also remove stuff in parentheses and white space before
		    # the open paren.
		    NEW_ADDR="${EXP_LINE%%>*}"
		    NEW_ADDR="${NEW_ADDR##*<}"
		    NEW_ADDR="${NEW_ADDR%(*)*}"
		    NEW_ADDR="${NEW_ADDR%% *}"
		    NEW_ADDR="${NEW_ADDR%%	*}"
		    LINE="${EXP_LINE#250?}"
		    if [ "$OPT_TERMINAL" = "" ]
		    then
			echo "${LINE#250?}"
		    fi

		    IS_TERMINAL="FALSE"
		    IS_ERROR="FALSE"
		    IS_PIPE_ERROR="FALSE"
		    if [ "$NEW_ADDR" = "$ALIAS" ]
		    then
			# the recursion has bottomed out.
			IS_TERMINAL="TRUE"
		    else
			case "$NEW_ADDR" in
			  *Unknown?host* )
			      IS_TERMINAL="TRUE"
			      IS_ERROR="TRUE"
			      ;;

			  *User?unknown* )
			      IS_TERMINAL="TRUE"
			      IS_ERROR="TRUE"
			      ;;

			  *Host?name?lookup?failure )
			      IS_TERMINAL="TRUE"
			      IS_ERROR="TRUE"
			      ;;

			  *desk.hp.com* )
			      IS_TERMINAL="TRUE"
			      ;;

			  *\|* )
			      IS_TERMINAL="TRUE"
			      if [ ! -z "$NOPIPES" ] 
			      then
				  IS_ERROR="TRUE"
				  IS_PIPE_ERROR="TRUE"
			      fi
			      ;;
			      
			      
			  *@*  )
			      # $NEW_ADDR needs to be expanded.  If the new alias
			      # does not include a domain, use the current domain

			      OLD_ADDR="$NEW_ADDR"
			      NEW_DOMAIN="${NEW_ADDR#*.}"
			      if [ "$NEW_DOMAIN" = "$NEW_ADDR" -a "$DOMAIN" != "" ]
			      then
				  NEW_ADDR="${NEW_ADDR}.${DOMAIN}"
			      fi
			      if [ ! -z "$OPT_TERMINAL" ]
			      then
				  expand_alias $OPT_TERMINAL -r "$MAX_RECURSION" "$NEW_ADDR" \
				    | while read OUT_LINE
				      do
					case "$OUT_LINE" in
					  *$ERROR_STRING* | *$PIPE_ERROR_STRING* )
					      echo "${LINE#250?}"
					      ;;
					  
					  Unexpected?output*Unknown?host )
					      # If we added a domain, try not
					      if [ "$OLD_ADDR" != "$NEW_ADDR" ]
					      then
						  expand_alias $OPT_TERMINAL -r "$MAX_RECURSION" "$OLD_ADDR"
					      else
						  echo "$OUT_LINE"
					      fi
					      ;;

					  * )
					      echo "$OUT_LINE"
					      ;;
					esac
				      done				\
				    | sed -e "s/^/${SHIFT}/"
			      else
				  expand_alias -r "$MAX_RECURSION" "$NEW_ADDR" \
				    | ( IFS=""
				      while read OUT_LINE
				      do
					case "$OUT_LINE" in
					  
					  Unexpected?output*Unknown?host )
					      # If we added a domain, try not
					      if [ "$OLD_ADDR" != "$NEW_ADDR" ]
					      then
						  expand_alias -r "$MAX_RECURSION" "$OLD_ADDR"
					      else
						  echo "$OUT_LINE"
					      fi
					      ;;

					  * )
					      echo "$OUT_LINE"
					      ;;
					esac
				      done				\
				      )					\
				    | sed -e "s/^/${SHIFT}/"
			      fi
			      ;;

			  telnet* )
			      IS_ERROR="TRUE"
			      IS_TERMINAL="TRUE"
			      ;;

			  * )
			      IS_TERMINAL="TRUE"
			      ;;
			esac
		    fi
		    if [ ! -z "$OPT_TERMINAL" -a "$IS_TERMINAL" = "TRUE" ]
		    then
			if [ "$IS_ERROR" = "FALSE" ]
			then
			    echo "${LINE#250?}"
			elif [ "$IS_PIPE_ERROR" = "TRUE" ]
			then
			    echo "$PIPE_ERROR_STRING"
			else
			    echo "$ERROR_STRING"
			fi
		    fi
		  ;;

	      220* )
		  # Pick up the domain from the 220 line
		  # The machine address is everything between the first and
		  # second blanks
		  MACHINE="${EXP_LINE#* }"
		  MACHINE="${MACHINE%% *}"
		  # The domain is everything after the first dot.
		  DOMAIN="${MACHINE#*.}"
		  ;;

	      * )
		  echo "Unexpected output: $EXP_LINE"
		  ;;
	    esac

	done
    exit 0
