#!/usr/bin/env ruby

begin
  require 'wx'
rescue LoadError => no_wx_err
  begin

    require 'rubygems'
    require 'wx'
  rescue LoadError
    raise no_wx_err
  end

end

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

# custom dialogs

class ConnectedStationsMessageBox < Wx::Dialog
	def initialize (what)

		super(nil, -1, "Connected Stations")
		if (what == nil) then what ="" end

		sizer = Wx::BoxSizer.new(Wx::VERTICAL)
		label = Wx::StaticText.new(self, -1, what)

		sizer.add(label, 0, Wx::ALIGN_CENTER | Wx::ALL, 5)

		button_sizer = Wx::StdDialogButtonSizer.new()
		btn = Wx::Button.new(self, Wx::ID_OK, 'OK')

		btn.set_default()
		button_sizer.add_button(btn)

		button_sizer.realize
		sizer.add(button_sizer, 0, Wx::ALIGN_CENTER_VERTICAL|Wx::ALL, 5)

		set_sizer(sizer)
		sizer.fit(self)
	end

end

class ConfigureRouterMessageBox < Wx::Dialog
	def initialize(routerConfig)

		if (routerConfig != nil) then
			if (routerConfig.user != nil) then user = routerConfig.user else user = "" end

			if (routerConfig.pass != nil) then pass = routerConfig.pass else pass = "" end

			if (routerConfig.url != nil) then url = routerConfig.url else url = "" end

		end

		super(nil, -1, 'Router Config')

		sizer = Wx::BoxSizer.new(Wx::VERTICAL)

		label = Wx::StaticText.new(self, -1, "Router Configuration")

		sizer.add(label, 0, Wx::ALIGN_CENTER | Wx::ALL, 5)

		box = Wx::BoxSizer.new(Wx::HORIZONTAL)
		label = Wx::StaticText.new(self, -1, "URL")

		box.add(label, 0, Wx::ALIGN_CENTER | Wx::ALL, 5)

		text = Wx::TextCtrl.new(self, -1, url, Wx::DEFAULT_POSITION, Wx::Size.new(80,-1))

		box.add(text, 1, Wx::ALIGN_CENTER | Wx::ALL, 5)

		sizer.add(box, 0, Wx::GROW | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL, 5)

		box = Wx::BoxSizer.new(Wx::HORIZONTAL)
		label = Wx::StaticText.new(self, -1, "Username")

		box.add(label, 0, Wx::ALIGN_CENTER | Wx::ALL, 5)

		text = Wx::TextCtrl.new(self, -1, user, Wx::DEFAULT_POSITION, Wx::Size.new(80,-1))

		box.add(text, 1, Wx::ALIGN_CENTER | Wx::ALL, 5)

		sizer.add(box, 0, Wx::GROW | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL, 5)

		box = Wx::BoxSizer.new(Wx::HORIZONTAL)
		label = Wx::StaticText.new(self, -1, "Password")

		box.add(label, 0, Wx::ALIGN_CENTER | Wx::ALL, 5)

		text = Wx::TextCtrl.new(self, -1, pass, Wx::DEFAULT_POSITION, Wx::Size.new(80,-1), Wx::TE_PASSWORD)

		box.add(text, 1, Wx::ALIGN_CENTER | Wx::ALL, 5)

		sizer.add(box, 0, Wx::GROW | Wx::ALIGN_CENTER_VERTICAL | Wx::ALL, 5)

		line = Wx::StaticLine.new(self, -1, Wx::DEFAULT_POSITION,
					  Wx::Size.new(20,-1), Wx::LI_HORIZONTAL)

		sizer.add(line, 0, Wx::ALIGN_BOTTOM | Wx::GROW , 5)

		button_sizer = Wx::StdDialogButtonSizer.new()
		btn = Wx::Button.new(self, Wx::ID_OK, 'OK')

		btn.set_default()
		button_sizer.add_button(btn)

		btn = Wx::Button.new(self, Wx::ID_CANCEL, 'Cancel')

		button_sizer.add_button(btn)
		button_sizer.realize
		sizer.add(button_sizer, 0, Wx::ALIGN_CENTER_VERTICAL|Wx::ALL, 5)

		set_sizer(sizer)
		sizer.fit(self)
    end

end

