Scan for and connect to networks from an openbox pipe menu

wireless.jpg

Source

So the other day when i was using wifi-select (awesome tool) to connect to a friends hot-spot, i realized “hey! this would be great as an openbox pipe menu.”  i’m fairly decent in bash and i knew both netcfg and wifi-select were in bash so why not rewrite it that way?

Screenshots

Here’s some screens to show what this does:

Click for larger

Showing the pipe menu

Asking for the a key

Asking for the a key

Showing a key failing

Showing a key failing

Trying to connect to a network you're already connected to

Trying to connect to a network you're already connected to

Wifi-Pipe

A simplified version of wifi-select which will scan for networks and populate an openbox right-click menu item with available networks.  displays security type and signal strength.  click on a network to connect via netcfg the same way wifi-select does it.

zenity is used to ask for a password and notify of a bad connection.  one can optionally remove the netcfg profile if the connection fails.

What’s needed

– you have to be using netcfg to manage your wireless
– you have to install zenity
– you have to save the script as ~/.config/openbox/wifi-pipe and make it executable:

chmod +x ~/.config/openbox/wifi-pipe

– you have to add a sudoers entry to allow passwordless sudo on this script and netcfg (!)

USERNAME ALL=(ALL) NOPASSWD: /usr/bin/netcfg
USERNAME ALL=(ALL) NOPASSWD: /home/USERNAME/.config/openbox/wifi-pipe

– you have to adjust  ~/.config/openbox/menu.xml like so:

<menu id="root-menu" label="Openbox 3">
  <menu id="pipe-wifi" label="Wifi" execute="sudo /home/USERNAME/.config/openbox/wifi-pipe INTERFACE" />
  <menu id="term-menu"/>
  <item label="Run...">
    <action name="Execute">
      <command>gmrun</command>
    </action>
  </item>
...

where USERNAME is you and INTERFACE is probably wlan0 or similar

openbox –reconfigure and you should be good to go.

The Script:

#!/bin/bash
#
# pbrisbin 2009
#
# simplified version of wifi-select designed to output as an openbox pipe menu
#
# required:
#   netcfg
#   zenity
#   NOPASSWD entries for this and netcfg through visudo
#
#   the following in menu.xml:
#     <menu id="pipe-wifi" label="Wifi" execute="sudo /path/to/wifi-pipe interface"/>
#
# the idea is to run this script once to scan/print, then again immediately to connect.
# therefore, if you scan but don't connect, a temp file is left in /tmp. the next scan
# will overwrite it, and the next connect will remove it.
#
###

# source this to get PROFILE_DIR and SUBR_DIR
. /usr/lib/network/network

errorout() {
  echo "<openbox_pipe_menu>"
  echo "<item label=\"$1\" />"
  echo "</openbox_pipe_menu>"
  exit 1
}

create_profile() {
  ESSID="$1"; INTERFACE="$2"; SECURITY="$3"; KEY="$4"
  PROFILE_FILE="$PROFILE_DIR$ESSID"

  cat > "$PROFILE_FILE" << END_OF_PROFILE
CONNECTION="wireless"
ESSID="$ESSID"
INTERFACE="$INTERFACE"
DESCRIPTION="Automatically generated profile"
SCAN="yes"
IP="dhcp"
TIMEOUT="10"
SECURITY="$SECURITY"
END_OF_PROFILE

  # i think wifi-select should adopt these perms too...
  if [ -n "$KEY" ]; then
    echo "KEY=\"$KEY\"" >> "$PROFILE_FILE"
    chmod 600 "$PROFILE_FILE"
  else
    chmod 644 "$PROFILE_FILE"
  fi
}

print_menu() {
  # scan for networks
  iwlist $INTERFACE scan 2>/dev/null | awk -f $SUBR_DIR/parse-iwlist.awk | sort -t= -nrk3 > /tmp/networks.tmp

  # exit if none found
  if [ ! -s /tmp/networks.tmp ]; then
    rm /tmp/networks.tmp
    errorout "no networks found."
  fi

  # otherwise print the menu
  echo "<openbox_pipe_menu>"
  IFS='='
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    echo "<item label=\"$ESSID ($SECURITY) $QUALITY%\">"
    echo "  <action name=\"Execute\">"
    echo "    <command>sudo $0 $INTERFACE connect \"$ESSID\"</command>"
    echo "  </action>"
    echo "</item>"
  done
  unset IFS
  echo "</openbox_pipe_menu>"
}

connect() {
  # check for an existing profile
  PROFILE_FILE="$(grep -REl "ESSID=[\"']?$ESSID[\"']?" "$PROFILE_DIR" | grep -v '~$' | head -n1)"

  # if found use it, else create a new profile
  if [ -n "$PROFILE_FILE" ]; then
    PROFILE=$(basename "$PROFILE_FILE")
  else
    PROFILE="$ESSID"
    SECURITY="$(awk -F '=' "/$ESSID/"'{print $2}' /tmp/networks.tmp | head -n1)"

    # ask for the security key if needed
    if [ "$SECURITY" != "none" ]; then
      KEY="$(zenity --entry --title="Authentication" --text="Please enter $SECURITY key for $ESSID" --hide-text)"
    fi

    # create the new profile
    create_profile "$ESSID" "$INTERFACE" "$SECURITY" "$KEY"
  fi

  # connect
  netcfg2 "$PROFILE" >/tmp/output.tmp

  # if failed, ask about removal of created profile
  if [ $? -ne 0 ]; then
    zenity --question \
           --title="Connection failed" \
           --text="$(grep -Eo "[\-\>]\ .*$" /tmp/output.tmp) \n Remove $PROFILE_FILE?" \
           --ok-label="Remove profile"
    [ $? -eq 0 ] && rm $PROFILE_FILE
  fi

  rm /tmp/output.tmp
  rm /tmp/networks.tmp
}

[ $(id -u) -ne 0 ] && errorout "root access required."
[ -z "$1" ] && errorout "usage: $0 [interface]"

INTERFACE="$1"; shift

# i added a sleep if we need to explicitly bring it up
# b/c youll get "no networks found" when you scan right away
# this only happens if we aren't up already
if ! ifconfig | grep -q $INTERFACE; then
  ifconfig $INTERFACE up &>/dev/null || errorout "$INTERFACE not up"
  sleep 3
fi

if [ "$1" = "connect" ]; then
  ESSID="$2"
  connect
else
  print_menu
fi

exit 0

Related Posts

Comments are closed.