#!/bin/bash
#

# usage()
#  Displays usage message to the user. If run with no arguments, we call this
#  and exit. Also called later in the script if there are incorrect arguments.
usage() {
    cat <<EOF
Usage:
    $0 enable wpa_tkip <SSID> <FREQ> <PSK>
    $0 enable wep <SSID> <FREQ> <PSK>
    $0 enable unsecured <SSID> <FREQ>
    $0 disable

Enables or disables adhoc mode for a session. Parameters are as follows:
    <SSID> - the identifier of the other adhoc system
    <FREQ> - initial frequency (e.g. 2462)
    <PSK> - pre-shared key (the passphrase or hex key). IMPORTANT: if this is
            a hex key, just pass it as-is. If it is a passphrase (which is more
            common, especially with WPA) then you need to quote it and escape
            the quotes from the shell. For example, type it as '"My passphrase"'
            on the shell commandline.

Once enabled, the following commands are useful:
    wpa_cli list_networks
    wpa_cli select_network <n>
    wpa_cli status
    iwconfig wlan0

You should disable the ad-hoc mode once you're finished to avoid leaving the
ad-hoc parameters in the system configuration file.
EOF
}

if [ $# -eq 0 ]
then
    usage
    exit 0
fi



# Test for configuration file
wpa_supplicant_cf="/etc/network/wlan0/wpa_supplicant.conf"
if [ \! -r "${wpa_supplicant_cf}" ]
then
    echo "Cannot read configuration file (${wpa_supplicant_cf})."
    exit 1
fi
new_cf="${wpa_supplicant_cf}.new"



# filter_out_adhoc()
#  Filters out any network block with an id_str of "xxx-adhoc". Can be used to
#  remove the adhoc configuration from the wpa_supplicant configuration.
#    stdin: config file
#    stdout: config file without xxx-adhoc block
filter_out_adhoc() {
    local line in_netblock blockpos i is_adhoc
    declare -a block_lines

    in_netblock=0
    while read -r line
    do
        if [ "${in_netblock}" -eq 0 ]
        then
            if [ "${line}" == "network={" ]
            then
                in_netblock=1
                blockpos=0
                is_adhoc=0
            else
                echo "${line}"
            fi
        else
            if [ "${line}" == "}" ]
            then
                in_netblock=0
                [ $is_adhoc -ne 0 ] && continue

                i=0
                echo "network={"
                while [ $i -lt $blockpos ]
                do
                    echo "	${block_lines[$i]}"
                    ((++i))
                done
                echo "}"
            else
                block_lines[((blockpos++))]="${line}"
                if [ "${line}" == 'id_str="xxx-adhoc"' ]
                then
                    is_adhoc=1
                fi
            fi
        fi
    done
}



# new_cf_no_adhoc()
#  Creates the file ${new_cf}, without any form of adhoc mode in it.
new_cf_no_adhoc() {
    cat "${wpa_supplicant_cf}" \
        | grep -v "^ap_scan=" \
        | filter_out_adhoc \
    > "${new_cf}"
}



# check_param()
#  Tests that the parameter is set, and echoes it; if not, prints error message
#  and usage and exits.
check_param() {
    if [ -z "$2" ]
    then
        echo "Parameter <$1> not specified."
        usage
        exit 1
    fi
    echo "$2"
}


# enable_wpa_tkip()
enable_wpa_tkip() {
    ssid="$(check_param SSID "$1")"
    freq="$(check_param FREQ "$2")"
    psk="$(check_param PSK "$3")"

    new_cf_no_adhoc
    cat > "${wpa_supplicant_cf}" <<EOF
ap_scan=2
$(cat "${new_cf}")
network={
    id_str="xxx-adhoc"
    ssid="${ssid}"
    frequency=${freq}
    mode=1
    key_mgmt=WPA-NONE
    proto=WPA
    pairwise=NONE
    group=TKIP
    psk=${psk}
}
EOF
    rm "${new_cf}"
}



# enable_wep()
enable_wep() {
    ssid="$(check_param SSID "$1")"
    freq="$(check_param FREQ "$2")"
    psk="$(check_param PSK "$3")"

    new_cf_no_adhoc
    cat > "${wpa_supplicant_cf}" <<EOF
ap_scan=2
$(cat "${new_cf}")
network={
    id_str="xxx-adhoc"
    ssid="${ssid}"
    frequency=${freq}
    mode=1
    key_mgmt=NONE
    wep_key0=${psk}
    wep_tx_keyidx=0
}
EOF
    rm "${new_cf}"
}



# enable_unsecured()
enable_unsecured() {
    ssid="$(check_param SSID "$1")"
    freq="$(check_param FREQ "$2")"

    new_cf_no_adhoc
    cat > "${wpa_supplicant_cf}" <<EOF
ap_scan=2
$(cat "${new_cf}")
network={
    id_str="xxx-adhoc"
    ssid="${ssid}"
    frequency=${freq}
    mode=1
    key_mgmt=NONE
}
EOF
    rm "${new_cf}"
}


# main script body
#
if [ "$1" == "enable" ]
then
    if [ "$2" == "wpa_tkip" ]
    then
        enable_wpa_tkip "$3" "$4" "$5"
    elif [ "$2" == "wep" ]
    then
        enable_wep "$3" "$4" "$5"

    elif [ "$2" == "unsecured" ]
    then
        enable_unsecured "$3" "$4"

    else
        echo "Unknown security mode '$2'."
        usage
        exit 1
    fi

    wpa_cli reconfigure
    wpa_cli list_networks
    echo "Adhoc configuration updated. Select your network with the command"
    echo "'wpa_cli select_network <n>'."

elif [ "$1" == "disable" ]
then
    echo "Disabling adhoc mode."
    new_cf_no_adhoc
    mv "${new_cf}" "${wpa_supplicant_cf}"
    wpa_cli reconfigure

else
    echo "Unrecognised option '$1'."
    usage
    exit 1
fi


# vim: ts=4:sw=4:expandtab
