#!/bin/bash
#******************************************************************
#$ident: @(#) netenv 0.94 Time-stamp: <03/07/31 21:35:06 bav> $
#******************************************************************
#                            Gerd Bavendiek  bav@epost.de  97-05-00
#
# This script is used to set up a file containing information about
# the actual network environment. This can be esp. useful for a
# laptop being used in multiple environments: at home, in the office,
# at a customer site.
#
# After the comment section has become quite large, I swapped it to a
# netenv.html file. 
#
# netenv will fail when dialog(1) is not found !
#
# As of version 0.81 netenv will try to use "math" when setting up a
# new environment. math is work of Bruce Perens <Bruce@Pixar.com>. To
# avoid conflicts with e.g. Mathematica it has been renamed to trpnc.
#-------------------------------------------------------------------
NETENV_VERSION="0.94"

# Are there any command line arguments?
if [ $# != 0 ]; then
  case $1 in
    -v|--version)
      echo "netenv version 0.94, adapted for Debian GNU/Linux"
      echo "Copyright 1997-2003 Gerd Bavendiek <bav@epost.de>"
      ;;
    -h|--help|*)
      cat <<EOF
netenv is an interactive utility to switch between different 
network configurations. It does not accept any command line 
arguments, but you can specify the configuration to use by
setting the variable NETENV.

For creation of new configurations and further environment variables,
please refer to the man page and html documentation.

EOF
      ;;
  esac
  exit 0
fi


# Security check
NO_NOT_BY_ROOT_OWNED_FILES=`find /etc/netenv ! -user 0 | wc -l | awk '{print $1}'`
NO_GROUP_WRITABLE_FILES=`find /etc/netenv -type f -perm -060 | wc -l | awk '{print $1}'`
NO_WORLD_WRITABLE_FILES=`find /etc/netenv -type f -perm -006 | wc -l | awk '{print $1}'`
if [ $NO_NOT_BY_ROOT_OWNED_FILES != "0" -o $NO_GROUP_WRITABLE_FILES != "0" -o $NO_WORLD_WRITABLE_FILES != "0" ]; then
   echo netenv: Security check failed, fix permissions in /etc/netenv !
   echo NO_NOT_BY_ROOT_OWNED_FILES=$NO_NOT_BY_ROOT_OWNED_FILES NO_GROUP_WRITABLE_FILES=$NO_GROUP_WRITABLE_FILES NO_WORLD_WRITABLE_FILES=$NO_WORLD_WRITABLE_FILES
   exit 1
fi

###set -x
# When located in /tmp, script must be called
# AFTER wiping out /tmp has been done ...
# Since this is not possible in Debian (bootmisc.sh called after
# networking), we put the file in /var/tmp, which is preserved upon boot.
NETENV_FIL="/var/tmp/netenv"
# Create the netenv file if it doesn't exist yet (only if called by root).
[ `id -u` = "0" ] && touch -a $NETENV_FIL
# Security check
if [ "X`stat -c %u $NETENV_FIL`" != "X0" -o ! -f $NETENV_FIL ]; then
  echo "netenv: $NETENV_FIL must be a regular file owned by root"
  exit 1
fi
if [ "X$((0`stat -c %a $NETENV_FIL` & 022))" != "X0" ]; then
  echo "netenv: Security check failed, fix $NETENV_FIL permissions"
  exit 1
fi

NETENV_BASE=/etc/netenv
COLS=68
TMPFIL=`tempfile -d /tmp -p dialo  2>/dev/null`
# Set up a trap to remove TMPFIL
trap "rm -f $TMPFIL; trap 0" 0 1 2 3 13 15
if [ $? -ne 0 ]; then TMPFIL=/tmp/netenv.tmp.$$; fi
# trpnc is no longer used in Debian
#MATH=/usr/bin/trpnc # Needed only when setting up a new environment, see
	            # function get_netenvdata()
DIALOG=dialog

if [ -r "/etc/hostname" ]; then
	NODE=`cat /etc/hostname`
else
	NODE=`uname -n`
fi