class WifiTaskBarIcon < Wx::TaskBarIcon
	MENU_ITEM_SHOWALL = 6000
	MENU_ITEM_CONFIGURE = 6001

	MENU_ITEM_QUIT = 6002
  	EVT_TIMER_ID = 6003

	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 "Exception raised while loading config file: "+$!

			@routerConfig = RouterConfig.new
			return false
		end
	end

	def initialize()
		super()
		@configFolder = ENV['HOME']+"/.wifistat/"

		@configFile = "config.yaml"
		@staticConn=0
		@conf=load_config

		load_images

		set_icon(@inactive, 'WiFi Monitor - Inactive')

		@image_index = 1

		# setup events for left click and menu items
		evt_taskbar_left_dclick  {show_stations }

	    	evt_menu(MENU_ITEM_SHOWALL) {show_stations }
		evt_menu(MENU_ITEM_CONFIGURE)  { configure_router }

		evt_menu(MENU_ITEM_QUIT)   { exit }

		timer = Wx::Timer.new(self, EVT_TIMER_ID)

		evt_timer(EVT_TIMER_ID) { update }
		timer.start(1000)

	end

	def create_popup_menu
		menu = Wx::Menu.new
		menu.append(MENU_ITEM_SHOWALL, "Show all")

		menu.append(MENU_ITEM_CONFIGURE, "Configure")
		menu.append_separator
		menu.append(MENU_ITEM_QUIT,   "Quit")

		return menu
	end

	def make_icon(imgname)
		# Resize the image if required by the plataform

		img = Wx::Image.new(imgname)
		if Wx::PLATFORM == "WXMSW"

			img = img.scale(16, 16)
		elsif Wx::PLATFORM == "WXGTK"

			img = img.scale(22, 22)
		end

		icon = Wx::Icon.new
		icon.copy_from_bitmap(Wx::Bitmap.new(img))

		return icon
	end

        def load_images
		#wxruby has no support for svg files, so we stick with png images
		@active = make_icon("/usr/share/icons/Tango/32x32/status/gnome-dev-wavelan-encrypted.png")

		@inactive = make_icon("/usr/share/icons/Tango/32x32/status/network-offline.png")
		@config = make_icon("/usr/share/icons/Tango/32x32/apps/config-users.png")

        end

	def configure_router
		dlg = ConfigureRouterMessageBox.new(@routerConfig)

		dlg.center_on_screen(Wx::BOTH)
		val = dlg.show_modal()

		if val == Wx::ID_OK
			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}")

		else
			puts "cancelled"

		end
		dlg.destroy
		@conf=true
		@tURL = URI.parse(@routerConfig.url)

	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
			#puts "Error http request: "+$!
			dlg = Wx::MessageDialog.new(nil, "Error http request: "+$!, "Error", Wx::OK | Wx::ICON_INFORMATION)

			dlg.show_modal()
			dlg.destroy()

	end

	def show_stations
		if (@allStation != nil) then

			stList="MAC\t\t\t\tchan\n"
			@allStation.each {	|st| stList+=st['mac']+"\t\t"+st['chan']+"\n" }

		else
			stList="No data\n"
		end

		dlg = ConnectedStationsMessageBox.new(stList)

		dlg.center_on_screen(Wx::BOTH)
		dlg.show_modal()
	end

	def update

		return if (@conf==false)
		@allStation = check()

		return if (@allStation == nil)
		@staticConn=@allStation.size if (@staticConn == 0) 

		if (@staticConn != @allStation.size) then

			dlg = ConnectedStationsMessageBox.new("A new station has connected on \n#{routerConfig.url}")
			dlg.center_on_screen(Wx::BOTH)

			dlg.show_modal()
		end

		if (@allStation == nil) then
			nStat=0

		else
			nStat=@allStation.size
		end

		tip = if nStat > 0 then "#{nStat} connections" else 'no connection' end

		if nStat > 0 then
			set_icon(@active, 'WiFi Monitor: '+tip)

		else
			set_icon(@inactive, 'WiFi Monitor: '+tip)
		end
	end

end

class WiFiMonitorApp < Wx::App
	def on_init
		@tbicon = WifiTaskBarIcon.new()

	end
end

wifimon = WiFiMonitorApp.new
wifimon.main_loop
Advertisements
%d bloggers like this: