#!/bin/sh
# iTalc client launcher using avahi
# Written by Stéphane Graber <stgraber@ubuntu.com>

find_free_port() {
# $1 = requested port
# $2 = sorted list of ports in use
# Basic logic: if the distance between two used ports A and B is greater than 1,
# then port A+1 is free.
    req_port=$1
    used_ports="$2 65536"
    candidate=$req_port
    for p in $used_ports
    do
        if [ $p -lt $req_port ]
        then # Pass the ports lower than the requested one
            continue
        elif [ $p -gt $candidate ]
        then
            echo $candidate
            return 0
        else
            candidate=$(($p+1))
        fi
    done
    return 1
}

ICA_LTSP=`xprop -root ica_ltsp | sed 's/^.* //' 2> /dev/null`
if [ "$ICA_LTSP" = "1" ]
then
    echo "ICA already running on the thin client."
    exit 0
fi

CONFIGFILE="/etc/italc/italc.conf"

# Provide a configuration file to enable switching off client autodetection
# and/or specifying user-defined ports.
if [ -f "$CONFIGFILE" ]
then
    . $CONFIGFILE
fi

AVAHIPUBLISHSERVICE="/usr/bin/avahi-publish-service"

PUBLISH_CLIENT=${PUBLISH_CLIENT:-True}

# Set default ports
ISDPORTDEF=${ISDPORT:-5800}
IVSPORTDEF=${IVSPORT:-5900}

HOSTNAME=`hostname`
MD5_3=`md5sum /etc/italc/keys/public/teacher/key 2> /dev/null | awk '{print \$1}'`
MD5_2=`md5sum /etc/italc/keys/public/admin/key 2> /dev/null | awk '{print \$1}'`
MD5_1=`md5sum /etc/italc/keys/public/supporter/key 2> /dev/null | awk '{print \$1}'`

if [ -n "$1" ]; then
    ROLE=$1
else
    ROLE="other"
fi

# Get session number
SESSION=`echo $DISPLAY | sed -r 's/^.*:([0-9]+)(|[^0-9].*)$/\1/'`

if [ -n "$LTSP_CLIENT" ]
then
    echo LTSP environement detected
    PORT=`echo $LTSP_CLIENT | awk -F . '{print \$4}'`
# Not much point in using the ports from /etc/italc/italc.conf for thin clients
    ISDPORT=$((($SESSION * 2 + 11) * 1000 + $PORT))
    IVSPORT=$((($SESSION * 2 + 10) * 1000 + $PORT))
    HOSTNAME=${LTSP_CLIENT_HOSTNAME:-$HOSTNAME}
else
    ISDPORT=$(($ISDPORTDEF + $SESSION))
    IVSPORT=$(($IVSPORTDEF + $SESSION))
fi

# Create script for awk
# First pattern
AWKSCRIPT='($1 ~ /^[0-9]+$/)'

# Add pattern for -isdport
AWKSCRIPT="$AWKSCRIPT"' && (/[[:space:]]-isdport[[:space:]]+'$ISDPORT'([[:space:]]|$)/'
if [ "$ISDPORT" = "$ISDPORTDEF" ];
then
AWKSCRIPT="$AWKSCRIPT"' || ! /[[:space:]]-isdport[[:space:]]/'
fi
AWKSCRIPT="$AWKSCRIPT"')'

# Add pattern for -ivsport and -rfbport
AWKSCRIPT="$AWKSCRIPT"' && (/[[:space:]]-(ivs|rfb)port[[:space:]]+'$IVSPORT'([[:space:]]|$)/'
if [ "$IVSPORT" = "$IVSPORTDEF" ];
then
AWKSCRIPT="$AWKSCRIPT"' || ! /[[:space:]]-(ivs|rfb)port[[:space:]]/'
fi
AWKSCRIPT="$AWKSCRIPT"')'

# Add action: print PID only
AWKSCRIPT="$AWKSCRIPT"' {print $1}'

RUNNING_ICA=`ps -C ica -o pid,command | gawk --source "$AWKSCRIPT" | sort -bg`
if [ -n "$RUNNING_ICA" ]
then
    for processus in $RUNNING_ICA
    do
        kill $processus
    done
    echo ICA already running, killing it.
    sleep 1s
fi

USED_PORTS=$(netstat -nap 2>/dev/null | grep -v TIME_WAIT | sed -n 's/unix[^0-9]*[0-9]*[^0-9]*\([0-9]*\).*/\1/p;s/tcp[^:]*:\([0-9]*\).*/\1/p;s/udp[^:]*:\([0-9]*\).*/\1/p' | sort -n)
ISDPORT=`find_free_port $ISDPORT "$USED_PORTS"`
USED_PORTS=$(echo "$USED_PORTS
$ISDPORT" | sort -n)
IVSPORT=`find_free_port $IVSPORT "$USED_PORTS"`

if [ "$PUBLISH_CLIENT" = "True" ] && [ -f $AVAHIPUBLISHSERVICE ] && [ ! -f /etc/ltsp/getltscfg-cluster.conf ]
then
    echo Announce the service on avahi
    $AVAHIPUBLISHSERVICE "italc $USER" _italc._tcp $IVSPORT $MD5_1 $MD5_2 $MD5_3 "$HOSTNAME" > /dev/null &
fi

echo Starting ICA
# Store the port in an xprop, for italc-launcher to find it
xprop -root -f ICA_PORT 16c -set ICA_PORT $ISDPORT
ica -noshm -isdport $ISDPORT -ivsport $IVSPORT -role $ROLE 2> /dev/null
xprop -root -remove ICA_PORT

if [ "$PUBLISH_CLIENT" = "True" ] [ -f $AVAHIPUBLISHSERVICE ] && [ ! -f /etc/ltsp/getltscfg-cluster.conf ]
then
    echo Stopping avahi
    kill `ps -C "avahi-publish-service italc $USER _italc._tcp $IVSPORT" -o pid=`
fi
