#!/bin/bash

# Change log

# Version 1.0
# Date -----
# written by hippytaff
# Data aquisation phase written

# version 1.1
# Date 24/3/2011
# Written by hippytaff and matt_symes
# Diagnostic phase written. Connectivity phase written.

# version 1.2
# Date 18/4/2011
# Written by hippytaff and matt_symes
# Connecting to disabled interfaces phase written. Zenity support added.

# version 2.0
# Date 20/4/2011
# Written by hippytaff and matt_symes
# Intellegent diagnostics. Selection of interface.

# 29/04/2011
# Remove extrenious info.

# 30/04/201
# THIS SHOULD BE REVERSED. I AM AS THICK AS TWO SHORT PLANKS.
# DIAGNOSTICS FIRST. IF THAT FAILS THEN SYSTEM INFO.
# AMAZING WHAT A GOOD SLEEP CAN DO. DIAGNOSTICS MUST
# BE FAR MORE ROBUST FIRST THOUGH.

function call_help
{
	cat <<-EOF
	Usage : 	
			--verbose
			--status-only
			--status-single-con
			--status-multi-con
			--status-try-connect
			--help
			--help-summary
			--help-extended
	EOF
}

function call_display_summary_help
{
	cat <<-EOF
	########################################################################################################
	############################## SCRIPT USAGE ############################################################
	########################################################################################################
	#
	# 1. Download script
	# 2. Make scipt executable => chmod 755 wireless_scrip_no_zenity_2.0.sh
	# 3. Run script => sudo ./wireless_scrip_no_zenity_2.0.sh
	# 4. Script starts up and performs initial enviroment tests
	#	>>> Checks is running as root
	#	>>> Checks required binaries are installed
	#	>>> Checks to see if rfkill is installed.
	#	>>> Reads and parses sudo lshw -c network for each interface.
	# 5. Asks the user to select an interface to check.
	# 6. Gets data for interface based on parsed lshw.
	# 7. Runs checks based on lshw
	#
	###########################################################################################################
	########################## SCRIPT COMMAND LINE ARGUMENTS ##################################################
	###########################################################################################################
	#
	# --verbose. 		=> Verbose output for continual monitoring. Logs every ping, dns and wget attempt
	# --status-only		=> Retrieve network status info
	# --status-single-con	=> Retrieve network status info and perform a single connectivity check
	# --status-multi-con	=> Retrieve network status info and repeatedly perform connectivity checking
	# --status-try-connect	=> Try to reconnect to disabled interface
	# --help			=> Basic help
	# --help-summary		=> Help summary
	# --help-extended		=> Extended help
	#
	EOF
}

function call_display_extended_help
{
	less <<-EOF
	#########################################################################################################
	########################## DATA AQUISITION PHASE ########################################################
	#########################################################################################################
	#
	# Data retrieved in this order
	#	>>> Checks for installed network managers (NM, WICD)
	#	>>> Checks for running network managers (NM, WICD)
	#	>>> Gets Mageia release. 		(cat /etc/lsb-release)
	#	>>> Gets kernel release. 		(uname -a)
	# 	>>> List network devices 		(s lshw -C network)
	#	>>> Gets PCI for wired and wireless 	(lspci -nnk | grep ...)
	#	>>> Gets USB devices			(lsusb)
	#	>>> Gets loaded modules 		(lsmod)
	#	>>> Get /etc/network/interface file
	#	>>> Get /etc/modules file
	# 	>>> Get /etc/modprobe.d/blacklist.conf file
	#	>>> List files in /etc/modprobe.d/ dir
	# 	>>> Gets /var/lib/NetworkManager/NetworkManager.state file
	#	>>> Gets /etc/NetworkManager/nm-system-settings.conf file.
	#
	# IF THE INTERFACE IS NOT UNCLAIMED (Found from parsing lshw)
	#	>>> Gets ifconfig info
	#	>>> Gets iwconfig info
	#	>>> rflist info
	#	>>> Gets nm-tool scan info
	#	>>> Gets iwlist scan info
	#	>>> Gets route info and parses to get default gateway IP if avaliable.
	#
	# IF INTERFACE HAS LOGICAL NAME AND DRIVER. (Found from parsing lshw)
	#	>>> Gets dmesg for interface and driver.
	#
	##########################################################################################################
	########################## INTELLIGENT DIAGONSTICS FUNCTIONALITY #########################################
	##########################################################################################################
	#
	# The information gained in the data aquisition phase is parsed to glean status information about the
	# system. This is then used to perform some rudimentary checks.
	#
	# 1. Information parsed in the aquisition phase. Depending on the state of the interface some of
	# these values may be empty
	#
	#	>>> Logical name (wlan0)
	#	>>> State (Empty, DISABLED, UNCLAIMED)
	#	>>> Adaptor name(Product name)
	#	>>> Adaptor Type (ETHERNET, WIRELESS)
	#	>>> Interface driver (ath9k etc)
	#	>>> Interface ip address.
	#
	# 2. If the interface is UNCLAIMED then the driver is missing or incorrect.
	#	>>> There is not much to do here but bail out for someone to diagnose the results file.
	#
	#	>>> Valid values from parsing lshw.
	#		>>> STATE
	#		>>> Adaptor name
	#		>>> Adaptor type
	#
	#		>>> _no_ Logical name, driver, ip address
	#
	#		>>> Can get static system files.
	#		>>> Can get lshw, lspci, lsusb
	#		>>> Can get modules, uname, kernel
	#
	#		>>> No interface. No driver from lshw.
	#		>>> Cannot ping, nslookup, wget as no interface. It is useless as we want to check that interface.
	#		>>> Cannot parse route.
	#		>>> Cannot check nm-tool, iwlist scan,
	#		>>> Cannot check dmesg for that interface
	#		>>> Cannot get ifconfig, iwconfig
	#
	#		>>> NOTE. lshw returns no kernel driver. lspci does. Suggests module is unloaded ?
	#
	# 3. If the interface is DISABLED a number of tests are performed to try to re-enable the interface
	#	NETWORK MANAGER TESTS
	#	>>> If network manager is stopped then all values from parsing lshw are valid.
	#	>>> Can check status from sudo service NetworkManager status => NetworkManager stop/waiting
	#		>>> Attempt to start network manager sudo service NetworkManager start
	#		>>> If the nm state file contains disabled entries it will enable them and restart nm.
	#		>>> If the /etc/network/interface contains the problem interface it will remove it and
	#			and restart nm as this can disable nm if the interface is in the interfaces file.
	#		>>> nm will the be restarted.
	#
	#	NON NETWORK MANAGER TESTS
	#	>>> Networking is restarted (sudo /etc/init.d/networking restart)
	#	>>> Interface is dropped and raised (sudo ifconfig <IFACE> down; sudo ifconfig <IFACE> up)
	#	>>> If a driver is found, unload then reload the driver (sudo modprobe -r <D>; sudo modprobe <D>)
	#		>>> Connectivity is checked after each of these steps.
	#	>>> If this fails bail out for someone to diagnose the results file.
	#
	# IF THE INTERFACE IS UP
	# 4.  If the apdator is not associated with any AP it will ...
	#	>>> TO BE IMPLEMENTED AT A LATER DATE. # FIXME:
	#	>>> It will then try to reconnect.
	#	>>> Connectivity is checked after each of these steps.
	#
	# 4. If the adaptor has no IP address...
	#	>>> If using DHCP it will attempt to get one via DHCP. (sudo dhclient <IFACE>)
	#	>>> Should have one if static IP.
	#	>>> It will then try to reconnect.
	#	>>> Connectivity is checked after each of these steps.
	#
	# 5. If connectivity is lost it will return off power management if the interface has that (wireless).
	#	>>> This has been know to cause loss of connectivity
	#	>>> It will then try to reconnect.
	#	>>> Connectivity is checked after each of these steps.
	#
	# 6. 	CONNECTIVITY CHECKING is performed by the following steps.
	#	>>> Try to ping the local router. IP address parsed from route -n
	#	>>> Try to ping an external ip chosen at random from a list. (ping -c3 8.8.8.8)
	#	>>> Try to perform a nslookup of an external URL chosen at random from a list to an external server. (nslookup)
	#	>>> Try to perform a nslookup of the local server defined in /etc/resolv.conf (nslookup)
	#	>>> Trying to wget an index.html file chosen at random from a list of URLs.
	#	>>> The results are logged to the file.
	#	>>> If connectivity is lost syslog, kern.log and messages are grep'ed to get info about
	#		driver and interface. tail -nX is used to get most recent entries.
	#	>>> Connectivity is checked with a delay of 1 second between each check.
	#
	# 7. If connectivity is restored it will then continue connectivity checking without logging until either the
	#	script is stopped or there is a drop in connectivity, at which point the relevent logs grep'ed tails
	#	will be written to the file.
	#
	######################################################################################################################
	############################################# USE CASES IDENTIFIED ###################################################
	######################################################################################################################
	#
	#	>>> No connectivity at boot up.
	#		>>> Run script to get network info and attempt to restart connectivity.
	#	>>> No connectivity after suspend/hibernate.
	#		>>> Run script to get network info and attempt to restart connectivity.
	# 	>>> Connectivity cuts out intermittently.
	#		>>> Run script and let it keep checking connectivity. When connectivity is lost the relevent log files
	#		are grep'ed and tailed to get information about what could have killed the connectivity.
	#		>>> Power management on wireless cards is disabled in an attempt to stop losing connectivity.
	#
	#	USE CASES IDENTIFIED BUT NOT IMPLEMENTED.
	#	>>> Slow network.
	#		>>> Check bit rate for speed
	#		>>> Check link quality
	#		>>> Check frequency 
	#
	#####################################################################################################################
	########################## LIMITATIONS AND ENHANCEMENTS #############################################################
	#####################################################################################################################
	#
	#	>>> Need to handle static addresses better.
	#	>>> WICD support.
	#	>>> Handle Ethernet cards better.
	#	>>> Handle multiple gateways. Currently get gateway for interface (look for default gateway for interface)
	#	>>> Handle proxy servers.
	#	>>> Multiple IP's on a single interface.
	#	>>> Add support for ndiswrapper.
	#	>>> sudo rm /dev/rmkill ->  to remove an rfblock if 'sudo rfkill unblock all' does not work
	#	>>> rfkill unblock wifi
	#	>>> wicd / wicd-daemon.py / ../wicd/daemon/monitor.py
	#	>>> Wireless encryption
	#	>>> Does no handle virtual adaptors (is this an issue ?)
	# 	>>> consider using nc. Can that tell us anything ?
	#
	EOF
}
#########################################################################################################
########################## SCRIPT DEFINES ###############################################################
#########################################################################################################

