You are not logged in.

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?
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 just to get PROFILE_DIR
. /usr/lib/network/network
[ -z "$PROFILE_DIR" ] && PROFILE_DIR='/etc/network.d/'
# awk code for parsing iwlist output
# putting it here removes the wifi-select dependency
# and allows for my own tweaking
# prints a list "essid=security=quality_as_percentage"
PARSER='
BEGIN { FS=":"; OFS="="; }
/\<Cell/ { if (essid) print essid, security, quality[2]/quality[3]*100; security="none" }
/\<ESSID:/ { essid=substr($2, 2, length($2) - 2) } # discard quotes
/\<Quality=/ { split($1, quality, "[=/]") }
/\<Encryption key:on/ { security="wep" }
/\<IE:.*WPA.*/ { security="wpa" }
END { if (essid) print essid, security, quality[2]/quality[3]*100 }
'
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 "$PARSER" | 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
  local IFS='='
  echo "<openbox_pipe_menu>"
  while read ESSID SECURITY QUALITY; do
    echo "<item label=\"$ESSID ($SECURITY) ${QUALITY/.*/}%\">" # trim decimals
    echo "  <action name=\"Execute\">"
    echo "    <command>sudo $0 $INTERFACE connect \"$ESSID\"</command>"
    echo "  </action>"
    echo "</item>"
  done < /tmp/networks.tmp
  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"
  while ! ifconfig | grep -q $INTERFACE; do sleep 1; done
fi
if [ "$1" = "connect" ]; then
  ESSID="$2"
  connect
else
  print_menu
fiScreenshots
removed -- Hi-res shots available on my site
NOTE - i have not tested this extensively but it was working for me in most cases. any updates/fixes will be edited right into this original post. enjoy!
UPDATE - 10/24/2009: i moved the awk statement from wifi-select directly into the script. this did two things: wifi-select is no longer needed on the system, and i could tweak the awk statement to be more accurate. it now prints a true percentange. iwlist prints something like Quality=17/70 and the original awk statement would just output 17 as the quality. i changed to print (17/70)*100 then bash trims the decimals so you get a true percentage.
Last edited by brisbin33 (2010-05-09 01:28:20)
//github/
Offline
now just install and set a decent gtk theme 
I'll definitely test this one out... now I just need to figure netcfg out ^^
Offline

This is a great idea. I salute you! I never have to connect to that many wireless networks so I just use netcfg at home and USB 3G modem at school. Pipe menus are pretty cool though.
< Daenyth> tomkx: my girlfriend is linux
< Daenyth> srsly
< Daenyth> she loves the way I «make install»
< Daenyth> all her /dev entries are mode 7 for me
Offline
this is completely awesome! works very well, thanks a lot!
cheers
Barde
Offline
Great script! 
Offline

Awesome, you should make a pkgbuld and up it to the AUR 
Offline

Any chance for a PekWM version?
It would be awesome!!
archlinux on Macbook Pro 10,1
Offline

@FaN_OnLy1, seeing as installation is 10% copy/pasting a script and 90% configuring your system (rc.xml, visudo, and so forth) im not sure if this makes sense as an AUR pkg.  but feel free to package it if you'd like (and credit me  ).
).
@froli, i'm not sure if pekwm supports any sort of pipe-menu, might be an openbox only feature.  i don't use that WM, so it probably wouldn't happen anyway  .
.
@all, thanks for the compliments; i find it a pretty slick approach, im glad others like it too!
also, if anyone doesn't want to deal with copy/pasting, you can try this*:
wget -O ~/.config/openbox/wifi-pipe "http://pbrisbin.com:8080/shared/wifi-pipe" && chmod +x ~/.config/openbox/wifi-pipethen proceed with the rc.xml and visudo configurations.
*FYI: not sure how long i'll leave that file up on my server, or if i'll push any updates to it.
//github/
Offline

@froli, i'm not sure if pekwm supports any sort of pipe-menu, might be an openbox only feature. i don't use that WM, so it probably wouldn't happen anyway
.
Yes PekWM support pipe-menu, but my question was not specific to you, it was for anyone who can adapt this script to PekWM.
I'll just try to adapt it to PekWM by myself and if it's successful, I'll post the results here. 
archlinux on Macbook Pro 10,1
Offline

Did anybody succeed in making a pekwm edition? I would be quite interested. . .
Thanks,
Rasmus
Arch x64 on Thinkpad X200s/W530
Offline

