#!/usr/bin/env ruby
# systray code based on http://neugierig.org/software/misc/gmail-notifier
require 'gtk2'
require 'gtktrayicon'
require 'net/http'
require 'open-uri'
require 'uri'
require 'fileutils.rb'
require 'yaml'
class RouterConfig
def user
@user
end
def user=(usr)
@user=usr
end
def url
@url
end
def url=(ur)
@url=ur
end
def pass
@pass
end
def pass=(pw)
@pass=pw
end
end
class ConnectedStationsMessageBox < Gtk::Dialog
def initialize (what)
super()
if (what == nil) then what="" end
set_modal(true)
#TODO: dynamic sizing from text
set_default_size(200,150)
set_title('Connected Stations')
label = Gtk::Label.new(nil, nil)
label.set_markup(what)
vbox.add(label)
ok = Gtk::Button.new('OK')
action_area.add(ok)
ok.signal_connect('clicked') do
destroy
end
show_all
end
end
class ConfigureRouterMessageBox < Gtk::Dialog
def initialize (routerConfig)
super()
set_modal(true)
set_default_size(200,100)
set_title('Router Configuration')
lblUrl = Gtk::Label.new("URL", nil)
lblUser = Gtk::Label.new("Username", nil)
lblPass = Gtk::Label.new("Password", nil)
entryUrl = Gtk::Entry.new
entryUser = Gtk::Entry.new
entryPass = Gtk::Entry.new
entryPass.set_visibility(false)
urlHbox = Gtk::HBox.new(true,nil)
userHbox = Gtk::HBox.new(true,nil)
passHbox = Gtk::HBox.new(true,nil)
urlHbox.add(lblUrl)
urlHbox.add(entryUrl);
userHbox.add(lblUser)
userHbox.add(entryUser);
passHbox.add(lblPass)
passHbox.add(entryPass);
vbox.add(urlHbox)
vbox.add(userHbox)
vbox.add(passHbox)
btOk = Gtk::Button.new('Save')
btCancel = Gtk::Button.new('Cancel')
action_area.add(btOk)
action_area.add(btCancel)
if (routerConfig != nil) then
if (routerConfig.user != nil) then entryUser.text = routerConfig.user end
if (routerConfig.pass != nil) then entryPass.text = routerConfig.pass end
if (routerConfig.url != nil) then entryUrl.text = routerConfig.url end
end
btOk.signal_connect('clicked') do
routerConfig.user=entryUser.text
routerConfig.pass=entryPass.text
routerConfig.url=entryUrl.text
response(Gtk::Dialog::RESPONSE_ACCEPT)
end
btCancel.signal_connect('clicked') do
response(Gtk::Dialog::RESPONSE_CANCEL)
end
show_all
end
end
class TrayApplet < Gtk::TrayIcon
def routerConfig
@routerConfig
end
def routerConfig=(rcf)
@routerConfig=rcf
end
def load_config
begin
@routerConfig=YAML::load(File.open(@configFolder+@configFile)) if File.exist?(@configFolder+@configFile)
if (!@routerConfig) then
puts "Error loading config file: "+$!
@routerConfig = RouterConfig.new
return false
else
print "Found #{@configFolder}#{@configFile}.\n"
@tURL = URI.parse(routerConfig.url)
return true
end
rescue
puts "Error loading config file: "+$!
@routerConfig = RouterConfig.new
return false
end
end
def initialize
super("Wireless Station monitor")
@configFolder = ENV['HOME']+"/.wifistat/"
@configFile = "config.yaml"
@staticConn=0
@conf=load_config
load_images
if (@conf) then
@image = Gtk::Image.new(@active)
else
@image = Gtk::Image.new(@inactive)
end
add(@image)
show_all
@tooltips = Gtk::Tooltips.new
menu = Gtk::Menu.new
item = Gtk::ImageMenuItem.new('_Show all')
item.image = Gtk::Image.new(@active)
item.signal_connect('activate') { show_stations }
item.show_all
menu.append(item)
item = Gtk::ImageMenuItem.new('Configure')
item.image = Gtk::Image.new(@config)
item.signal_connect('activate') { configuration }
item.show_all
menu.append(item)
item = Gtk::SeparatorMenuItem.new
item.show_all
menu.append(item)
item = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT)
item.signal_connect('activate') { Gtk.main_quit }
item.show; menu.append(item)
add_events(Gdk::Event::BUTTON_PRESS_MASK)
add_events(Gdk::Event::BUTTON_RELEASE_MASK)
signal_connect('button-press-event') do |w, e|
show_stations if e.button == 1 and e.event_type == Gdk::Event::BUTTON2_PRESS
end
signal_connect('button-release-event') do |w, e|
menu.popup(nil, nil, e.button, e.time) if e.button == 3
end
update()
Gtk::timeout_add(10000) {update; true}
end
def load_images
img_online = "/usr/share/icons/Tango/scalable/status/gnome-dev-wavelan-encrypted.svg"
img_offline = "/usr/share/icons/Tango/scalable/status/network-offline.svg"
img_config = "/usr/share/icons/Tango/scalable/apps/config-users.svg"
@active = Gtk::Image.new(Gdk::Pixbuf.new(img_online, 24, 24)).pixbuf
@inactive = Gtk::Image.new(Gdk::Pixbuf.new(img_offline, 24, 24)).pixbuf
@config = Gtk::Image.new(Gdk::Pixbuf.new(img_config, 24, 24)).pixbuf
end
def check
# http request/html parsing to check for new connections
# TODO: make regex a configurable parameter for multiple routers
allItem = Array.new
regex=/writeRow\(\[sid\,\"(.+)\"\,(.+)\,(.+)/
open(@tURL, :http_basic_authentication=> [@routerConfig.user, @routerConfig.pass]) {|f|
oi=f.read
oi.scan(regex)
tmpHash= {'mac'=>$1,'chan'=>$2}
allItem << tmpHash
}
return allItem
rescue
dialog = Gtk::MessageDialog.new(self,
Gtk::Dialog::DESTROY_WITH_PARENT,
Gtk::MessageDialog::WARNING,
Gtk::MessageDialog::BUTTONS_CLOSE, "Error http request: "+$!)
dialog.run
dialog.destroy
end
def show_stations
if (@allStation != nil) then
stList="<b>MAC</b>\t\t\t\t<b>chan</b>\n"
@allStation.each { |st| stList+=st['mac']+"\t\t"+st['chan']+"\n" }
else
stList="No data\n"
end
dlg = ConnectedStationsMessageBox.new(stList)
end
def configuration
cfg=ConfigureRouterMessageBox.new(routerConfig);
cfg.run do |response|
case response
when Gtk::Dialog::RESPONSE_ACCEPT
FileUtils.mkdir_p(@configFolder) unless File.directory?(@configFolder)
File.open(@configFolder+@configFile, 'w') { |f| f.puts routerConfig.to_yaml }
dlg = ConnectedStationsMessageBox.new("New config for #{routerConfig.url}")
end
end
cfg.destroy
@conf=true
@tURL = URI.parse(routerConfig.url)
end
def update
return if (@conf==false)
@allStation = check()
return if (@allStation == nil)
@staticConn=@allStation.size if (@staticConn == 0)
dlg = ConnectedStationsMessageBox.new(
"A new station has connected on \n#{routerConfig.url}"
) if (@staticConn != @allStation.size)
if (@allStation == nil) then
nStat=0
else
nStat=@allStation.size
end
@image.pixbuf = if nStat > 0 then @active else @inactive end
tip = if nStat > 0 then "#{nStat} connections" else 'no connection' end
@tooltips.set_tip(self, tip, nil)
end
end
# main
Gtk.init
TrayApplet.new
Gtk.main
Like this:
Like Loading...