#! /bin/sh

# adsl.sh - Easily manage your ADSL connection
# TODO : determine dhs.org and dyndns.org's IPs automatically.
#
# Copyright (c) 2000 Raphaël HALIMI <raph@captainblood.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

VERSION="2.3.1"

# Some variables... Don't change them. Believe me.
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=adsl
DESC="ADSL link"
TERM=linux
TAIL="tail -n 5 /var/log/messages"

# Temp files. Don't touch them.
TMP_DIR=/tmp/adsl.sh
LOCK_FILE=$TMP_DIR/lock
TMP_PPPD=$TMP_DIR/pppd
TMP_PPTP1=$TMP_DIR/pptp1
TMP_PPTP2=$TMP_DIR/pptp2
TMP_IFACE=$TMP_DIR/iface
TMP_DEVICE=$TMP_DIR/device
TMP_DHS=$TMP_DIR/dhs
TMP_DYNDNS=$TMP_DIR/dyndns
TMP_APACHE=$TMP_DIR/apache
TMP_IP=$TMP_DIR/ip_address

# Modem and network interface addresses. Normally you don't want to change
# this.
MODEM_ADD="10.0.0.138"
ETH_ADD="10.0.0.1"

# You should change this one. For most people, it should be set to eth0. I
# have two network cards and my ADSL modem is connected to the second one, so
# it's eth1 for me.
ADSL_ETH="eth1"

# If you have a dhs.org account, and want this script to automatically update
# the IP adress for this host, set the DHS variable to 1 and modify the other
# variables tou suit your needs. Otherwise, set the DHS variable to 0.
# NOTE : it works only with dynamic hostnames, such as "foo.dyn.dhs.org", not
# with "foo.dhs.org". NOTE 2 : you'll need lynx to get this working. Check your
# Linux distribution, there should be a package containing it.
DHS=0
DHS_LOGIN=""
DHS_PASS=""
DHS_HOSTNAME=""

# Same thing, but fot dyndns users.
DYNDNS=0
DYNDNS_LOGIN=""
DYNDNS_PASS=""
DYNDNS_HOSTNAME=""

# If you have an Apache server on your machine, set the following variable to 1.
# It will gracefully restart Apache, so that your virtual hosts can work.
# Otherwise, set it to 0. Don't forget to change the second variable to suit
# your needs (if you installed Apache from a package, the path should be right ;
# if you installed from tarball, it must be /usr/local/apache/bin/apachectl).
# NEW : now, the script keep gracefully restarting Apache until the
# Virtual Hosts *really* work (sometimes, it doesn't, due to DNS
# propagation latency). Fill the "APACHE_VIRTUAL_URL" variable to one of
# your Virtual Host"s URL (complete URL, with "http://") and
# "APACHE_VIRTUAL_STRING" with something unique in this page's source
# code (like a word contained in the page's title, for example). 
RESTART_APACHE=0
APACHECTL=/usr/sbin/apachectl
APACHE_VIRTUAL_URL=""
APACHE_VIRTUAL_STRING=""
APACHE_TIMEOUT=5

# If Ctrl-C is pressed, we do a clean quit.
function ctrl_c {
	echo "Interrupted by user."
	echo "Warning : you should manually check temp files (in $TMP_DIR)."
	clean_quit 1
}

trap ctrl_c INT


# Creating temp dir.
if [ ! -d $TMP_DIR ] ; then
   mkdir $TMP_DIR
fi

# Checking no other instance is running.
if [ -e $LOCK_FILE ] ; then
   echo "Another instance of this script is running. Aborting."
   exit 1
fi

# We create the temp file.
touch $LOCK_FILE

# A function to cleanly quit.
function clean_quit {
	echo "Cleanly quitting..."
	echo -n "Removing lock file : "
        rm $LOCK_FILE
	echo "done."
        exit $1
}