# dialog is in /usr, which might be on a separate partition. If this is not 
# mounted, we are in trouble. However, the user can specify a NETENV
# assignment at the boot prompt.
nodialog () {
	echo "dialog binary not found."
	echo
	echo "Probably the partition containing /usr could not be mounted"
	echo "To get a valid network setup, specify it at the boot prompt"
	echo "like this: linux NETENV=someplace"
	echo
	echo "For \"someplace\", put in one of the names after the dash"
	echo "in the files from the following listing (only the ones starting"
	echo "with $NODE)."
	echo
	ls $NETENV_BASE
	echo
	echo "Press enter to continue"
	read -t 20
	exit 1
}

which dialog >/dev/null 2>&1 || DIALOG=nodialog

NETENV_TIMEOUT=0 # as a default, don't timeout at all
NETENV_RUN_INIT_SCRIPTS=""
ALLOW_EXPERT=NO
NETENV_DO_RESTART=""
NETENV_REMEMBER_LAST=""

# You can change the variables in the configuration file:
CONFFILE=/etc/netenv/netenv.conf


if [ -r $CONFFILE ]; then
  . $CONFFILE
fi

# In the configuration file, also NETENV_RUN_INIT_SCRIPTS may be set.
DEBIAN_RUN_INIT_SCRIPTS="networking $NETENV_RUN_INIT_SCRIPTS"


###TERM=linux; export TERM # We are called from init, so we need to know

# Some functions ...

ExitOnCancel() { echo "You have canceled the setup routine. No Network \
configuration will be done !"; exit 1; }
ExitOnError() { echo "An unknown error ocurred during setup. No Network \
configuration will be done !"; exit 1; }

first() { echo $* | cut -f1 -d" "; }
second() { echo $* | cut -f2 -d" "; }
third() { echo $* | cut -f3 -d" "; }
fourth() { echo $* | cut -f4 -d" "; }

CheckReturnVal()
{
   case $? in
      0) ;;
      1) ExitOnCancel;;
      *) ExitOnError;;
   esac
}
CheckNoInput()
{
   if [ "$1" = "" ]; then 
      echo "You did not respond with input. No Network \
       configuration will be done !"
      exit 1
   fi
}


get_netenvdata()
{   
   # Executable assigned by $MATH is being used. If it's not available,
   # don't panic, just a loss of convenience ...

	 # Debian uses bash's arithmetic evaluation instead of trpnc.

   while true
   do
      
      $DIALOG --inputbox "IP-Address\nEnter the current IP-address or the keyword dhcp ..." \
       9 $COLS $IPADDR 2>$TMPFIL
      CheckReturnVal
      IPADDR=`cat $TMPFIL`
      case $IPADDR in 
         [dD][hH][cC][pP])
            # Maybe this is SuSE specific. RedHat / Debian users feedback appreciated !
            BOOTPROTO='dhcp'
            # This is a rather crude attempt to distinguish between
            # onboard and PCMCIA-NIC's.
            STARTMODE='hotplug' # Default is PCMCIA-NIC
	    # cardmgr is (hopefully) not running at this time, so if
	    # there is a eth0, it must be onboard
            if dmesg | grep eth0 >/dev/null 2>&1; then STARTMODE='onboot'; fi
           ;;
         *)      
      CheckNoInput $IPADDR
      ipa=`echo $IPADDR | sed 's/\./ /g'`
      I1=`first $ipa`
      I2=`second $ipa`
      I3=`third $ipa`
      I4=`fourth $ipa`

      # Just a wild guess ...
      NETMASK=255.255.255.0
      
      $DIALOG --inputbox "Netmask\nEnter the netmask of the current subnet ..." \
       9 $COLS $NETMASK 2>$TMPFIL
      CheckReturnVal
      NETMASK=`cat $TMPFIL`
      CheckNoInput $NETMASK

      netm=`echo $NETMASK | sed 's/\./ /g'`
      N1=`first $netm`
      N2=`second $netm`
      N3=`third $netm`
      N4=`fourth $netm`
      let R1=$(($I1 & $N1))
      let R2=$(($I2 & $N2))
      let R3=$(($I3 & $N3))
      R4="0"
      NETWORK="$R1.$R2.$R3.$R4"
      
      $DIALOG --inputbox "Network\nEnter the IP-Address of the current network ..." \
       9 $COLS $NETWORK 2>$TMPFIL
      CheckReturnVal
      NETWORK=`cat $TMPFIL`
      CheckNoInput $NETWORK

      let R1=$((~N1 & 255 | I1))
      let R2=$((~N2 & 255 | I2))
      let R3=$((~N3 & 255 | I3))
      let R4=$((~N4 & 255 | I4))
      BROADCAST="$R1.$R2.$R3.$R4"
      
      $DIALOG --inputbox "Broadcast\nEnter the broadcast-Address of the current network ..." \
       9 $COLS $BROADCAST 2>$TMPFIL
      CheckReturnVal
      BROADCAST=`cat $TMPFIL`
      CheckNoInput $BROADCAST
			
      let R1=$(($I1 & $N1))
      let R2=$(($I2 & $N2))
      let R3=$(($I3 & $N3))
      GATEWAY="$R1.$R2.$R3.1"
      
      $DIALOG --inputbox "Gateway\nEnter the Gateway-Address of the current network ..." \
       9 $COLS $GATEWAY 2>$TMPFIL
      CheckReturnVal
      GATEWAY=`cat $TMPFIL`
      # Don't check for GATEWAY, no input simply means closed shop -
      # which may be useful.

      # As of 0.92 I remove PROFILE. It's confusing people ...

      # As of 0.92 add Nameserver. Comes in handy from time to
      # time. Useful only when GATEWAY is set.
      if [ -n "$GATEWAY" ]; then 
         $DIALOG --inputbox "Nameserver\nEnter the IP-address of the current nameserver ..." \
         9 $COLS $GATEWAY 2>$TMPFIL
         CheckReturnVal
         DNS_1=`cat $TMPFIL`
         # Don't check for input - there may be no nameserver
      fi      
      ;;