# Defines for the script.
VERBOSE=1
QUIET=0
WLESS=wireless-results.txt
VERSION=2.0

# Srcipt binaries.
DATE_FN=
WHOAMI=
ROUTE=
PING=
NSLOOKUP=
WGET=
PGREP=
IFCONFIG=
DHCP=
IWLIST=
IWCONFIG=
URPMI=
RPM=
LSUSB=
LSPCI=
LSMOD=
UNAME=
GREP=
TAIL=
DMESG=
SUDO=
MODPROBE=
LSHW=
SED=
CUT=

# Script *constants*
PING_TRIES=3
REPING_TIME=0.2
ROUTER_PING_TARGET=	 	
EXTERNAL_PING_TARGET=8.8.8.8
DNS_SERVER_IP=8.8.8.8
DNS_LOOKUP_NAME=www.google.com
WGET_URL=www.google.com
# This list of ping targets is also a list of DNS servers and so doubles up bto randomise the dns server used for nslookup.
# Local ones from local providers have a habbit of passing back 'i cannot find this' pages. _Useless_
PING_TARGETS=("8.8.8.8" "208.67.222.222" "4.2.2.1" )
URL_TARGETS=("www.google.com" "www.amazon.com" "www.mageia.org")
NETWORK_MANAGER=[N]etworkManager
WPA_NAME=[w]pa_supplicant
PGREP_WICD_PID=
PGREP_NM_PID=
WICD=wicd

# Script interface variables
ADAPTOR_NAME=
INTERFACE_NAME=
INTERFACE_DRIVER=
INTERFACE_IP=
INTERFACE_STATE=
INTERFACE_TYPE=
MANAGER_INSTALLED=
WLAN_AP=
WLAN_ESSID=
VERBOSE_CONNECTIVITY_CHECKING=
LSHW_RES=