# Okay, here we go. First, the function called to stop the ADSL link.
function adsl_stop {
         # Verifying if the temp files are here. If not, it means that the
	 # current ADSL link might not been started with this script.
	 if [ ! -f $TMP_PPPD -o ! -f $TMP_PPTP1 -o ! -f $TMP_PPTP2 ] ; then
	    echo " --> Can't determine if the current ADSL link was started with this script."
	    echo "Aborting."
	    clean_quit 1
	 fi
	 # Defining PIDs we should kill.
         PPPD_PID="`cat $TMP_PPPD`"
	 PPTP1_PID="`cat $TMP_PPTP1`"
	 PPTP2_PID="`cat $TMP_PPTP2`"
	 # Verifying if the PIDs match the processes we want. If yes, we kill
	 # them. If not, we don't do anything.
	 if [ "`ps ax | grep "$PPTP2_PID".*pptp | grep -v grep`" ] ; then
	    echo " --> Killing pptp GRE-to-PPP gateway..."
	    kill $PPTP2_PID
	    while [ "`ps ax | grep "$PPTP2_PID".*pptp | grep -v grep`" ] ; do
	   	  sleep 1
	    done
	 else
	    echo " --> Warning: pptp GRE-to-PPP gateway not running any more. Skipping..."
	 fi
	 if [ "`ps ax | grep "$PPPD_PID".*pppd | grep -v grep`" ] ; then
	    echo " --> Killing pppd..."
	    kill $PPPD_PID
	    while [ "`ps ax | grep "$PPPD_PID".*pppd | grep -v grep`" ] ; do
	    	  sleep 1
	    done
	 else
	    echo " --> Warning: pppd not running any more. Skipping..."
	 fi
	 if [ "`ps ax | grep "$PPTP1_PID".*pptp | grep -v grep`" ] ; then
	    echo " --> Killing pptp Call Manager..."
	    kill $PPTP1_PID
	    while [ "`ps ax | grep "$PPTP1_PID".*pptp | grep -v grep`" ] ; do
	   	  sleep 1
	    done
	 else
	    echo " --> Warning: pptp Call Manager not running any more. Skipping..."
	 fi
	 # Removing pptp's run files.
	 rm -rf /var/run/pptp
	 # Deconfiguring network interface attached to the ADSL modem.
         ifconfig $ADSL_ETH down
	 # Removing temp files.
	 rm $TMP_PPPD $TMP_PPTP1 $TMP_PPTP2 $TMP_IFACE $TMP_DEVICE
}

# Now the function to start the ADSL link
function adsl_start {
         # First we configure the network interface the ADSL modem is attached
	 # to.
         ifconfig $ADSL_ETH $ETH_ADD
	 # Now we start pptp.
	 pptp $MODEM_ADD
	 # Waiting until it starts pppd...
	 until [ "`$TAIL | grep pppd.*started`" ] ; do
	       sleep 1
	 done
	 echo " --> PPP daemon started..."
	 # Now it's started, we write its PID in a temp file.
	 PPPD_PID=`$TAIL | grep pppd.*started | awk '{print $5}' | sed \
	 "s/pppd\[//" | sed "s/\]://"`
	 echo $PPPD_PID > $TMP_PPPD
         # Waiting for pppd to connect...
	 until [ "`$TAIL | grep pppd.*"$PPPD_PID".*Connect`" ] ; do
	       sleep 1
	 done
	 # Writing interface and device in temp files.
	 IFACE=`$TAIL | grep pppd.*Connect: | awk '{print $7}'`
	 DEV=`$TAIL | grep pppd.*Connect: | awk '{print $9}'`
	 # Saving interface and device in a file.
	 echo $IFACE > $TMP_IFACE
	 echo $DEV > $TMP_DEVICE
	 # We write both pptp processes' PIDs in two other temp files, too.
	 # First, the Call Manager...
	 echo `ps ax | grep pptp.*call.*man.*"$MODEM_ADD" | grep -v grep | awk '{print $1}'` > $TMP_PPTP1
	 # Then, the Gateway...
	 PDEV="`cat $TMP_DEVICE | sed "s/tty/pty/"`"
	 # Waiting for Gateway to start...
	 until [ "`ps ax | grep pptp.*gateway.*"$PDEV" | grep -v grep`" ] ; do
	       sleep 1
	 done
	 echo `ps ax | grep pptp.*gateway.*"$PDEV" | grep -v grep | awk '{print $1}'` > $TMP_PPTP2
	 # Now we watch /var/log/messages, waiting for pppd to connect. If it
	 # tells something bad, we launch the adsl_stop function.
	 while true ; do
	       if [ "`$TAIL | grep pppd.*"$PPPD_PID".*timeout.*Config\-Requests`" ] ; then
	          echo " --> Timeout sending Config-Requests."
		  adsl_stop
		  echo "Aborting."
		  clean_quit 1
	       elif [ "`$TAIL | grep pppd.*"$PPPD_PID".*LCP.*terminated.*peer`" ] ; then
	          echo " --> LCP terminated by peer."
		  adsl_stop
		  echo "Aborting."
		  clean_quit 1
	       elif [ "`$TAIL | grep pppd.*"$PPPD_PID".*terminated`" ] ; then
	          echo " --> Connection terminated."
		  adsl_stop
		  echo "Aborting."
		  clean_quit 1
	       elif [ "`$TAIL | grep pppd.*"$PPPD_PID".*Login.ok`" ] ; then
	          echo " --> Login OK."
		  break
	       elif [ "`$TAIL | grep pppd.*"$PPPD_PID".*local.*IP.*address`" ] ; then
	          echo " --> Login OK."
		  break
	       fi
	 done
	 # Waiting for pppd to get an IP adress
         until [ "`$TAIL | grep pppd.*"$PPPD_PID".*local.*IP`" ] ; do
	       sleep 1
	 done
	 # Writing some info on standard output.
	 NEWIP=`$TAIL | grep pppd.*"$PPPD_PID".*local.*IP | awk '{print $9}'`
	 echo " --> Interface $IFACE configured, using device $DEV."
	 echo " --> IP address:  $NEWIP."
	 # Checking if IP adress has changed.
	 if [ "`cat $TMP_IP`" != "$NEWIP" ] ; then
	    IP_CHANGE="1"
	 fi
	 echo $NEWIP > $TMP_IP
}

