#!/bin/ash

#
# App : AutoDisconnect
# Url : https://garage.maemo.org/projects/autodisconnect/
# Version: 0.4.8
# Author: Aymeric Brisse <aymeric.brisse@gmail.com>
# License: GNU General Public License
#

# ---------------------------------------------------------------------------
# FUNCTIONS
# ---------------------------------------------------------------------------

GC_ROOT="/apps/autodisconnect"

# ---------------------------------------------------------------------------
getvalue()
# ---------------------------------------------------------------------------
# Get Conf value
#
{
    echo "`gconftool-2 -g $GC_ROOT/param_$1`"
}

# ---------------------------------------------------------------------------
read_parameters()
# ---------------------------------------------------------------------------
# Read general parameters
#
{
    # Enable logging
    g_logging=true

    # Notifications
    g_notifications=`getvalue "notifications"`

    # Exceptions (SSH)
    g_exceptions=""
    [[ `getvalue "exception_ssh"` = true ]] && g_exceptions="ssh $g_exceptions"

    # Exceptions (OpenVPN)
    g_exception_openvpn=`getvalue "exception_openvpn"`

    # Exceptions (Hotspot)
    g_exception_hotspot=`getvalue "exception_hotspot"`

    # Exceptions (VoIP)
    g_exception_voip=`getvalue "exception_voip"`

    # Exceptions (IM Accounts)
    g_exception_im_accounts=`getvalue "exception_im_accounts"`

    # Network Interfaces to check
    g_enable=""
    [[ `getvalue "connection_wlan"` = true ]] && g_enable="wlan $g_enable"
    [[ `getvalue "connection_gprs"` = true ]] && g_enable="gprs $g_enable"

    # Where to store the logfile. This is cleared when it goes over 50k.
    logfile=/var/log/autodisconnect.log
}

# ---------------------------------------------------------------------------
read_connection_parameters()
# ---------------------------------------------------------------------------
# Read connection specific parameters
#
{
    # How often to test for inactivity (min)
    g_samplerate=`getvalue $short_interface"_interval"`

    # Grace Period (sec)
    g_pre_interval=`getvalue $short_interface"_pre_interval"`

    # Number of bytes allowed to be received without disconnect
    g_dontcountbytespermin=`getvalue $short_interface"_traffic"`
    
    # Number of bytes to ignore for each time period
    g_dontcountbytes=$((g_dontcountbytespermin*g_samplerate))

    # Convert min interval to sec interval
    g_samplerate=$((g_samplerate*60))
}

# ---------------------------------------------------------------------------
killsiblings()
# ---------------------------------------------------------------------------
# Kill other instances of the process
#
{
    TmpFile=/tmp/$(basename $0).tmp

    `ps | egrep 'S[ ]*/bin/ash[ ]*/opt/autodisconnect/autodisconnect-network' | sed 's/^[ ]*\([0-9]*\) .*$/\1/g' > $TmpFile`

    while read Pid
    do
        [[ -n "$Pid" -a "$Pid" -ne "$$" ]] && {
            logentry "<Kill $Pid>"
            kill -KILL $Pid 2>/dev/null
        }
    done < $TmpFile
}

# ---------------------------------------------------------------------------
init()
# ---------------------------------------------------------------------------
{
    # Don't let log file get too big
    if [[ -w "$logfile" ]]; then
        size=`stat $logfile | grep Size | awk '{ print $2; }'`
        [[ "$size" -gt 50000 ]] && :>$logfile
    fi

    # Log
    logentry "<if-up-start>"  

    # Kill every instances already running
    killsiblings

    # Allow dbus to work
    [[ -e /tmp/dbus-info ]] && eval `cat /tmp/dbus-info`

    export DBUS_SESSION_BUS_ADDRESS \
           DBUS_SESSION_BUS_PID \
           DBUS_SESSION_BUS_WINDOWID    
}

# ---------------------------------------------------------------------------
logentry()
# ---------------------------------------------------------------------------
# Send a string to this function to append it to the log file
#
# Arg 1 - The text to log
{
    [[ "$g_logging" = true ]] && {
        echo -e "[`date +%T`][$$][$interface] $1" >> $logfile
    }
}

# ---------------------------------------------------------------------------
osnotify()
# ---------------------------------------------------------------------------
# Send a string to this function to generate a system popup
#
# Arg 1 - The text to display
{
    [[ "$g_notifications" = true ]] && {
        /usr/bin/dbus-send --type=method_call \
            --dest=org.freedesktop.Notifications \
            /org/freedesktop/Notifications \
            org.freedesktop.Notifications.SystemNoteInfoprint \
            string:"$1"
    }
}

# ---------------------------------------------------------------------------
disconnect()
# ---------------------------------------------------------------------------
# Disconnect current connection
{   
    dbus-send --system --dest=com.nokia.icd \
        /com/nokia/icd_ui \
        com.nokia.icd_ui.disconnect \
        boolean:true
}

# ---------------------------------------------------------------------------
isrunning()
# ---------------------------------------------------------------------------
# Check if a process is running
#
# Arg 1 - the service
{
	test -n "`ps | grep "$1" | grep -v grep`"
}

# ---------------------------------------------------------------------------
disable_quit()
# ---------------------------------------------------------------------------
# Disabled for some interfaces
#
{
    connection_check=`echo "$g_enable" | grep "$short_interface" 2>/dev/null`
    
    if [[ -n "$short_interface" -a -n "$connection_check" ]]; then        
        osnotify "AutoDisconnect is now monitoring your $display_interface connection"
        logentry "interface started"
        false
    else
        logentry "interface ignored"
        true
    fi
}