# Script paths
LSB_RELEASE=/etc/lsb-release
NETWORKING_PATH=/etc/init.d/networking
RESOLV_FILE=/etc/resolv.conf
INTERFACES_FILE=/etc/network/interfaces
MODULES_FILE=/etc/modules
BLACKLIST_FILE=/etc/modprobe.d/blacklist.conf
BLACKLIST_FOLDER=/etc/modprobe.d/*
SYSLOG_LOG=/var/log/syslog
MESSAGES_LOG=/var/log/messages
KERNEL_LOG=/var/log/kern.log
NM_STATE_FILE=/var/lib/NetworkManager/NetworkManager.state
NM_APPLET_FILE=/etc/NetworkManager/nm-system-settings.conf
NETWORK_MANAGER_CONF=/etc/NetworkManager/NetworkManager.conf

# Script arrays
ADAPTOR_NAMES=()
INTERFACE_STATES=()
INTERFACE_NAMES=()
INTERFACE_DRIVERS=()
INTERFACE_IPS=()
INTERFACE_TYPES=()

#################################################################################################
########################## SCRIPT FUNCTIONS #####################################################
#################################################################################################

# Function to check that rfkill is installed, and offer to install it if not
#
function call_rfkill_check
{
	RFKILL_INSTALLED=$("$RPM" -qa | grep rfkill)

	sleep 1

	if [[ "$?" == "0" ]]
	then
		if  [[ "$RFKILL_INSTALLED" == "" ]]
		then
			# Ask the suer if they want to install rfkill
			echo "rfkill is not installed!...rfkill can unblock wireless blocks should there be any, would you like to install it?  y/n"
		
			# What do they say ?
			read ans
		
			if [[ "$ans" == "y" ]]
			then
				# might cause problems with non-debian distros. Consider removing the option to install
				#+or piss about to allow support for non-apt setups

				sudo "$URPMI" --auto rfkill 	

				[[ "$?" -ne 0 ]] && { echo "Error installing rfkill"; return 1; }
			else
				echo "Continuing without rfkill."
				echo "You will not be notified of any blocks."

				return 1;
			fi
		fi
	else
		echo "Error checking for installed rfkill"

		return 1;
	fi

	sudo rfkill unblock all				# Now we know its there, unblock any blocks

	return 0;
}

# Function to redirect stdout to wireles-script.txt ($WLESS)
#
function call_redirect_stdout
{
	# Redirect output.
	exec 5>&1
	exec >> "$WLESS"
	exec 2>&1
}

# Function to restore stdout
#
function call_restore_stdout
{
	exec 1>&5 5>&-
}

# Function to check for that we have root privilages
#
function call_check_root_privilages
{
	WHOAMI=$(which whoami)

	[[ "$WHOAMI" == "" ]] && { echo "Cannot find whoami binary"; exit 1; }

	# Check we are root.
	[[ $("$WHOAMI") == "root" ]] ||
		{ echo "This script needs to be run as root. Please run with sudo ./wireless_script"; exit 1; }
}

# Function to initialise the script.
# It just gets the binaries to the moment.
# May also allow us to use the script on
# different distributions or workarounds
# if binaries are missing.
#
function call_initialise
{
	# Get the location of the binaries
	ROUTE=$(which route)
	PING=$(which ping)
	NSLOOKUP=$(which nslookup)
	WGET=$(which wget)
	PGREP=$(which pgrep)
	DATE_FN=$(which date)
	IFCONFIG=$(which ifconfig)
	DHCP=$(which dhclient)
	IWLIST=$(which iwlist)
	IWCONFIG=$(which iwconfig)
	URPMI=$(which urpmi)
	RPM=$(which rpm)
	LSUSB=$(which lsusb)
	LSPCIDRAKE=$(which lspcidrake)
	LSMOD=$(which lsmod)
	UNAME=$(which uname)
	GREP=$(which grep)
	TAIL=$(which tail)
	DMESG=$(which dmesg)
	SUDO=$(which sudo)
	MODPROBE=$(which modprobe)
	LSHW=$(which lshw)
	SED=$(which sed)
	CUT=$(which cut)

	# Check binaries exist.
	# NOTE TO SELF. MAYBE SKIP WGET TEST IF BINARY NOT THERE.
	[[  "$ROUTE" != "" && "$PING" != "" &&
		"$NSLOOKUP" != "" && "$WGET" != "" && "$PGREP" != "" &&
		"$DATE_FN" != "" && "$IFCONFIG" != "" && "$DHCP" != ""  &&
		"$IWLIST" != "" && "$IWCONFIG" != "" && "$URPMI" != "" && 
		"$RPM" != "" && "$LSUSB" != "" && "$LSPCIDRAKE" != ""  && 
		"$LSMOD" != ""  && "$UNAME" != "" && "$GREP" != "" &&
		"$TAIL" != "" && "$DMESG" != "" && "$SUDO" != "" && "$MODPROBE" != "" && 
		"$LSHW" != "" && "$SED" != "" && "$CUT" != "" ]] ||
		{ echo "cannot find required binaries"; exit 1; }
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to check to see what networking daemons are running
#
function call_check_for_connection_managers
{
	echo "******************************************************************************************"
	echo "Running networking services"
	echo "******************************************************************************************"

	# Check to see if network manager is installed
	if [[ $("$RPM" -qa | "$GREP" -c networkmanager) -gt 0  ]]
	then
		# Flag that NetworkManager is installed
		MANAGER_INSTALLED="NetworkManager"

		# Write it to the file
		echo "NetworkManager is installed"

		# It is installed bu is it running ?
		call_is_network_manager_running

		if [[ "$?" -eq 0 ]]
		then 
			echo "NetworkManager is running"
		else
			echo "NetworkManager is _not_ running"
		fi

		# Exit at this point
		return 0;
	else
		echo "NetworkManager is _not_ installed"
	fi

	# Check for an installed version of wicd.
	if [[ $("$RPM" -qa | "$GREP" -c wicd )  -gt 0  ]]
	then
		# Flag that wicd is installed.
		MANAGER_INSTALLED="wicd"

		# Log to the file.
		echo "WICD is installed"
		
		# It's installed but is it running ?
		call_is_wicd_running

		if [[ "$?" -eq 0 ]]
		then
			echo "WICD is running"
		else
			echo "WICD is _not_ running"
		fi
		
		# Exit at this point.
		return 0;
	else
		echo "WICD is _not_ installed"
	fi

	# Check to see that networking is up if not using managers.
	# FIXME: Implement this. Test on server.

	MANAGER_INSTALLED="none"

	return 0;
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to check if NetworkManager daemon is running
#
function call_is_network_manager_running
{
	RUNNING=$(service NetworkManager status)

	echo "$RUNNING"

	# Is it running ?
	[[ "$RUNNING" =~ start/running ]] && return 0

	# It's not running
	return 1
}

# This is the function to start and wait for it to either
# connect or not. It will start or restart depedning on wether
# network manager is already running.
#
function call_start_nm_wait
{
	# Simple sanity check here.
	[[ "$MANAGER_INSTALLED" != "NetworkManager" ]] && return 1

	# Lets see if network manager is running.s
	call_is_network_manager_running

	if [[ "$?" -eq 0 ]]
	then
		echo "Stopping NetworkManager"

		# It is running so restart it.
		call_manage_nm stop
		
		sleep 1

		echo "Starting NetworkManager"

		call_start_nm start
	else
		echo "Starting NetworkManager"

		# It's not running. Start it
		call_start_nm start
	fi

	return "$?"
}

# Comment block
: <<"COMMENT"

10.10 has a tool called nmcli
11.04 has a tool called nmonline

These are not availiable in 10.04 or lower.

It might be worth checking the distro to use the new tools
if they are availiable as they might be more reliable
org.freedesktop.NetworkManager

dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.DBus.Properties.GetAll string:org.freedesktop.NetworkManager

org.freedesktop.NetworkManager

http://projects.gnome.org/NetworkManager/developers/spec.html#type-NM_STATE
http://nienhueser.de/blog/?p=28
http://fedoraforum.org/forum/showthread.php?t=243118
http://dbus.freedesktop.org/doc/dbus-tutorial.html
http://www.freedesktop.org/wiki/Software/dbus#Documentation

dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.StateChanged string:org.freedesktop.NetworkManager

dbus-send --dest='org.freedesktop.ExampleName            \
          /org/freedesktop/sample/object/name              \
          org.freedesktop.ExampleInterface.ExampleMethod   \
          int32:47 string:'hello world' double:65.32

dbus-monitor "type='signal',sender='org.kde.kopete',interface='org.kde.Kopete',path='/Kopete',member='contactChanged'" | awk '/string "/ {print $2; fflush() }' | sed -u 's/"//g' | while read contact
do
if [[  "$contact" == "${*}" ]]
then
if qdbus org.kde.kopete /Kopete contactProperties "$contact" | grep pending_messages: | grep -q '<p'
then
qdbus org.kde.kopete /Kopete openChat "$contact"
fi
fi
done

 dbus-monitor "type='signal',sender='org.freedesktop.NetworkManager',interface='org.freedesktop.NetworkManager.StateChanged'"

COMMENT

# Function to start/restart network manager and wait
# until it tries to connect.
# $1 start or restart command
# FIXME: Get this function to use the actual interface name.
#
function call_start_nm
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_start_nm"; exit 1; }

	# Get the initial state of connectivity
	PREVIOUS_STATE=$(nm-tool | grep State | cut -f2 -d' ')

	# Restart network manager
	call_manage_nm "$1"

	# Wait for network manager to reconnect or not.
	# Sixty second timeout.
	NM_TIME_OUT=60

	while ((NM_TIME_OUT > 0))
	do
		# Sleep for a second
		sleep 1	

		# Get the current state
		CURRENT_STATE=$(nm-tool | grep State | cut -f2 -d' ')

		# Have we changed state.
		if [[ "$PREVIOUS_STATE" != "$CURRENT_STATE" ]]
		then
			# Disconnected to connecting. Nothing to do here but log it.
			[[ "$PREVIOUS_STATE" == "disconnected" && "$CURRENT_STATE" == "connecting" ]] && 
				{ echo "Connecting after restarting network manager"; }

			# We have connected.
			[[ "$PREVIOUS_STATE" == "connecting" && "$CURRENT_STATE" == "connected" ]] && 
				{ echo "Connected after restarting network manager"; return 0; }
			
			# We tried to connect and got disconnected.
			[[ "$PREVIOUS_STATE" == "connecting" && "$CURRENT_STATE" == "disconnected" ]] &&
				{ echo "Could not connect after restarting network manager"; return 1; }

			# We were disconnected and we still are disconnected. Assume failure
			[[ "$PREVIOUS_STATE" == "disconnected" && "$CURRENT_STATE" == "disconnected" ]] &&
				{ echo "Could not connect after restarting network manager"; return 1; }

			# We have gone from the connected state to the disconnected state here.
			# Just log this as the timout or disconnected->disconnected state will trap this.
			[[ "$PREVIOUS_STATE" == "connected" && "$CURRENT_STATE" == "disconnected" ]] &&
				{ echo "network manager disconnected after being connected"; }
	
			# Store the current state
			PREVIOUS_STATE="$CURRENT_STATE"
		fi

		# Decrement the timeout.
		((NM_TIME_OUT--))
	done

	# At this point we timmed out
	echo "Timed out waiting for network manager to reconnect"

	return 1
}

# Function to stop/start/restart network manager
# $1 Operation to be performed on Network Manager
#
function call_manage_nm
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_manager_nm"; exit 1; }

	echo "$1 Network Manager"
	echo

	# Restart network manager.
	"$SUDO" service NetworkManager "$1"

	return "$?"
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

: <<"COMMENT"

It is possible to merge this funcitonality with the
NetworkManager functionality above as they are both
almost identical. At the moment though they shall remain
seperate

COMMENT

# Function to check if wicd daemon is running
#
function call_is_wicd_running
{
	RUNNING=$(service wicd status)

	echo "$RUNNING"

	# Is it running ?
	[[ "$RUNNING" =~ running ]] && return 0

	# It's not running
	return 1
}

# This is the function to start and wait for it to either
# connect or not. It will start or restart depending on wether
# wicd is already running.
#
function call_start_wicd_wait
{
	# Simple sanity check here.
	[[ "$MANAGER_INSTALLED" != "wicd" ]] && return 1

	# Lets see if wicd is running.
	call_is_wicd_running

	if [[ "$?" -eq 0 ]]
	then
		echo "Stopping wicd"

		# It is running so restart it.
		call_manage_wicd stop
		
		sleep 1

		echo "Starting wicd"

		call_start_wicd start
	else
		echo "Starting wicd"

		# It's not running. Start it
		call_start_wicd start
	fi

	return "$?"


}

# Function to start/restart wicd and wait
# until it tries to connect.
# $1 start or restart command
#
function call_start_wicd
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_start_wicd"; exit 1; }

	# Restart network manager
	call_manage_wicd "$1"

	# Just a simple sleep for the moment.
	sleep 30

	return 0
}

# Function to manage the wicd daemon
# $1 Operation to perform on the daemon
#
function call_manage_wicd
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_manage_wicd"; exit 1; }

	echo "$1 WICD"
	echo

	# Restart network manager.
	"$SUDO" service wicd "$1"

	return "$?"
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to aquire the system info for the network
#
function call_get_system_info
{
	echo "******************************************************************************************"
	echo "    Mageia release "
	echo "******************************************************************************************"
	echo
	[[ -f "$LSB_RELEASE" ]] && cat "$LSB_RELEASE"
	echo
	echo "******************************************************************************************"
	echo "    Kernel"
	echo "******************************************************************************************"
	echo
	"$UNAME" -a
	
	return "$?"
}

# Function to get the list of loaded drivers
#
function call_get_loaded_drivers
{
	echo "******************************************************************************************"
	echo "    List of drivers"
	echo "******************************************************************************************"
	echo
	"$LSMOD"

	return "$?"
}

# Function to return the relevent PCI info for the interface
# $1
#
function call_get_lspci_info
{
#03:00.0 Ethernet controller: Broadcom Corporation NetLink BCM5784M Gigabit Ethernet PCIe (rev 10)
#06:00.0 Network controller: Atheros Communications Inc. AR928X Wireless Network Adapter (PCI-Express) (rev 01)

	echo
	echo "******************************************************************************************"
	echo "    pci devices"
	echo "******************************************************************************************"
	echo
	"$LSPCIDRAKE" -v | "$GREP" -i network

	return "$?"
}

# Function to return the lsusb info for the interfaces
# $1
#
function call_get_lsusb_info
{
	echo
	echo "******************************************************************************************"
	echo "    usb devices"
	echo "******************************************************************************************"
	echo
	# FIXME: Dump them all to the file for the moment
	# until we can identify a method to just get the
	# wireless apadtors as per Chill555's suggestion.
	"$LSUSB" # | "$GREP" -i wirel
	
	return "$?"
}

# Function to return lshw info for the interface
# $1
#
function call_add_lshw_info
{
	echo
	echo "******************************************************************************************"
	echo "      lshw  List of network devices"
	echo "******************************************************************************************"
	echo
	echo "$LSHW_RES"
}

# Function to get the network info.
# $1 Interface
#
function call_get_hardware_info
{
	# Get then info from lshw
	call_add_lshw_info

	# Get the lspci info for the card.
	call_get_lspci_info

	# Get the lsusb info for the card.
	call_get_lsusb_info
	
	return 0
}

# Function to get the file
#
function call_get_file_info
{
	function call_get_resolv
	{
		echo
		echo "******************************************************************************************"
		echo "resolv.conf"
		echo "******************************************************************************************"

		# Does the name server file exist
		[[ -f "$RESOLV_FILE" ]] && { cat "$RESOLV_FILE"; return 0; }

		echo "$RESOLV_FILE does not exist"

		return 1;
	}

	function call_get_interfaces
	{
		echo
		echo "******************************************************************************************"
		echo "interfaces"
		echo "******************************************************************************************"

		[[ -f "$INTERFACES_FILE" ]] && { cat "$INTERFACES_FILE"; return 0; }

		echo "$INTERFACES_FILE does not exist"

		return 1;
	}

	function call_get_blacklisted_devices
	{
		echo
		echo "******************************************************************************************"
		echo "Blacklist file"
		echo "******************************************************************************************"

		[[ -f "$BLACKLIST_FILE" ]] && { cat "$BLACKLIST_FILE"; return 0; }

		echo "$BLACKLIST_FILE does not exist"

		return 1;
	}

	function call_get_modules_file
	{
		echo
		echo "******************************************************************************************"
		echo "Modules file"
		echo "******************************************************************************************"

		[[ -f "$MODULES_FILE" ]] && { cat "$MODULES_FILE"; return 0; }

		echo "$MODULES_FILE does not exist"

		return 1;
	}

	function call_list_all_blacklist_files
	{
		echo
		echo "******************************************************************************************"
		echo "Files in folder $BLACKLIST_FOLDER"
		echo "******************************************************************************************"

		for blacklist_file in  $BLACKLIST_FOLDER
		do
			echo "$blacklist_file"
		done
	}

	function call_get_nm_state_file
	{
		echo
		echo "******************************************************************************************"
		echo "NetworkManager.state"
		echo "******************************************************************************************"

		[[ -f "$NM_STATE_FILE" ]] && { cat "$NM_STATE_FILE"; return 0; }

		echo "$NM_STATE_FILE does not exist"

		return 1;
	}

	function call_get_nm_applet_file
	{
		echo
		echo "******************************************************************************************"
		echo "nm_applet_file"
		echo "******************************************************************************************" 

		# The file name was changed between 10.10 and 11.04

		# This is for 10.10 and lower
		[[ -f "$NM_APPLET_FILE" ]] && { cat "$NM_APPLET_FILE"; return 0; }

		# This is for 11.04 and greater.
		[[ -f "$NETWORK_MANAGER_CONF" ]] && { cat "$NETWORK_MANAGER_CONF"; return 0; }

		echo "$NM_APPLET_FILE or $NETWORK_MANAGER_CONF does not exist"

		return 1;
	}

	# Get the files.
	call_get_interfaces
	call_get_resolv
	call_get_modules_file
	call_get_blacklisted_devices
	call_list_all_blacklist_files

	# Get the files for any managers installed.
	if [[ "$MANAGER_INSTALLED" == "NetworkManager" ]]
	then
		# Get nm specific files.
		call_get_nm_state_file
		call_get_nm_applet_file

	elif [[ "$MANAGER_INSTALLED" == "wicd" ]]
	then
		echo
	fi
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to get interface info
# $1 Interface
#
function call_get_interface_info
{
	# Get ifconfig information.
	echo
	echo "******************************************************************************************"
	echo "  network info "
	echo "******************************************************************************************"
	echo
	"$IFCONFIG" -v -a "$1"

	# If the interface is a wireless interface......
	if [[ $INTERFACE_TYPE =~ Wireless ]]
	then	
		# Parse the iwconfig info and add to the file.
		call_parse_iwconfig "$1" true

		# List any rf blocks for wireless interfaces.
		echo "******************************************************************************************"
		echo " rfkill list all Rfkill Blocks"
		echo "******************************************************************************************"
		echo
		sudo rfkill list all
		echo
	fi

	return 0
}

# Function to parse iwconfig to get any relevent information form it.
# $1 Interface name
# $2 Should the results be echoed ?
#
function call_parse_iwconfig
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_parse_iwconfigS"; exit 1; }

	# Get the iwconfig data.
	IWCONFIG_RES=$("$IWCONFIG" "$1")

	[[ "$?" -ne 0 ]] && 
		{ 
			echo "******************************************************************************************"
			echo " Wireless specific network info"
			echo "******************************************************************************************"
			echo
			echo "Could not get iwconfig network information for parsing"; 
			return 1; 
		}

	# Blat out to the file if required.
	[[ "$?" == true ]] && { echo "$IWCONFIG_RES"; echo; }

	# Parse to find out which ESSID we are connected to (if any)
	WLAN_ESSID=${IWCONFIG_RES#*${INTERFACE_NAME}*ESSID$':"'}
	WLAN_ESSID=${WLAN_ESSID%%$'"'*}

	# Parse to get the access point.
	WLAN_AP=${IWCONFIG_RES#*${INTERFACE_NAME}*Access Point$': '}
	WLAN_AP=${WLAN_AP%% *}

	return 0
}

# Scan the access point.
# $1 Interface
#
function call_scan_AP
{
	if [[ "$MANAGER_INSTALLED" == "NetworkManager" ]]
	then
		# Is network manager running ?
		call_is_network_manager_running

		if [[ "$?" -eq 0 ]]
		then 
			echo
			echo "******************************************************************************************"
			echo "Using nm-tool"
			echo "******************************************************************************************"

			# Use nm-tool
			nm-tool
		fi
	fi

	echo
	echo "******************************************************************************************"
	echo "Using iwlist scan"
	echo "******************************************************************************************"

	# use iwlist
	"$IWLIST" "$1" scan
}

# Function to parse the route
# $1 Interface
# $2 truefalse to echo/not echo route info
#
function call_get_and_parse_route
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_get_and_parse_route"; exit 1; }

	# Get the routes. This will give us the ip address of the default gateway.
	# 0.0.0.0         xxx.xxx.xxx.xxx     0.0.0.0         UG    0      0        0 wlan0
	ROUTE_RES=$("$ROUTE" -n)

	# Did it fail ?
	[[ "$?" -eq 0  ]] || return 1

	# Echo the route info if required.
	[[ "$2" == true ]] && 
		{
			echo;
			echo "******************************************************************************************";
			echo "Route info";
			echo "******************************************************************************************";
			echo "$ROUTE_RES";
		}

	# Get the gateway ip addess.
	while read LINE
	do
		# Look for the G of gateway for our adaptor.
		if [[ "$LINE" =~ G && "$LINE" =~ $1 ]]
		then
			# Get the router ip address.
			ROUTER_PING_TARGET=${LINE:16:16}
		fi

	done < <(echo "$ROUTE_RES")

	# Parse the route.
	[[ $ROUTER_PING_TARGET == "" ]] && { echo "Failed to parse route"; return 1; }

	# Sucess
	return 0
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to interrogate dmesg for failure information.
# $1 Interface
# $2 Driver
#
function call_interrogate_dmesg
{
	# Sanity  check
	[[ "$1" == ""  || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_interrogate_dmesg"; exit 1; }

	echo
	echo "******************************************************************************************"
	echo "******************************************************************************************"
	echo "dmesg for interface $1 and $2"
	echo "******************************************************************************************"
	echo "******************************************************************************************"
	echo

	"$DMESG" | "$GREP" -E "$1|$2" | "$TAIL" -n30
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to get full system information from calls and files
# $1 Interface
#
function call_get_full_system_info
{
	# Get the system information
	call_get_system_info

	# Check for failure
	[[ "$?" -ne 0 ]] && return 1

	# Get the network info
	call_get_hardware_info

	# Check for failure
	[[ "$?" -ne 0 ]] && return 1

	# Get the drivers loaded by the system.
	call_get_loaded_drivers

	[[ "$?" -ne 0 ]] && return 1

	# Get the file info.
	call_get_file_info

	# If the interface is UNCLAIMED this is all the usefull information
	# we can aquire at this time.
	[[ "$INTERFACE_STATE" =~ "UNCLAIMED" ]] && { echo "INTERFACE $ADAPTOR_NAME UNCLAIMED. NO MORE USEFUL STATE INFORMATION"; return 1; }

	# Get the interface info
	call_get_interface_info "$INTERFACE_NAME"
	
	# Check for failure
	[[ "$?" -ne 0 ]] && return 1

	if [[ $INTERFACE_TYPE =~ Wireless ]]
	then	
		# Scan for access points.
		call_scan_AP "$INTERFACE_NAME"
	fi

	# Display dmesg only if we have an interface name and a driver.
	[[ "$INTERFACE_NAME" != "" && "$INTERFACE_DRIVER" != "" ]] && call_interrogate_dmesg "$INTERFACE_NAME" "$INTERFACE_DRIVER"

	# Parse the route to get the default gateway
	call_get_and_parse_route "$INTERFACE_NAME" true

	# Check for failure
	[[ "$?" -ne 0 ]] && return 1

	return 0;
}

# Function to get the basic summary from system calls.
#
function call_get_summary_network_info
{
	# Get the interface info
	call_get_interface_info "$INTERFACE_NAME"

	# Just pass on the previous return value.
	return "$?"
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to check the connectivity to internal and external entities
# $1 Do we want continual connectivity checking ? (true, false)
# $2 Interface name.
# $3 Driver name
# $4 IP address.
#
function call_check_connectivity
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_check_connectivity"; return 1; }

	[[ "$4" == "" ]] && { echo "No IP address. Cannot check for connectivity"; return 1; }

	echo
	echo "******************************************************************************************"
	echo "Checking connectivity"
	echo "******************************************************************************************"

	MODE=$VERBOSE
	CONNECTIVITY_ACHIEVED=false

	# loop	while :
	while :
	do
		# Randomise the targets we will hit.
		call_get_random_targets

		# Ping router. If ping fails interrogate dmesg. exit loop
		call_ping_target "$ROUTER_PING_TARGET" "$PING_TRIES" "$REPING_TIME" "$MODE" "$2"

		# Did it fail ?
		[[ "$?" -eq 0 ]] ||  { echo "Ping failure to router"; 
					call_interrogate_logs "$2" "$3"; 
					call_get_summary_network_info; 
					return 1; }

		# Ping external target.
		call_ping_target "$EXTERNAL_PING_TARGET" "$PING_TRIES" "$REPING_TIME" "$MODE" "$2"

		# Did it fail ?
		if [[ "$?" -ne 0 ]]
		then
			echo "Ping failure to first external server target $EXTERNAL_PING_TARGET. Trying with different target."

			# Don't assume failue yet. Try another ping target as target might be down.
			call_get_random_targets

			# Ping external target. 
			call_ping_target "$EXTERNAL_PING_TARGET" "$PING_TRIES" "$REPING_TIME" "$MODE" "$2"

			# If ping fails interrogate logs. exit loop
 			[[ "$?" -eq 0 ]] || 
				{ echo "Ping failure to second external server target $EXTERNAL_PING_TARGET"; 
				call_interrogate_logs "$2" "$3"; 
				call_get_summary_network_info; 
				return 1; }
		fi

		# We perform two dns lookups here. One to an external server and one to the local server (what ever that may be)
		# Perform a dns lookup _on an external server_. 
		call_nslookup "$DNS_LOOKUP_NAME" "$MODE" "$DNS_SERVER_IP"

		if [[ "$?" -ne 0 ]]
		then
			echo "First nslookup failure to external server $DNS_SERVER_IP failed"

			# Don't assume failure yet. Try another DNS nameserver server for the lookup.
			call_get_random_targets

			# Perform a dns lookup _on an external server_. 
			call_nslookup "$DNS_LOOKUP_NAME" "$MODE" "$DNS_SERVER_IP"

			[[ "$?" -eq 0 ]] || 
				{ echo "Second nslookup failure to external server $DNS_SERVER_IP failed"; 
					call_interrogate_logs "$2" "$3"; 
					call_get_summary_network_info; 
					return 1; }
		fi

		# Perform a dns lookup _on the local server_ defined in /etc/resolv.conf. 
		call_nslookup "$DNS_LOOKUP_NAME" "$MODE"

		[[ "$?" == 0 ]] || 
			{ echo "nslookup failure to local server $LOCAL_DNS_SERVER failed"; 
				call_interrogate_logs "$2" "$3"; 
				call_get_summary_network_info; 
				return 1; }

		# wget a file.
		call_wget "$WGET_URL" "$MODE"

		if [[ "$?" -ne 0 ]]
		then
			# Don't assume failure yet. Try another server server for the wget.
			call_get_random_targets	


			# wget file. if wget fails interrogate logs. exit loop
			call_wget "$WGET_URL" "$MODE"

			# Did it fail ?
			[[ "$?" -eq 0 ]] || 
				{ echo "wget failure"; 
					call_interrogate_logs "$2" "$3"; 
					call_get_summary_network_info; 
					return 1; }
		fi

		# Do we want continual connectivity checking ?
		# The default here is true unless overridden by the command liine switch.
		[[ "$1" == false ]] && { return 0; }

		# Only want this displayed once
		[[ "$CONNECTIVITY_ACHIEVED" == false ]] && 
			{	call_restore_stdout;
				CONNECTIVITY_ACHIEVED=true;
				echo;
				echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
				echo "Connectivity achieved. Press enter to stop continual checking when required.";
				echo "Please give the script some time to finish.";
				echo "This may take some time depending on what it is doing.";
				echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
				call_redirect_stdout; }

		# Sleep for a second as part of the read command. 
		# Hitting enter will exit the loop.
		read -t 1 && return 0;

		# Change mode to quiet unless overridden by arguments. We don't want
		# the  log file to get too big.
		MODE=$VERBOSE_CONNECTIVITY_CHECKING
	done

	# All is good at this point
	return 0
}

# Fuunction to randomise the targets selecting new targets each time from a list.
#s
function call_get_random_targets
{
	# External servers to ping. These double up as name servers.
	while :
	do
		# Generate a random number between 0-12
		RND=$RANDOM 
		RND=$((RND %= 13))

		# Set the ping target from the list.
		[[ "$EXTERNAL_PING_TARGET" != ${PING_TARGETS[$RND]} ]] && { EXTERNAL_PING_TARGET=${PING_TARGETS[$RND]}; break; }
	done

	# External DNS nameserver IP to query for an nslookup.
	while :
	do
		RND=$RANDOM 
		RND=$((RND %= 13))

		# Randomise the dns server used for nslookup.
		[[ "$DNS_SERVER_IP" != ${PING_TARGETS[$RND]} ]] && { DNS_SERVER_IP=${PING_TARGETS[$RND]}; break; }
	done

	# A URL to lookup by query a dns server
	while :
	do
		RND=$RANDOM 
		RND=$((RND %= 10))

		# Set the the dns lookuptarget
		[[ "$DNS_LOOKUP_NAME" != ${URL_TARGETS[$RND]} ]] && { DNS_LOOKUP_NAME=${URL_TARGETS[$RND]}; break; }
	done

	# A target for wget to retrive a file.
	while :
	do
		RND=$RANDOM 
		RND=$((RND %= 10))

		# Set up the wget target.
		[[ "$WGET_URL" != ${URL_TARGETS[$RND]} ]] && { WGET_URL=${URL_TARGETS[$RND]}; break; }
	done
}

# Function to ping a target.
# $1 ping ip address.
# $2 ping count attempts
# $3 ping retry in seconds.
# $4 Verbose (1) or quiet
# $5 The interface to ping from
#
function call_ping_target
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" || "$3" == ""  || "$4" == ""  || "$5" == "" ]] && { echo "DEBUG: Interface value null in call_ping_target"; exit 1; }

	if (( $2 == $VERBOSE ))
	then
		echo
		echo "******************************************************************************************"
		echo "Ping tests"
		echo "******************************************************************************************"
	fi

	# Ping and store the return string
	PING_RES=$("$PING" -c $2 -i $3 -I $5 $1)

	# What was the result of the ping.
	if [[ "$?" -eq 0 ]]
	then
		# success
		(( $4 == $VERBOSE )) && 
			{ 	echo "sucessfully pinged $1"; 
				echo "$PING_RES"; 
				echo "******************************************************************************************"; }

		return 0
	else
		# failure
		echo "_unsucessfully_ pinged $1"
		echo "******************************************************************************************"

		return 1
	fi
}

# Function to perform a dns look up using nslookup
# $1 is the url to lookup
# $2 Verbose (1) or quiet (0)
# $3 The dns server to use as the lookup.
#
function call_nslookup
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_nslookup"; exit 1; }

	if (( $2 == $VERBOSE ))
	then
		echo
		echo "******************************************************************************************"
		echo "nslookup test to server $3"
		echo "******************************************************************************************"
	fi

	# Perform a dns lookup on the required host.
	NS_LOOKUP_RES=$("$NSLOOKUP" $1 $3)

	if [[ "$?" -eq 0  ]]
	then
		if [[ $NS_LOOKUP_RES =~ answer ]]
		then
			(( $2 == $VERBOSE )) && { echo "sucessfully looked up $1"; echo "$NS_LOOKUP_RES"; }

			return 0
		else
			echo "_unsucessfully_ looked up $1"

			return 1			
		fi
	else
		echo "_unsucessfully_ looked up $1"

		return 1
	fi
}

# Function to retrieve a file using wget
# $1 the url of the file to retrieve
# $2 Verbose (1)  or  Quiet (0)
#
function call_wget
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_wget"; exit 1; }

	if (( $2 == $VERBOSE ))
	then
		echo
		echo "******************************************************************************************"
		echo "wget test"
		echo "******************************************************************************************"
	fi

	WGET_RES=$("$WGET" -q "$1")

	if [[ "$?" -eq 0 ]]
	then
		(( $2 == $VERBOSE )) && { echo "sucessfully retrieved file $1"; echo "$WGET_RES"; }

		# Delete the file.
		rm "index.html"

		return 0
	else
		echo "_unsucessfully_ retrieved file $1"

		return 1
	fi
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to in interrogate the log for the interface and driver
# $1 Interface
# $2 Driver
#
function call_interrogate_logs 
{
	# Interrogate all the logs we are interested in.
	call_interrogate_log "$SYSLOG_LOG" "$1" "$2"
	call_interrogate_log "$KERNEL_LOG" "$1" "$2"
}

# Function to interrogate the logs for failure information.
# Currently interrogates /var/log/messages, /var/log/syslog and /var/log/kern.log
# $1 log to interrogate.
# $2 Interface
# $3 Driver
#
function call_interrogate_log
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" || "$3" == "" ]] && { echo "DEBUG: Interface value null in call_interrogate_log"; exit 1; }

	# Check the log file exists
	[[ -f "$1" ]] || { echo "Cannot find log file $1"; return 1; }

	# Log header.
	echo
	echo "******************************************************************************************"
	echo "******************************************************************************************"
	echo "Log file: $1"
	echo "******************************************************************************************"
	echo "******************************************************************************************"
	echo

	# Interrogate the log.
	cat "$1" | "$GREP" -E "$1|$2" | "$TAIL" -n 30
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to try to intellegently connect to an access point
# based on the parsed system information
# $1 Interface name
# $2 Driver name
#
function call_intelligent_diagnostics
{
	# If the interface is unclaimed then there is not much we can do
	# as we have the wrong or no driver loaded. This should have been
	# caught earlier but this is a precaution.
	[[ "$INTERFACE_STATE" =~ "UNCLAIMED" ]] && { return 1; }

	# Try to check the connectivity. This is the initial conectivity check.
	call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

	[[ "$?" -eq 0 ]] && return 0

	## Call the new function
	call_glue "$1" "$2"
	
	return "$?";
}

# Function to aqttempt to get a DCHP lease from a dhcp server
# $1 The interface to aquire the DHCP lease from
#
function call_get_dhcp_lease
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_get_dhcp_lease"; exit 1; }

	# Release any existing addresses
	$("$SUDO" "$DHCP" -r "$1")

	echo "Trying to aquire dhcp address for interface $1"

	$("$SUDO" "$DHCP" "$1")

	[[ "$?" -eq 0 ]] || { echo "Could not get dhcp lease from dhclient for interface $1"; return 1; }

	echo "Aquired a dhcp lease for interface $1"

	return 0;
}

# Function to toggle power management on wireless cards
# Has been known to cause dropouts on cards.
# $1 The interface
#
function call_toggle_power_managent
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_toggle_power_managent"; exit 1; }

	$("$SUDO" "$IWCONFIG" $1 power off)

	[[ "$?" -eq 0 ]] || { echo "Could not toggle power management for interface $1"; return 1; }

	return 0
}

# Function to reparse all the network info
# $1 The interface
#
function call_reparse_network_info
{
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_reparse_network_info"; exit 1; }

	# Function to get and parse the network data
	call_get_and_parse_lshw_info

	# Get and parse the route info. Don't echo it.
	call_get_and_parse_route "$INTERFACE_NAME" false
	
	if [[ $INTERFACE_TYPE =~ Wireless ]]
	then
		# Reparse network data.
		call_parse_iwconfig "$INTERFACE_NAME" false
	fi

	return "$?"
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################


# Function to
# $1 the interface name
# $2 The driver name
#
function call_glue
{
	# If the interface is unclaimed then there is not much we can do
	# as we have the wrong or no driver loaded. This should have been
	# caught earlier but this is a precaution.
	[[ "$INTERFACE_STATE" =~ "UNCLAIMED" ]] && { return 1; }

	# Try to re-enable network manager.

	# Posibilities here. 
	# The interface will be disable if it is specified as disabled in NetworkManager.state file.
	# Interface can be enabled but networking itself is disabled in NetworkManager.
	# Therefor this needs to come out of the test for a disabled interface below.
	call_try_conect_network_manager "$1"

	# Sucess.
	[[ "$?" -eq 0 ]] && return 0

	# There was a problem it was fixed but network manager would not restart.
	[[ "$?" -eq 2 ]] && return 1

	# Try to connect via wicd if it installed.
	call_try_conect_wicd "$1"

	# Sucess.
	[[ "$?" -eq 0 ]] && return 0

	# There was a problem it was fixed but wicd would not restart.
	[[ "$?" -eq 2 ]] && return 1

	# If the interface is disabled the try to reconnect
	if [[ "$INTERFACE_STATE" =~ "DISABLED" ]]
	then
		# A zero results means the interface was enabled.
		[[ "$?" -eq 0 ]] && { echo "Interface enabled"; return 0; }

		# A problem was found and a fix attempted but the interface was still disabled.
		[[ "$?" -eq 2 ]] && { echo "Problem found but interface was not enabled"; return 1; }

		# Try to enable the interface.
		call_try_enable_interface

		# Pass back the results of trying to reconnect the interface
		return "$?"
	fi

	# Try to connect to the enabled interface.
	call_try_connect_enabled_interface 

	return "?$"
}

# Function to try to reconect using network manager.
# $1 The interface name
#
function call_try_conect_network_manager
{
	# Check network manager is installed. If not exit early.
	[[ "$MANAGER_INSTALLED" != "NetworkManager" ]] && return 1;

	# Check to see if network manager is running.
	call_is_network_manager_running

	# If it's not running the initial check is to start it and see what happens.
	if [[ "$?" -ne 0 ]]
	then
		echo "NetworkManager not running. Initially just starting it"

		# Restart network manager first. You never know.
		call_start_nm_wait

		if [[ "$?" -eq 0 ]]
		then
			# Reparse the network data.
			call_reparse_network_info "$INTERFACE_NAME"; 

			# Try to check the connectivity
			call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

			[[ "$?" -eq 0 ]] && { echo "Restarting the manager restored connectivity "; return 0; }
		fi
	fi

	# Lets check the state file for network manager to see if anything is disabled.

	# Network manager will be disabled if it enabled is set false
	# in the NetworkManager.state file
	call_parse_nm_state_file

	if [[ "$?" -eq 1 ]] 
	then 
		# There was a problem with the state file. Something was disabled.
		echo "Networkmangers state file was disabled"; 
		
		# Restart network manager
		call_start_nm_wait

		if [[ "$?" -eq 0 ]]
		then
			# Reparse the network data.
			call_reparse_network_info "$INTERFACE_NAME"; 

			# Try to check the connectivity
			call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

			[[ "$?" -eq 0 ]] && { echo "Restarting the manager restored connectivity "; return 0; }
		else
			# There was a problem here and even them we could not connect to return error code 2 for the moment.
			call_interrogate_logs "$INTERFACE_NAME" "$INTERFACE_DRIVER"

			return 2
		fi
	fi

	# NetworkManager will disable an interface if it is specified in /etc/network/interfaces. Lets check for this.
	call_check_interfaces_file "$INTERFACE_NAME"

	if [[ "$?" -eq 1 ]] 
	then 
		# The interface was declared in the file /etc/network/interfaces.
		echo "The interface $INTERFACE_NAME was declared in the networking file"; 
		
		# Restart network manager
		call_start_nm_wait
		
		if [[ "$?" -eq 0 ]]
		then
			# Reparse the network data.
			call_reparse_network_info "$INTERFACE_NAME"; 

			# Try to check the connectivity
			call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

			[[ "$?" -eq 0 ]] && { echo "Restarting the manager restored connectivity "; return 0; }
		else
			# There was a problem here and even them we could not connect to return error code 2 for the moment.
			call_interrogate_logs "$INTERFACE_NAME" "$INTERFACE_DRIVER"

			return 2
		fi
	fi
		
	# None of these checks fixed it.
	return 1
}

# Function to try to connect via wicd if wicd is down
#
function call_try_conect_wicd
{
	# Check network manager is installed. If not exit early.
	[[ "$MANAGER_INSTALLED" != "wicd" ]] && return 1;

	# Check to see if network manager is running.
	call_is_wicd_running

	# If it's not running the initial check is to start it and see what happens.
	if [[ "$?" -ne 0 ]]
	then
		echo "wicd not running. Initially just starting it"

		# Restart network manager first. You never know.
		call_start_wicd_wait

		if [[ "$?" -eq 0 ]]
		then
			# Reparse the network data.
			call_reparse_network_info "$INTERFACE_NAME"; 

			# Try to check the connectivity
			call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

			[[ "$?" -eq 0 ]] && { echo "Restarting the manager restored connectivity "; return 0; }
		fi
	fi

	return 1
}

# This function will try to enable an interface if the interface is disabled.
# $1 The interface
# $2 The interface driver.
#
function call_try_enable_interface
{
	# If network manager is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "NetworkManager" ]] && { call_manage_nm stop; }

	# If wicd is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "wicd" ]] && { call_manage_wicd stop; }

	# Restart networking
	call_restart_networking
	
	if [[ "$?" -eq 0 ]]
	then
		# If network-managet is installed
		if [[ "$MANAGER_INSTALLED" == "NetworkManager" ]]
		then
			# Then try to restart.
			call_start_nm_wait

		elif [[ "$MANAGER_INSTALLED" == "wicd" ]]
		then
			# Then try to restart.
			call_start_wicds_wait
		fi

		# Reparse the network data.
		call_reparse_network_info "$INTERFACE_NAME"; 

		# Try to check the connectivity
		call_check_connectivity true "$INTERFACE_NAME"  "$INTERFACE_DRIVER" "$INTERFACE_IP"

		[[ "$?" -eq 0 ]] && { echo "Restarting the networking restored connectivity "; return 0; }
	fi

	# If network manager is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "NetworkManager" ]] && { call_manage_nm stop; }

	# If wicd is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "wicd" ]] && { call_manage_wicd stop; }

	# up down interface
	call_down_up_interface "$1"	

	if [[ "$?" -eq 0 ]]
	then
		# If network-managet is installed
		if [[ "$MANAGER_INSTALLED" == "NetworkManager" ]]
		then
			# Then try to restart.
			call_start_nm_wait

		elif [[ "$MANAGER_INSTALLED" == "wicd" ]]
		then
			# Then try to restart.
			call_start_wicds_wait
		fi

		# Reparse the network data.
		call_reparse_network_info "$INTERFACE_NAME"; 

		# Try to check the connectivity
		call_check_connectivity true "$INTERFACE_NAME"  "$INTERFACE_DRIVER" "$INTERFACE_IP"

		[[ "$?" -eq 0 ]] && { echo "Dropping and raising interface $1 restored connectivity "; return 0; }
	fi

	# If network manager is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "NetworkManager" ]] && { call_manage_nm stop; }

	# If wicd is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "wicd" ]] && { call_manage_wicd stop; }
	
	# Unload reload modules.
	call_reload_drivers "$2"

	if [[ "$?" -eq 0 ]]
	then
		# If network-managet is installed
		if [[ "$MANAGER_INSTALLED" == "NetworkManager" ]]
		then
			# Then try to restart.
			call_start_nm_wait
		
		elif [[ "$MANAGER_INSTALLED" == "wicd" ]]
		then
			# Then try to restart.
			call_start_wicds_wait
		fi

		# Reparse the network data.
		call_reparse_network_info "$INTERFACE_NAME"; 

		# Try to check the connectivity
		call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

		[[ "$?" -eq 0 ]] && { echo "Unloading and reloading $2 restored connectivity "; return 0; }
	fi

	echo "Failure. Could not restore connectivity."

	# Failure
	return 1;
}

# This function will try to connect to an interface that is
# enabled but not connected.
#
function call_try_connect_enabled_interface
{
	# FIXME: Assume dhcp for the moment. Must take into account static IP addresses.
	# If we have no ip address then DHCP failed.
	if [[ "$INTERFACE_IP" == "" || "$ROUTER_PING_TARGET" == "" ]]
	then
		call_get_dhcp_lease "$INTERFACE_NAME"

		[[ "$?" -eq 1 ]] && { echo "Could not aquire a DHCP lease for interface $INTERFACE_NAME"; return 1; }

		# Reparse the network info
		call_reparse_network_info "$INTERFACE_NAME"

		# Recheck conectivity.
		call_check_connectivity true "$INTERFACE_NAME""$INTERFACE_DRIVER" "$INTERFACE_IP"

		[[ "$?" -eq 0  ]] && return 0;
	fi

	# After that do we have an ip address ?
	[[ "$INTERFACE_IP" == "" ]] && { echo "No IP address after call to dhclient."; return 1; }

	# After that do we have a route ?
	[[ "$ROUTER_PING_TARGET" == "" ]] && { echo "No route to gateway after call to dhclient."; return 1; }

	# Sanity  check	
	[[ "$INTERFACE_NAME" == "" || "$INTERFACE_DRIVER" == "" ]] && { echo "DEBUG: Interface value null in call_intelligent_diagnostics"; exit 1; }

	if [[ $INTERFACE_TYPE =~ Wireless ]]
	then
		# decide where this should go.
		call_toggle_power_managent "$INTERFACE_NAME"

		# Recheck conectivity.
		call_check_connectivity true "$INTERFACE_NAME"  "$INTERFACE_DRIVER" "$INTERFACE_IP"

		# Did that work ?
		[[ "$?" -eq 0  ]] && return 0;
	fi

	# At this point the interface should be up so lets have a look
	# at the rest of the parameters.

	# Are we associated with an access point ?
	if [[ "$WLAN_AP" == "" || "$WLAN_ESSID" == "" ]]
	then
		# Try to connect without using a manger
		call_conect_no_manager "$INTERFACE_NAME"

		[[ "$?" -eq 0  ]] && return 0;
	fi
	
	return 1;
}










#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to connect to the network bypassing any manager
# $1 Interface
#
function call_conect_no_manager
{
	[[ "$1" == "" ]] && { echo "No interface defined in call_conect_no_manager"; return 1; }

	# We want to see the menu
	call_restore_stdout

	RESPONSE=
	while [[ "$RESPONSE" != [1-4] ]]
	do
		echo "1. Connect to an open network"
		echo "2. Connect to WEP network"
		echo "3. Connect to WPA network"
		echo "4. Exit"

		read RESPONSE
	done

	# Redirect back to the file.
	call_redirect_stdout

	# Exit this.
	[[ "$RESPONSE" == "4" ]] && return 0;

	# If network manager is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "NetworkManager" ]] && { call_manage_nm stop; }

	# If wicd is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "wicd" ]] && { call_manage_wicd stop; }

	# Drop the interface.
	call_manipulate_interface "$1" "down"

	# Make sure the interface is up
	call_manipulate_interface "$1" "up"

	case "$RESPONSE" in 
		1)
			# connect to open network
			call_connect_to_open $1
		;;
		2)
			# connect to wep network ifconfig
			call_connect_using_wep $1
		;;
		3)
			# connect to wpa network using wpa_supplicant
			call_connect_using_wpa2 $1	
		;;
	esac

	# If network manager is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "NetworkManager" ]] && { call_manage_nm start; }

	# If wicd is installed and running lets stop it.
	[[ "$MANAGER_INSTALLED" == "wicd" ]] && { call_manage_wicd start; }

	return 0;
}

server1-link

# Function to connect to an open network
# $1 The interface to connect on ($INTERFACE).
#
function call_connect_to_open
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_connect_to_open"; exit 1; }

	call_restore_stdout

	RESPONSE=
	while [[ "$RESPONSE" != "y" ]]
	do
		echo "Please enter the AP name"
		read AP_NAME

		[[ "$AP_NAME" == "" ]] && { echo "Invalid name"; return 1; }
	 
		echo "Name $AP_NAME. This this correct ?"
		read RESPONSE
	done

	call_redirect_stdout

	# Connect to the network.
	$("$IWCONFIG" "$1" essid "$AP_NAME" key open)

	if [[ "$?" -eq 0 ]]
	then
		# Get ip address using dchp.
		call_get_dhcp_lease "$1"
	else
	 	 echo "Could not connect to open network $SSID"; return 1;
	fi

	# Reparse the network data.
	call_reparse_network_info "$INTERFACE_NAME"; 

	# Try to check the connectivity
	call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

	return 0;
}

# Function to connect using wep encryption
# $1 The interface to connect on ($INTERFACE).
#
function call_connect_using_wep
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_connect_using_wep"; exit 1; }

	call_restore_stdout

	RESPONSE=
	while [[ "$RESPONSE" != "y" ]]
	do
		echo "Please enter the AP name"
		read AP_NAME
		echo "Please enter your passkey. This will not be stored by the script. It will just be used to connect"
		read AP_PASSKEY

		[[ "$AP_NAME" == "" || "$AP_PASSKEY" == "" ]] && { echo "Invalid name or passkey entry"; return 1; }
	 
		echo "Name $APNAME. Key $AP_PASSKEY. This this correct ?"
		read RESPONSE
	done

	call_redirect_stdout

	#Connect to the network
	$("$IWCONFIG" "$1" essid "$AP_NAME" key "$AP_PASSKEY")

	if [[ "$?" -eq 0 ]]
	then
		# Get ip address uing dchp.
		call_get_dhcp_lease "$1"
	else
	 	echo "Could not connect to WEP $SSID"; return 1;
	fi

	# Reparse the network data.
	call_reparse_network_info "$INTERFACE_NAME"; 

	# Try to check the connectivity
	call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"

	return 0;
}

# Function to connect to a network using WPA personnel bypassing managers
# Uses standard wpa_supplicant
# $1 The interface to connect on ($INTERFACE).
#
function call_connect_using_wpa2
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_connect_using_wpa2"; exit 1; }

	# Stop wpa_supplicant.
	WPA_PID=$("$PGREP" "$WPA_NAME")

	if [[ "$?" -eq 0 ]]
	then
		if [[ $WPA_PID != "" ]]
		then
			$(sudo kill -TERM "$WPA_PID")

			echo "Killed wpa_supplicant after stopping nm."
		fi
	fi

	call_restore_stdout

	RESPONSE=
	while [[ "$RESPONSE" != "y" ]]
	do
		echo "Please enter the AP name"
		read AP_NAME
		echo "Please enter your passkey. This will not be stored by the script. It will just be used to connect"
		read AP_PASSKEY

		[[ "$AP_NAME" == "" || "$AP_PASSKEY" == "" ]] && { echo "Invalid name or passkey entry"; return 1; }
	 
		echo "Name $APNAME. Key $AP_PASSKEY. This this correct ?"
		read RESPONSE
	done

	call_redirect_stdout

	# Create the key file for wpa.
	wpa_passphrase "$AP_NAME" "$AP_PASSKEY" | sed "1a key_mgmt=WPA-PSK\nscan_ssid=1" > wpa_supplicant.conf

	# Start wpa_supplicant using the generated configuration file.
	$(wpa_supplicant -c wpa_supplicant.conf -B -i "$1")

	if [[ "$?" -eq 0 ]] 
	then
		echo "Connection sucessful using wpa"
	else
		echo "Connection _unsucessful_ using wpa"
	fi

	# Clean up.
	$(rm -f wpa_supplicant.conf)

	if [[ "$?" -eq 0 ]]
	then
		# Get ip address uing dchp.
		call_get_dhcp_lease "$1"
	else
	 	echo "Could not connect via WPA"
	fi

	# Reparse the network data.
	call_reparse_network_info "$INTERFACE_NAME"; 

	# Try to check the connectivity
	call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"	

	# Stop wpa_supplicant.
	WPA_PID=$("$PGREP" "$WPA_NAME")

	if [[ "$?" -eq 0 ]]
	then
		if [[ $WPA_PID != "" ]]
		then
			$(sudo kill -TERM "$WPA_PID")

			echo "Killed wpa_supplicant"
		fi
	fi

	return 0
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################


# A function to regressively try to connect to a router
# $1 Interface
# $2 Driver name.
#
function call_try_connect_disabled_interface
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_conect_via_script"; exit 1; }

	# Try to get network manager to connect by itself.
	call_try_conect_network_manager

	if [[ "$?" -eq 0 ]]
	then
		# That got network manager back up and running.
		# Lets check connectivity.

		# Reparse the network data.
		call_reparse_network_info "$INTERFACE_NAME"; 

		# Try to check the connectivity
		call_check_connectivity true "$1" "$2" "$INTERFACE_IP"

		[[ "$?" -eq 0 ]] && { echo "Restarting the manager restored connectivity "; return 0; }
	fi

	# Try to enable the interface
	call_try_enable_interface

	[[ "$?" -eq 0 ]] && return 0

	echo "Failure. Could not restore connectivity."

	# Failure
	return 1;
}

# Function to parse the NetworkManager state file
#
function call_parse_nm_state_file
{
	[[ -f "$NM_STATE_FILE" ]] || { echo "NetworkMamager files does not exist"; return 1; }

	if [[ $("$GREP" -c "false" "$NM_STATE_FILE") != 0 ]]
	then
		# Make a backup of the file
		$("$SUDO" cp "$NM_STATE_FILE" "$NM_STATE_FILE.old")

		# Change any false values to true.
		$("$SUDO" "$SED" -i 's/false/true/g' "$NM_STATE_FILE")
		
		return 1
	fi

	return 0
}

# Function to check the interfaces file for clashes
# with NetworkManager
# $1 Interface name
#
# FIXME: This has holes. 'auto eth0 wlan0' being one example
# FIXME: Should suffice for most instances though, so i wont
# worry too much at the moment.
#
function call_check_interfaces_file
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_check_interfaces_file"; exit 1; }

	# FIXME: This is limited to DHCP only at the moment.
	# FIXME: NEED TO CHECK IF THE IP ADDRESS IS STATIC OR NOT.

	# If the interface is disabled then see if we can bring the interface up.
	CHUNK=$(cat "$INTERFACES_FILE")

	# Set when we have found the interface
	FOUND_INTERFACE="0"

	# Does the file contain a reference to our disabled interface ?	
	if [[ "$CHUNK" =~ $1 ]]
	then
		# Make a backup of the file.
		$("$SUDO" mv "$INTERFACES_FILE" "$INTERFACES_FILE".bk)

		# Loop over all the lines in the file.
		while read LINE 
		do
			# Search for interface in the line.
			if [[ "$FOUND_INTERFACE" == "0" && "$LINE" =~ $1 ]]
			then
				# Flag that we have found the interface.
				FOUND_INTERFACE="1"

				# Miss this iteration.
				continue

			elif [[ "$FOUND_INTERFACE" == "1" ]]
			then	
				[[ "$LINE" =~ $1 ]] && continue

				if [[ "$LINE" =~ iface  || "$LINE" =~ auto ]]
				then
					# Don't want to perform regex matching any more.
					# Any more references to the interface in this file
					# and the file is malformed anyway
					FOUND_INTERFACE="2"
				else
					continue
				fi
			fi

			# Add to the file.
			echo "$LINE" >> "$INTERFACES_FILE"

		done < <(echo "$CHUNK")

		return 1
	fi
	
	return 0;
}

# Function to restart the networking service
#
function call_restart_networking
{
	"$SUDO" "$NETWORKING_PATH" restart

	[[ "$?" -eq 0 ]] || { echo "Could not restart networking"; return 1; }

	return 0;
}

# Function to drop and raise an interface
# $1 Interface name
#
function call_down_up_interface
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_down_up_interface"; exit 1; }

	echo "Dropping and raising interface $1"

	call_manipulate_interface "$1" "down"

	[[ "$?" -eq 0 ]] || { return 1; }

	call_manipulate_interface "$1" "up"

	[[ "$?" -eq 0 ]] || { return 1; }

	echo "Dropped and raised interface $1 sucessfully"

	# Success
	return 0;
}

# Function to drop or raise an interface 
# $1 Interface
# $2 Operation to perform
#
function call_manipulate_interface
{
	# Sanity  check
	[[ "$1" == "" || "$2" == "" ]] && { echo "DEBUG: Interface value null in call_manipulate_interface"; exit 1; }

	$("$SUDO" "$IFCONFIG" "$1" "$2")

	[[ "$?" -eq 0 ]] || { echo "Could not "$2" interface $1"; return 1; }

	echo "$2 interface $1 sucessfully"

	return 0;
}

# Function to remove and reload the kernel modules.
# $1 The module name
#
function call_reload_drivers
{
	# Sanity  check
	[[ "$1" == "" ]] && { echo "DEBUG: Interface value null in call_reload_drivers"; exit 1; }

	echo "Reloading driver $1"
	echo

	# Unload the driver
	$("$SUDO" "$MODPROBE" -r "$1")

	[[ "$?" -eq 0 ]] || { echo "Could not unload $1"; return 1; }

	# Reload the driver
	$("$SUDO" "$MODPROBE" "$1")

	[[ "$?" -eq 0 ]] || { echo "Could not reload $1"; return 1; }

	echo "Reloaded driver $1 sucessfully"

	# Sucess
	return 0;
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to check if network manager is connected
# matthew@matthew-laptop:~/my_documents/collaborative_scripts$ nm-tool | grep State
# State: connected
#  State:             unavailable
#  State:             connected
# matthew@matthew-laptop:~/my_documents/collaborative_scripts$ nm-tool | grep State
# State: disconnected
#  State:             unavailable
#  State:             disconnected
# matthew@matthew-laptop:~/my_documents/collaborative_scripts$ nm-tool | grep State
# State: connecting
#  State:             unavailable
#  State:             connecting (configuring)
#
# matthew@matthew-laptop:~/my_documents/collaborative_scripts$ 
#
function call_get_is_connected
{
	# Check to see if we are connected.
	[[ $(nm-tool | grep State | cut -f2 -d' ') == "connected" ]] && return 0

	# We are not connected.
	return 1;
}

#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################
#####################################################################################################################################################################################

# Function to get the lshw info
#
function call_get_and_parse_lshw_info
{
	# Get the network hardware details.
	LSHW_RES=$("$SUDO" "$LSHW" -C Network) 2> /dev/null

	[[ "$?" -ne 0 ]] && { echo "Could not get lshw network information for parsing"; return 1; }

	# Make a temporary copy of lshw for the network section.
	CHUNK=${LSHW_RES#*-network}

	# At the start of the loop for the very unlightly event there are no adaptors ;)
	if [[ $CHUNK =~ -network ]]
	then
		# Loop over getting the name of the adaptors. 
		# This is to allow the user to pick an adaptor to check.
		while :
		do
			# Get the first network stanza for parsing.
			TEMP_CHUNK=${CHUNK%%-network*}

			# If the item has no product name then it is a virtual adaptor.
			# Ignore these at the moment.
			if [[ "$TEMP_CHUNK" =~ "product:" ]] 
			then
				# Looking for the product name
				ADAPTOR_NAME=${TEMP_CHUNK#*product: }

				# Get the product name.
				ADAPTOR_NAME=${ADAPTOR_NAME%%$'\n'*}
	
				# Add the adaptor to the array of adaptors.
				ADAPTOR_NAMES+=("$ADAPTOR_NAME")

				# Get the interface type.
				INTERFACE_TYPE=${TEMP_CHUNK#*description: }
				INTERFACE_TYPE=${INTERFACE_TYPE%%$'\n'*}
				INTERFACE_TYPES+=("$INTERFACE_TYPE")

				# Check to see if the interface is UNCLAIMED.
				INTERFACE_STATE=${TEMP_CHUNK%Network controller*}
				INTERFACE_STATE=${INTERFACE_STATE#*-network }
				INTERFACE_STATE=${INTERFACE_STATE%%$'\n'*}

				if [[ "$INTERFACE_STATE" =~ "UNCLAIMED" ]]
				then
					# Unclaimed interface. Bail out of this iteration as we can get no more useful info here.
					INTERFACE_STATES+=("$INTERFACE_STATE"); 
				else
					# Next let's check to see if we are DISABLED.
					INTERFACE_STATE=${TEMP_CHUNK%Wireless interface*}
					INTERFACE_STATE=${INTERFACE_STATE#*-network }
					INTERFACE_STATE=${INTERFACE_STATE%% *}

					INTERFACE_STATES+=("$INTERFACE_STATE")

					if [[ "$TEMP_CHUNK" =~ "logical name" ]]
					then
						# Get the wireless interface name.
						INTERFACE_NAME=${TEMP_CHUNK#*logical name: }
						INTERFACE_NAME=${INTERFACE_NAME%%$'\n'*}
					else
						INTERFACE_NAME=
					fi

					INTERFACE_NAMES+=("$INTERFACE_NAME")

					if [[ "$TEMP_CHUNK" =~ driver= ]]
					then
						# Get the driver name
						INTERFACE_DRIVER=${TEMP_CHUNK#*driver=}
						INTERFACE_DRIVER=${INTERFACE_DRIVER%% *}
					else
						INTERFACE_DRIVER=
					fi

					INTERFACE_DRIVERS+=("$INTERFACE_DRIVER")

					if [[ "$TEMP_CHUNK" =~ ip= ]]
					then
						# Get the IP address
						INTERFACE_IP=${TEMP_CHUNK#*ip=}
						INTERFACE_IP=${INTERFACE_IP%% *}
					else
						INTERFACE_IP=
					fi

					INTERFACE_IPS+=("$INTERFACE_IP")
				fi
			fi

			# Check to see if we need to break out of the loop.
			# The terminating condition is a simple regex pattern match not existing.
			[[ $CHUNK =~ -network ]] || break

			# then chop it off the rest of our search for the next iteration.
			CHUNK=${CHUNK#*-network}
		done
	fi

	return 0;
}

# This function gets the user to select an adaptor
#
function call_select_adaptor
{
	COUNTER=

	# Loop over getting the users input.
	while :
	do
		clear
		echo "Please select an adaptor to check"
		echo
		COUNTER=1
		
		for ADAPTOR_NAME in "${ADAPTOR_NAMES[@]}"
		do
			echo "$COUNTER. $ADAPTOR_NAME"

			((COUNTER+=1))
		done
		
		echo "$COUNTER. Exit"
		
		# Get user input
		read RESPONSE

		# Is input valid ? "$COUNTER"
		[[ "$RESPONSE" == [1-"$COUNTER"] ]] && break
	done

	# Bail out early if required.
	[[ "$RESPONSE" == "$COUNTER" ]] && exit 0
	
	# Decrement as arrays are zero based indices.
	((RESPONSE-=1))

	# Set up the variables.
	ADAPTOR_NAME="${ADAPTOR_NAMES[${RESPONSE}]}"
	INTERFACE_STATE="${INTERFACE_STATES[${RESPONSE}]}"
	INTERFACE_NAME="${INTERFACE_NAMES[${RESPONSE}]}"
	INTERFACE_DRIVER="${INTERFACE_DRIVERS[${RESPONSE}]}"
	INTERFACE_IP="${INTERFACE_IPS[${RESPONSE}]}"
	INTERFACE_TYPE="${INTERFACE_TYPES[${RESPONSE}]}"

	return 0
}

MAIN_MENU_OPTION="6"

# Function to parse the command line for parameters
# $1 Command line args. CAN BE EMPTY.
#
function call_parse_command_line
{
	# Move passed the first argument
	VERBOSE_CONNECTIVITY_CHECKING="$QUIET"

	# Loop over the command line arguments.
	for ARG in "$1"
	do
		if [[ "${ARG}" == "--verbose" ]] 
		then
			# Set mode to verbose
			VERBOSE_CONNECTIVITY_CHECKING="$VERBOSE"
		elif [[ "${ARG}" == "--status-only" ]] 
		then
			# Set mode to verbose
			MAIN_MENU_OPTION="1"

		elif [[ "${ARG}" == "--status-single-con" ]] 
		then
			# Set mode to verbose
			MAIN_MENU_OPTION="2"

		elif [[ "${ARG}" == "--status-multi-con" ]] 
		then
			# Set mode to verbose
			MAIN_MENU_OPTION="3"
		elif [[ "${ARG}" == "--status-try-connect" ]] 
		then
			# Set mode to verbose
			MAIN_MENU_OPTION="4"
		elif [[ "${ARG}" == "--status-try-connect-no-manager" ]] 
		then
			# Set mode to verbose
			MAIN_MENU_OPTION="5"
		elif [[ "${ARG}" == "--help" ]]
		then
			call_help

			exit 0
		elif [[ "${ARG}" == "--help-summary" ]]
		then
			call_display_summary_help
			
			exit 0
		elif [[ "${ARG}" == "--help-extended" ]]
		then
			call_display_summary_help

			call_display_extended_help

			exit 0
		elif [[ x"${ARG}" != x ]]
		then
			echo "Invalid command line option ${ARG}"

			exit 1
		fi
	done

	return 0;
} 

# Function to start it all off
# $1 Command line arguments. CAN BE EMPTY.
#
function call_start
{
	# clear the terminal screen.
	clear

	# Parse the command line for user options.
	call_parse_command_line "$1"

	# Let the user know we are doing something
	echo "Performing initial enviroment checks....."

	# Delete any old file we many have
	$(rm -rf wireless-results.txt)

	# First things first. We neeed to be running with root privilages. 
	call_check_root_privilages

	# Initialise the script
	call_initialise

	# is rfkill installed
	call_rfkill_check
	 
	# Get the lswh
	call_get_and_parse_lshw_info

	# Get the user to select an adaptor to test.
	call_select_adaptor

	# Tell the user to be patisent.
	# If they are smart they will put the kettle on at this point.
	echo "Please be patient. Depending on your setup this could take some time..."

	# redirect stdout
	call_redirect_stdout

	# Open code blocks for the forums.
	echo "[code]"

	# Initial log entries.
	echo "Version: $VERSION (Development)"
	echo $($DATE_FN)
	echo

	# Check to see what networking services are running.
	call_check_for_connection_managers

	# At the the start get the full system information
	call_get_full_system_info "$INTERFACE_NAME"

	case "$MAIN_MENU_OPTION" in
		2)
			# Did the last call fail for some reason ?
			[[ "$?" -eq 0 ]] && call_check_connectivity false "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"
		;;
		3)
			# Did the last call fail for some reason ?
			[[ "$?" -eq 0 ]] && call_check_connectivity true "$INTERFACE_NAME" "$INTERFACE_DRIVER" "$INTERFACE_IP"
		;;
		4)
			# Try to connect regresssively.
			[[ "$?" -eq 0 ]] && call_try_connect_disabled_interface "$INTERFACE_NAME" "$INTERFACE_DRIVER"
		;;
		5)
			# Try to connect regresssively.
			call_conect_no_manager "$INTERFACE_NAME" "$INTERFACE_DRIVER"
		;;
		6)
			# Try to connect regresssively.
			call_intelligent_diagnostics "$INTERFACE_NAME" "$INTERFACE_DRIVER"
		;;
	esac

	# Finished
	echo "Finished <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"

	# Cleanup any mess we may have left.
	call_cleanup

	echo "http://wireless.kernel.org/en/users/Drivers"

	# Close code blocks for the forums.
	echo "[/code]"

	#restore stdout
	call_restore_stdout

	echo "probe complete...please see 'wireless-results.txt'"
}

# Function to clean up, delete files etc
#
function call_cleanup
{
	echo
}

#####################################################################################################
########################### The meat and two veg ;) #################################################
#####################################################################################################

# Kick it all off.
call_start "$@"