# Now, the function to update the dhs.org account, if needed. Quite simple, we
# access the webpage with lynx.
function dhs_update {
         if [ "$DHS" = "1" ] ; then
            echo -n "Updating dhs.org entry : "
	    if [ "$IP_CHANGE" = "1" ] ; then
               lynx -dump -auth=$DHS_LOGIN:$DHS_PASS "http://63.175.98.30/nic/hosts?domain=dyn.dhs.org&hostname=$DHS_HOSTNAME&hostscmd=edit&hostscmdstage=2&type=4&updatetype=online&ip=$NEWIP" > $TMP_DHS
	       if [ "`grep Updating.*done $TMP_DHS`" ] ; then
	          echo "success."
	       else
	          echo "failed."
	       fi
	    else
	       echo "IP address didn't change, not needed."
	    fi
         fi
}

# The same function, but for dyndns users.
function dyndns_update {
	 if [ "$DYNDNS" = "1" ] ; then
	    echo -n "Updating dyndns.org entry : "
	    if [ "$IP_CHANGE" = "1" ] ; then
	       lynx -dump -auth=$DYNDNS_LOGIN:$DYNDNS_PASS "http://members.dyndns.org/nic/update?hostname=$DYNDNS_HOSTNAME&myip=$NEWIP" > $TMP_DYNDNS
	       if [ "`grep good $TMP_DYNDNS`" ] ; then
	          echo "success."
	       else
	          echo "failed."
	       fi
	    else
	       echo "IP address didn't change, not needed."
	    fi
	 fi
}

# Last function : the one which restart Apache, if needed.
function restart_apache {
         if [ "$RESTART_APACHE" = "1" ] ; then
	    echo -n "Gracefully restarting Apache : "
	    TRY=0
	    while true ; do
		  lynx -source -connect_timeout=$APACHE_TIMEOUT $APACHE_VIRTUAL_URL > $TMP_APACHE 2>&1
	          if [ -z "`grep $APACHE_VIRTUAL_STRING $TMP_APACHE`" ] ; then
	    	     TRY=$[$TRY + 1]
	             $APACHECTL graceful > /dev/null
		  else
		     break
	          fi
	    done
	    echo "success after $TRY attempt(s)."
	 fi
}

# Now we can start the script. Not much things to do, everything was in the
# functions.
case "$1" in
  start)
  	echo "Starting $DESC: "
        adsl_start
	echo "Done."
	dhs_update
	dyndns_update
	restart_apache
	;;
  stop)
	echo "Stopping $DESC: "
        adsl_stop
	echo "Done."
	;;
  restart)
	echo "Restarting $DESC: "
	adsl_stop
	adsl_start
	echo "Done."
	dhs_update
	dyndns_update
	restart_apache
	;;
  *)
	N=/etc/init.d/$NAME
	echo "Usage: $N {start|stop|restart}" >&2
	clean_quit 1
	;;
esac

clean_quit 0