# ---------------------------------------------------------------------------
read_full_network_interface()
# ---------------------------------------------------------------------------
# Read the full connection interface name (ie the last digit, as gprs<0>)
#
# No args
{
    network_interface="`grep $short_interface /proc/net/route | tail -1 | cut -f1`"
    logentry "network interface identified as $network_interface"
}

# ---------------------------------------------------------------------------
connection_is_closed()
# ---------------------------------------------------------------------------
# Check if the connection has been closed
#
# No args
{
    interface_check="`grep $network_interface /proc/net/route | tail -1 | cut -f1`"

    if [[ -z "$interface_check" ]]; then
        logentry "interface closed (externally)"
        true
    else
        false
    fi
}

# ---------------------------------------------------------------------------
main()
# ---------------------------------------------------------------------------
# Main entry point
#
{
    # Read general parameters
    read_parameters

    # Get interface (IPV6 Support)
    interface="$ICD_CONNECTION_TYPE"
    short_interface="`echo $interface | awk -F"_" '{print tolower(substr($1,0,4))}'`"

    if [[ "$short_interface" = "wlan" ]]; then
        display_interface="Wifi"
    else
        display_interface="GPRS"
    fi

    # Init -> Kill other instances & dbus & log
    init

    # Quit if the interface doesn't have to be checked
    if `disable_quit`; then
        return 0
    fi

    # Read connection specific parameters
    read_connection_parameters
    
    # Waiting for possible closing connections
    # Waiting for initial traffic to be made -> then the next check will close the connection if idle
    sleep $g_pre_interval

    # Get the full network interface
    read_full_network_interface

    # Quit if the interface has been closed
    if `connection_is_closed`; then
        return 0
    fi
    
    packets_before="`grep $network_interface /proc/net/dev | awk -F":" '{print $2}' | awk '{print $1}'`"
    
    # MONITORING LOOP
    while true
    do
        sleep $g_samplerate

        # Check if connection is still alive
        if `connection_is_closed`; then
            break
        fi

        exception_apply=""

        # Running options
        # -------------------------------------
        # 0 : never
        # 1 : always
        # 2 : when not charging
        # 3 : when locked
        # 4 : when not charging AND locked

        # Check if the phone is charging
        if [[ "$g_running_options" = 2 -o "$g_running_options" = 4 ]]; then
            if [[ "`lshal -u '/org/freedesktop/Hal/devices/bme' | grep battery.rechargeable.is_charging | awk '{print $3}'`" = true ]]; then
                exception_apply="phone_charging"
            fi
        fi

        # Check if the phone is locked
        if [[ "$g_running_options" = 3 -o "$g_running_options" = 4 ]]; then
            if [[ -n "`dbus-send --system --print-reply --type=method_call --dest=com.nokia.mce /com/nokia/mce/request com.nokia.mce.request.get_tklock_mode | tail -n 1 | grep unlocked`" ]]; then
                exception_apply="phone_unlocked"
            fi
        fi

        # Check if no exception service is running
        if [[ -z "$exception_apply" -a -n "$g_exceptions" ]]; then
            my_ip="`ifconfig "$network_interface" | grep "inet addr" | sed 's/^[ ]*inet addr:\([0-9\.]*\) .*$/\1/g'`"
            for exception in $g_exceptions ; do
                [[ -n "`netstat | grep :$exception | grep ESTABLISHED | grep $my_ip`" ]] && {
                    exception_apply="$exception"
                    break
                }
            done
        fi

        # Check if OpenVPN is not active
        if [[ -z "$exception_apply" -a "$g_exception_openvpn" = true -a -n "`grep -E \"tun|tap\" /proc/net/route`" ]]; then
            exception_apply="openvpn"
        fi

        # Check if VoIP is not active

        if [[ -z "$exception_apply" -a "$g_exception_voip" = true ]] && `isrunning "/usr/lib/telepathy/telepathy-sofiasip"`; then
            exception_apply="voip"
        fi

        # Check if hotspot/dns is not active (using WLAN interface)

        if [[ -z "$exception_apply" -a "$g_exception_hotspot" = true ]] && `isrunning "/usr/sbin/dnsmasq -i wlan0"`; then
            exception_apply="hotspot"
        fi

        # Check if an IM Account is active (XMMP or Skype or Pidgin)

        if [[ -z "$exception_apply" -a "$g_exception_im_accounts" = true ]] && \
        (`isrunning "/usr/lib/telepathy/telepathy-gabble"` || `isrunning "/usr/lib/telepathy/telepathy-spirit"` || `isrunning "/usr/lib/telepathy/telepathy-haze"`); then
            exception_apply="im_account"
        fi

        # Log exception

        if [[ -n "$exception_apply" ]]; then
            logentry "interface checked ($exception_apply)"
            continue
        fi
        
        # Check the traffic volume
        packets_after="`grep $network_interface /proc/net/dev | awk -F":" '{print $2}' | awk '{print $1}'`"

        if [[ `echo "$packets_after<$packets_before+$g_dontcountbytes" | bc` -eq 1 ]]; then
            osnotify "AutoDisconnect has closed your $display_interface connection (inactive)"
            logentry "interface closed (inactive) [+`echo "$packets_after-$packets_before" | bc`]"        
            disconnect            
            break
        else            
            logentry "interface checked [+`echo "$packets_after-$packets_before" | bc`]"
            packets_before=$packets_after   
        fi

    done
    
}

# ---------------------------------------------------------------------------
# RUNTIME
# ---------------------------------------------------------------------------

# Start AutoDisconnect

g_running_options=`getvalue "running_options"`

if [[ "$g_running_options" != 0 ]]; then
    main
    logentry "<if-up-stop>"
fi

exit 0