so i did some quick pekwm research, looks like adjusting my script wouldn't be too hard; i may put it together myself, but here is some code that might help anyone interested in doing the work:
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 "Dynamic {"
  IFS='='
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    echo "Entry = \"$ESSID ($SECURITY) $QUALITY%\" {"
    echo "   Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>"
    echo "}"
  done
  unset IFS
  echo "}"
}SubMenu = "WiFi" {
  Entry = { Actions = "Dynamic /path/to/wifi-pipe" }NOTE: completely untested (and pretty much just a guess based on googling).
if i ever feel motivated enough to install pekwm and test, ill post complete pekwm script/instructions... but i wouldn't expect anything anytime soon 
//github/
Offline

so i did some quick pekwm research, looks like adjusting my script wouldn't be too hard; i may put it together myself, but here is some code that might help anyone interested in doing the work:
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 "Dynamic {" IFS='=' cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do echo "Entry = \"$ESSID ($SECURITY) $QUALITY%\" {" echo " Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>" echo "}" done unset IFS echo "}" }SubMenu = "WiFi" { Entry = { Actions = "Dynamic /path/to/wifi-pipe" }NOTE: completely untested (and pretty much just a guess based on googling).
if i ever feel motivated enough to install pekwm and test, ill post complete pekwm script/instructions... but i wouldn't expect anything anytime soon
I think the script's not working  ... When I type
 ... When I type 
sh wifi-pipein a term it returns nothing 
archlinux on Macbook Pro 10,1
Offline

I think the script's not working
... When I type
sh wifi-pipein a term it returns nothing
well, just to be sure you're doing it right...
he above is only an adjustment to the OB script's print_menu() function, it's not an entire script to itself. so, if the original OB script shows output for you with
sh ./wifi-pipethen using the above pint_menu() function (with all the other supporting code) should also show output, (only really only changes the echo's so they print the info in the pekwm format).
oh, and if neither version shows output when you rut it in a term, then you've got other issues... ;P
here's an entire [untested] pekwm script:
#!/bin/bash
#
# pbrisbin 2009
#
# simplified version of wifi-select designed to output as an pekwm pipe menu
#
# required:
#   netcfg
#   zenity
#   NOPASSWD entries for this and netcfg through visudo
#
#   the following in pekwm config file:
#      SubMenu = "WiFi" {
#        Entry = { Actions = "Dynamic /path/to/wifi-pipe" }
#
# 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 "Dynamic {"
  echo "  Entry = \"$1\""
  echo "}"
  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 "Dynamic {"
  IFS='='
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    echo "Entry = \"$ESSID ($SECURITY) $QUALITY%\" {"
    echo "   Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>"
    echo "}"
  done
  unset IFS
  echo "}"
}
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//github/
Offline

Hey that's awesome, thanks for testing Pank!
currently it's sorted by signal strength, and note: i took out any "profile exists / auto generated" stuff, as i don't really care about that. i'm sorry if that's what you were hoping to sort on.
//github/
Offline

No, as I wrote here want I really want is a dynamic netcfg-menu/wifi-select which only shows relevant networks; that is networks that has a profile already.
--Rasmus
Arch x64 on Thinkpad X200s/W530
Offline

@brisbin33 Thanks a lot for this pekwm!! 
archlinux on Macbook Pro 10,1
Offline

brisbin33,
How do I limit the output to networks with already existing profiles. I tried to mess around with your script but I did not succeed.
It is useful when you have got a lot of profiles and rarely connects to new networks.
Would it be possible?
Thanks,
Rasmus
Arch x64 on Thinkpad X200s/W530
Offline

Pank, i would just change:
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    echo "Entry = \"$ESSID ($SECURITY) $QUALITY%\" {"
    echo "   Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>"
    echo "}"to:
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    
    # if a profile file does not exist for the ESSID, don't print it
    PROFILE_FILE="$(grep -REl "ESSID=[\"']?$ESSID[\"']?" "$PROFILE_DIR" | grep -v '~$' | head -n1)"
    [ -z "$PROFILE_FILE" ] && continue
    echo "Entry = \"$ESSID ($SECURITY) $QUALITY%\" {"
    echo "   Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>"
    echo "}"in the pint_menu() function; this does duplicate code from the connect() function, but it's easier than rewriting both parts  .
.
//github/
Offline

It works as a charm.
Last question and I promise I won't bother you no more 
Would it be possible to use the description label of the profile rather than the ESSID?
Thanks,
Rasmus
Arch x64 on Thinkpad X200s/W530
Offline

Would it be possible to use the description label of the profile rather than the ESSID?
anything's possible, something like:
  cat /tmp/networks.tmp | while read ESSID SECURITY QUALITY; do
    
    # if a profile file does not exist for the ESSID, don't print it
    PROFILE_FILE="$(grep -REl "ESSID=[\"']?$ESSID[\"']?" "$PROFILE_DIR" | grep -v '~$' | head -n1)"
    if [ -z "$PROFILE_FILE" ]; then
      continue
    else
      DESC="$(awk -F '"' '/^DESCRIPTION/ {print $2}' "$PROFILE_FILE")"
    fi
    echo "Entry = \"$DESC ($SECURITY) $QUALITY%\" {"
    echo "   Actions = \"Exec sudo $0 $INTERFACE connect \\\"$ESSID\\\"\"</command>"
    echo "}"might work. again, untested.
//github/
Offline

Hello,
The script seems to work, but it is slowing down my menu. Everytime when I open my menu, the script starts to search for the available networks. The menu freezes untill the script lists the available networks.
Any solution?
Arch x86_64 on HP 6820s and on HP nx9420. Registered Linux User 350155, since 24-03-2004
"Everyone said that it could not be done, until someone came along who didn't know that."
Offline

i believe the menu is not created (and the scan not started) until you actually mouse over the parent entry.
try putting the wifi entry towards the bottom of your root menu, then don't mouse over it when you open the menu and see if the delay still exists.
if the wifi entry is first in the menu, right click puts your mouse right on it to begin with and a wait-for-scan is probably unavoidable.
//github/
Offline

That's what I already figured out. I changed it to be a submenu under my system-menu and now it doesn't bother me anymore. Thxs.
Last edited by NeoXP (2009-10-01 18:03:05)
Arch x86_64 on HP 6820s and on HP nx9420. Registered Linux User 350155, since 24-03-2004
"Everyone said that it could not be done, until someone came along who didn't know that."
Offline
Nice, thanks for the script!
Offline