esac
      (
      echo "The current contents of your /tmp/netenv is as follows:"
      echo
      echo "# Networkenvironment: netask"

      if [ "$BOOTPROTO" = "dhcp" ] ; then
         echo export BOOTPROTO=$BOOTPROTO
         echo export STARTMODE=$STARTMODE
      else
         echo export IPADDR=$IPADDR
         echo export NETWORK=$NETWORK
         echo export NETMASK=$NETMASK
         echo export BROADCAST=$BROADCAST
         if [ ! -z "$GATEWAY" ]; then
            echo export GATEWAY=$GATEWAY
         fi
         if [ ! -z "$DNS_1" ]; then
            echo export DNS_1=$DNS_1
         fi
      fi
      echo -e "\n\n\n\n\n"
      echo "Answer <Yes> if that looks ok, otherwise <No>"
      echo
      ) > $TMPFIL
	 
      $DIALOG --yesno "`cat $TMPFIL`" 20 72
	 
      if [ $? -eq 0 ]; then
	 (
	 echo "# Networkenvironment: netask"
         if [ "$BOOTPROTO" = "dhcp" ] ; then
            echo export BOOTPROTO=$BOOTPROTO
            echo export STARTMODE=$STARTMODE
         else
	    echo export IPADDR=$IPADDR
	    echo export NETWORK=$NETWORK
	    echo export NETMASK=$NETMASK
	    echo export BROADCAST=$BROADCAST
	    if [ ! -z "$GATEWAY" ]; then
	       echo export GATEWAY=$GATEWAY
	    fi
 	    if [ ! -z "$DNS_1" ]; then
 	       echo export DNS_1=$DNS_1
 	    fi
         fi
	 ) > $NETENV_FIL
         break
      else	
	 $DIALOG --yesno "Do you want to repeat the setup process ? " 5 72
	 if [ $? -eq 1 ]; then exit 1; fi		   
      fi
   done

   chmod 644 $NETENV_FIL

   $DIALOG --yesno "Do you want to save this configuration ?" 5 72
   if [ $? -eq 0 ]; then
      $DIALOG --inputbox "Configuration name\nEnter the name under which\
 the configuration should be stored ..." \
       9 $COLS  2>$TMPFIL
      CheckReturnVal
      NETENV=`cat $TMPFIL`
# The scripts requires that there be a file named /etc/netenv/$NODE. 
# If it does not yet exist, we have to create it.
      if [ -e /etc/netenv/$NODE ]; then
				CheckNoInput $NETENV
				NETCONF_FIL="$NETENV_BASE/"$NODE"-"$NETENV
      else
# The file does not yet exist.
# If the user has let the name field empty, use "default". This is necessary
# in order to be able to bypass DIALOG by specifying a non-empty NETENV at the
# boot prompt (in case /usr/ has not been mounted. 
				if [ X$NETENV = X ]; then
					NETENV=default
				fi
				NETCONF_FIL="$NETENV_BASE/"$NODE"-"$NETENV
# the target of the link doesn't exit yet, but it will be created soon.
				(cd $NETENV_BASE; ln -s ${NODE}-${NETENV} $NODE)
      fi
      cp $NETENV_FIL $NETCONF_FIL # As of 0.92 omit -p (scripts clean /tmp)  
   fi
} # End Function get_confdata

choose_network_environment()
{
   ITEM_LIST=( ) # have to be reentrant as of 0.93 ...
   # The ls gives a list of files starting with the current node name,
   # excluding emacs backup files. The list starts with the default
   # and ends with ask.
   for i in `ls $NETENV_BASE/$NODE $NETENV_BASE/$NODE-*[0-9a-zA-Z] 2>/dev/null`
   do
      netenv_id="unknown"
      eval `grep '^[[:space:]]*netenv_id' $i`
      SUFFIX=`basename $i | cut -d '-' -f2-`
      # Maybe something like lulu or foo-bar or lulu-no-eth or foo-bar-no-eth
      SUFFIX=`basename $i`
      if [ $SUFFIX != $NODE ]; then
         LENGTH=$((${#NODE}+1))
         SUFFIX=${SUFFIX:$LENGTH}
      fi
      ITEM_LIST=( "${ITEM_LIST[@]}" "$SUFFIX" "$netenv_id" )
   done
   
   ITEM_LIST=( "${ITEM_LIST[@]}" "new" "Set up new environment" )
   CHOOSE_TITLE_TEXT="netenv $NETENV_VERSION on $NODE running `uname -s` `uname -r`\n\nChoose your current network-environment !"
   NETENV_REMEMBER_LAST=`echo "$NETENV_REMEMBER_LAST" | tr 'A-Z' 'a-z'`
   if [ \( X"$NETENV_REMEMBER_LAST" = Xyes -o X"$NETENV_REMEMBER_LAST" = Xdefault \) -a -r /var/cache/netenv/lastitem ]; then
     LAST_ITEM="`cat /var/cache/netenv/lastitem`"
   else 
     LAST_ITEM=""
   fi
   $DIALOG  --default-item "$LAST_ITEM" --timeout $NETENV_TIMEOUT --menu "$CHOOSE_TITLE_TEXT" 20 $COLS 12 "${ITEM_LIST[@]}" 2>$TMPFIL
   EXIT_STATUS=$?
   if [ X`grep -v ^$ $TMPFIL` = Xtimeout ]; then
     if [ X"$NETENV_REMEMBER_LAST" = Xdefault -a -r /var/cache/netenv/lastitem ]; then
       cp /var/cache/netenv/lastitem $TMPFIL
       EXIT_STATUS=0
     fi
   else
     [ $EXIT_STATUS = 0 ] && cp -f $TMPFIL /var/cache/netenv/lastitem
   fi
   return "$EXIT_STATUS"
} # End Function choose_network_environment

# End of function defining

# Let's do the work ...
case $1 in
   '-h'|'--help'|'-?'|'help')
      echo Version $NETENV_VERSION
      echo Docs and examples in /usr/share/doc/packages/netenv
      echo Latest versions see http://netenv.sourceforge.net
      exit 0
   ;;
esac

###NODE=foo-bar  # TODO
# The following block will hopefully get us a valid NETENV. It is
# skipped for those, who still prefer input at the boot prompt 
if [ -z "$NETENV" ]; then
   choose_network_environment
   if [ $? -ne 0 -a X`grep -v ^$ $TMPFIL` != Xtimeout ]; then
     if [ "$ALLOW_EXPERT" = "YES" ]; then
       $DIALOG --yesno "Do you want to enter expert mode ? " 5 72
       if [ $? -eq 0 ]; then
         /bin/sh
	 choose_network_environment
       else
	 echo "You didn't choose a network environment - good luck !"
	 exit 0
       fi
     else
       echo "You didn't choose a network environment - good luck !"
       exit 0
     fi
   else
#      NETENV=`cat $TMPFIL` && rm -f $TMPFIL
      NETENV=`grep -v ^$ $TMPFIL` 
      # Deal with special cases
      if [ "$NETENV" = new ]; then
	 :
      elif [ "$NETENV" = $NODE -o "$NETENV" = timeout ]; then
	 NETENV=""
	 echo "netenv: File $NETENV_BASE/$NODE will be used for setting up the network environment ..."
      else	
	 echo "netenv: File $NETENV_BASE/$NODE"-"$NETENV will be used for setting up the network environment ..."
      fi
   fi
else
   # Continue here, if variable NETENV has been set up as boot argument
   echo "netenv: Using provided NETENV=$NETENV ..."
   if [ "$NETENV" = $NODE ]; then
     # user has given the default on the command line.
     NETENV=""
   fi
fi

# Define the file holding the current network-environment
# configuration. Directory is $NETENV_BASE, filename is e.g. foo-off
# for the current system named "foo" and the Variable NETENV=off
# (Laptop "foo" used in the office). If NETENV has not been defined,
# look for file <nodename>, e.g. "foo".

# Handle special case: ask for environment
if [ "$NETENV" = new ]; then
   NETCONF_FIL="$NETENV_BASE/"$NODE"-"$NETENV
   if [ -r $NETCONF_FIL ]; then
      . $NETCONF_FIL
   fi

   get_netenvdata

   # At this point we assume to have a valid NETENV_FIL, eventually a
   # NETCONF_FIL too. The latter is not a must. If the user decided
   # not to store the data it may be a once-and-never-again environment.

elif [ -z "$NETENV" ]; then
   # Variable NETENV has not been defined or assigned, probably on
   # home tower or something like that ...
   # This is the default !
   NETCONF_FIL="$NETENV_BASE/"$NODE
else
   NETCONF_FIL="$NETENV_BASE/"$NODE"-"$NETENV
fi	

if [ -r $NETCONF_FIL ]; then
   cp $NETCONF_FIL $NETENV_FIL # As of 0.92 omit -p (scripts clean /tmp)   
   chmod 644 $NETENV_FIL
else
   echo "netenv: Using temporary configuration data ..."
fi

. $NETENV_FIL

# If NETENV_SCRIPT has been defined, run it. Of course this is done as
# root. There is no NIC configured yet !
if [ -r "$NETENV_SCRIPT" ]; then
   if [ -z "$NETENV" ]; then
      PROFILE=default
   else
      PROFILE=$NETENV
   fi
   echo "executing $NETENV_SCRIPT $PROFILE ..."
   . $NETENV_SCRIPT $PROFILE
fi


# New as of 0.93. If netenv is not run during boot but on the fly, ask the user, if
# he wants to restart the network
if [ "`tty`" != /dev/console ]; then
  case $NETENV_DO_RESTART in
    never|Never|NEVER)
      DO_RESTART=no;;
    yes|Yes|YES)
      DO_RESTART=yes;;
    *)
      $DIALOG --yesno "Do you want to activate changes by restarting the network ? " 5 72
      if [ $? -eq 0 ]; then
	DO_RESTART=yes
      else
	DO_RESTART=no
      fi
      ;;
  esac
  if [ $DO_RESTART = "yes" ]; then
    if grep 'Red Hat' /etc/issue > /dev/null; then
      /etc/init.d/network restart 
    elif grep SuSE /etc/issue > /dev/null; then
      /etc/init.d/network restart
         # As of SuSE 8.0 route has gone. Still here for 7.3 Users ...
      if [ -x /etc/init.d/route ]; then /etc/init.d/route restart; fi
    elif grep 'Debian\|Ubuntu' /etc/issue > /dev/null; then
      for script in $DEBIAN_RUN_INIT_SCRIPTS; do
	/etc/init.d/$script restart;
      done
      for script in $NETENV_START_STOP_SCRIPTS; do
	/etc/init.d/$script stop;
	/etc/init.d/$script start;
      done
    fi
  fi
fi

exit 0
