#!/usr/bin/env python
import sys
import locale
import gobject
import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
import gnome
import gnome.ui
from os import path, spawnl, popen, system, P_NOWAIT, umask
from threading import Thread
from time import sleep
from select import select
from string import *
from socket import *
import errno
import re

debug = False

def debug_print(something):
	if debug:
		print something

def get_shared_path():
	testfile = 'version'
	sharedirs = [".",path.join(path.dirname(sys.argv[0]),"../share/ups-monitor")]
	sharepath = None
	for sharedir in sharedirs:
		fname = path.join(path.abspath(sharedir),testfile)
		if path.exists(fname):
			sharepath = path.abspath(sharedir)
			break
	
	if sharepath is None:
		raise Exception, "UPS monitor shared files " + testfile + " cannot be found in any of " + str(sharedirs) + " default paths"
	
	return sharepath

sys.path[0] = get_shared_path()

import eggtrayicon



class AuxiliaryProgramNotFound(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class NoBrowserError(AuxiliaryProgramNotFound):
	pass
	
class NoMailClientError(AuxiliaryProgramNotFound):
	pass

def get_full_path_to_program(program):
	possible_browsers = [program]
	for browser in possible_browsers:
		command = popen("LC_ALL=C which " + browser + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None



def get_browser():
	possible_browsers = ["gnome-open","mozilla","firefox","konqueror"]
	for browser in possible_browsers:
		command = popen("LC_ALL=C which " + browser + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None


def get_mail_client():
	possible_clients = ["gnome-open","evolution","kmail"]
	for client in possible_clients:
		command = popen("LC_ALL=C which " + client + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None


def open_webpage(url):
	browser = get_browser()
	if browser is None:
		raise NoBrowserError, "No suitable browser found"
	system( browser + " '" + url + "'" )

def compose_mail(url):
	client = get_mail_client()
	if client is None:
		raise NoMailClientError, "No suitable mail client found"
	system( client  + " 'mailto:" + url + "'" )
	


def read_ups_config(file):
	f = open(file)
	lines = f.readlines()
	lines2 = []
	for line in lines:
		commentpos = find(line,"#")
		if commentpos != -1:
			line2 = line[:commentpos]
		else:
			line2 = line
		if line2:
			lines2 = lines2 + [ strip(line2) ]
	currentups = None
	upses = dict()
	for line2 in lines2:
		r = re.compile("\[(.*)\]")
		if r.match(line2):
			[currentups] = r.findall(line2)
			upses[currentups] = []
		elif currentups:
			strip(line2)
			if len(line2) > 0:
				key, value = split(line2,"=",1)
				strip(key)
				strip(value)
				upses[currentups] = upses[currentups] + [ { key : value } ]
		
	return upses
	
def is_computer_name_local(hostname):
	if hostname == "localhost" or hostname == "localhost.localdomain" or hostname == "127.0.0.1":
		return True

def get_friendly_computer_name(hostname):
	if is_computer_name_local(hostname):
		return "this computer"
	return hostname	
	
class UPSError(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class InvalidAddressError(UPSError):
	pass


class UPSNotConnectedError(UPSError):
	pass

class AuthenticationFailedError(UPSError):
	pass
	
class UPSNotFoundError(UPSError):
	pass

class LostConnection(UPSError):
	pass

class UPSMonitorError(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class NoLastUPSError(UPSMonitorError):
	pass



def working(e):
	try:
		value, name = e
	except Exception:
		debug_print( "era error de verdad")
		return False
	if value == 115:
		return True
	return False
	
def timeout(e):
	try:
		value, name = e
	except Exception:
		debug_print( "era error de verdad")
		return False
	if value == errno.ETIME or value == errno.ETIMEDOUT:
		return True
	return False
	
class UPSSocket(socket):
	def push(self,data):
		debug_print( "Sending data: " + str(data))
		buf = data
		while len(buf) > 0:
			select([],[self],[self])
			try:
				sent = self.send(data)
			except Exception:
				raise LostConnection, "The network connection to the UPS is lost"
			if sent == 0:
				raise LostConnection, "The network connection to the UPS is lost"
			buf = buf[sent:]
			
	def get_data_until(self,terminators):
		debug_print( "Waiting for data until: " + str(terminators))
		if type(terminators) == type("string"):
			terminators = [terminators]
		buf = ""
		found = False
		while found == False:
			debug_print( "Waiting...")
#			select([self],[],[self])
			debug_print( "Receiving something")
			rcvd = self.recv(8192)
			if len(rcvd) < 1:
				raise LostConnection, "The network connection to the UPS is lost"
			buf = buf + rcvd
			for delimiter in terminators:
				if find(buf,delimiter)  != -1:
					found = True
		return buf
	


class UPS:

	address = None
	host = None
	ups_name = None
	username = None
	password = None
	socket = None
	poller_thread = None
	poll_callback = None
	failure_callback = None
	
	status = "OK"

	manufacturer = None
	model = None
	serial = None
	
	power_source = None
	battery_status  = None
	ups_status = None
	battery_voltage = None
	
	battery_charge = None
	ups_load = None
	remaining_time = None
	max_remaining_time = None
	
	def __init__ (self,address,username,password):
		if find(address,"@") == -1:
			address = address + "@localhost"
		self.address = address
		self.ups_name , self.host = split(address,"@")
		self.username = username
		self.password = password
		
	def check_ups_exists(self):
		self.poll()
		
	def connect(self):
#		self.set_poll_callback(poll_callback)
#		self.set_failure_callback(failure_callback)


		self.socket = UPSSocket(AF_INET,SOCK_STREAM)
		self.socket.setblocking(1)
		self.socket.settimeout(15)
		
		try:
			self.socket.connect((self.host,3493))
		except Exception, e:
			if not working(e):
				raise InvalidAddressError, "Could not connect to the specified UPS address"

		a = select([self.socket],[self.socket],[self.socket])

 		try:
			self.socket.push(" ")
 		except Exception, e:
 			debug_print( e)
			raise InvalidAddressError, "Could not connect to the specified UPS address"

		if self.username is not None:
			self.authenticate(self.username,self.password)

		self.check_ups_exists()

	def disconnect(self):
 		try:
			self.socket.push("LOGOUT\n")
 		except Exception, e:
 			pass
		self.stop_monitoring()

		self.socket.close()
		self.socket = None

	def authenticate(self,username,password):
		if not self.is_connected():
			raise UPSNotConnectedError, "This UPS object is not connected yet"
		
		self.username = username
		self.password = password
		
		try:
			self.socket.push("USERNAME " + self.get_username() + "\n")
 		except Exception, e:
 			debug_print( e)
 			raise InvalidAddressError, "Could not connect to the specified UPS address"
		
		response = self.socket.get_data_until("\n")
		
		if response[0:2] != "OK":
			raise AuthenticationFailedError, "The specified username is invalid"
		
		self.socket.push("PASSWORD " + self.get_password() + "\n")
		response = self.socket.get_data_until("\n")
		
		if response[0:2] != "OK":
			raise AuthenticationFailedError, "The specified password is invalid"
		
	def is_connected(self):
		if self.socket is None:
			return False
		return True

	def is_monitoring(self):
		if self.poller_thread is None:
			return False
		if self.poller_thread.isAlive() is not True:
			return False
		return True
		
	def poll(self):
		debug_print( "polling UPS")
		self.status = "OK"
		if not self.is_connected():
			raise UPSNotConnectedError, "This UPS object is not connected yet"
		
		try:
			self.socket.push("LIST VAR " + self.get_ups_name() + "\n")
			response = self.socket.get_data_until(["END LIST VAR","ERR"])

		except LostConnection, e:
			debug_print( "Disconnected")
			self.disconnect()
			if self.failure_callback:
				gtk.threads_enter()
				self.failure_callback()
				gtk.threads_leave()
			return
			
		except Exception, e:
			debug_print( dir(e))
			debug_print( "Timed out while sending or receiving data")
			self.disconnect()
			if self.failure_callback:
				gtk.threads_enter()
				self.failure_callback()
				gtk.threads_leave()
			return
		
		if find(response,"ERR UNKNOWN-UPS") != -1:
			raise UPSNotFoundError, "UPS " + self.get_ups_name() + " is not attached to " + self.get_host()
		
		if find(response,"ERR DRIVER-NOT-CONNECTED") != -1:
			self.status = "DRIVER-NOT-CONNECTED"
		
		if find(response,"ERR DATA-STALE") != -1:
			self.status = "DATA-STALE"

# 		if find(response,"ERR DRIVER-NOT-CONNECTED") == -1 and find(response,"ERR") != -1:
# 			raise Exception, "Unknown error while polling UPS"
		
		lines = split(response,"\n");
		
		expression = r'VAR [^ \t\n\r\f\v]+ ([^ \t\n\r\f\v]+) "(.*)"'
		linelist = []
		for line in lines:
			matches = re.findall(expression,line)
			if len(matches) > 0:
				linelist = linelist + [matches[0]]
		
		self.parse_input(linelist)

		if self.poll_callback:
			debug_print( "Calling callback thread")
			gtk.threads_enter()
			self.poll_callback()
			gtk.threads_leave()
		
	def parse_input(self,linelist):
		
		# clear stuff out first
# 		self.manufacturer = None
# 		self.model = None
# 		self.serial = None
		
		self.power_source = None
		self.ups_status  = None
		self.battery_voltage = None
		
		self.battery_charge = None
		self.ups_load = None
		self.remaining_time = None
		self.battery_status = None
		
		radixchar = str(locale.nl_langinfo(locale.RADIXCHAR))
		
		for line in linelist:
			key, value = line
			value = value.replace(".",radixchar)
			if key == "battery.charge":
				self.battery_charge = float(value) / 100
			if key == "battery.runtime":
				self.remaining_time = int(value)
				if self.max_remaining_time is None:
					self.max_remaining_time = self.remaining_time
				if self.remaining_time > self.max_remaining_time:
					self.max_remaining_time = self.remaining_time
			if key == "battery.voltage":
				self.battery_voltage = float(value)
			if key == "ups.load":
				self.ups_load = float(value) / 100
			if key == "ups.mfr":
				self.manufacturer = value
			if key == "ups.model":
				self.model = value
			if key == "ups.serial":
				self.serial = value
			if key == "ups.status":
				self.battery_status = "NORMAL"
				self.ups_status = "NORMAL"
				if find(value,"OL") != -1:
					self.power_source = "AC"
				elif find(value,"OB") != -1:
					self.power_source = "BAT"
				elif find(value,"LB") != -1:
					self.battery_status = "LOW"
				elif find(value,"RB") != -1:
					self.battery_status = "REPLACE"
				elif find(value,"BYPASS") != -1:
					self.ups_status = "BYPASS"
				elif find(value,"CAL") != -1:
					self.ups_status = "CALIBRATING"
				elif find(value,"OFF") != -1:
					self.ups_status = "OFFLINE"
				elif find(value,"OVER") != -1:
					self.ups_status = "OVERLOADED"
				elif find(value,"TRIM") != -1:
					self.ups_status = "TRIMMING"
				elif find(value,"BOOST") != -1:
					self.ups_status = "BOOSTING"
				elif value == "FSD":
					self.power_source = "BAT"
					self.battery_status = "LOW"
				else:
					debug_print( "Unknown status value " + value)
					
	
	def get_address(self):
		return self.address
	def get_host(self):
		return self.host
	def get_ups_name(self):
		return self.ups_name
	def get_username(self):
		return self.username
	def get_password(self):
		return self.password

	def set_poll_callback(self,func):
		self.poll_callback = func
	
	def set_failure_callback(self,func):
		self.failure_callback = func
	
	def start_monitoring(self,poll_callback,failure_callback):
		self.set_poll_callback(poll_callback)
		self.set_failure_callback(failure_callback)

		self.poller_thread= UPSPollerThread(self)
		self.poller_thread.start()

	def stop_monitoring(self):
		if self.poller_thread:
			self.poller_thread.stop()
			self.poller_thread = None

class UPSPollerThread(Thread):
	ups = None
	poll_callback = None
	failure_callback = None
	poll_count = 0

	def __init__(self,ups):
		Thread.__init__(self)
		self.ups = ups
		self.setDaemon(True)
		
	def run(self):
		while True:
			if self.ups is None:
				return
			self.poll_count = self.poll_count + 1
			self.ups.poll()
			if self.ups is not None:
				sleep (1)

	def stop(self):
		self.ups = None

class UPSTrayMonitor:

	window = None
	ac_icon = None
	bat_icon = None
	warning_icon = None
	battery_good_icon = None
	battery_low_icon = None
	battery_critical_icon = None
	icon_container = None
	sharepath = None
	last_tooltip = None
	alarm_message = None
	error_message = None
	event_box = None
	app = None
	logo_icon = None

	def __init__(self,app):
		self.app = app
		self.sharepath = app.sharepath

		self.window = eggtrayicon.create_window("ups-tray-monitor")

		self.event_box = gtk.EventBox()
		self.event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK)
		self.window.add(self.event_box)

		self.event_box.show()

		self.window.tooltip = gtk.Tooltips()
		self.window.tooltip.enable()

		self.icon_container = gtk.HBox()
		self.icon_container.set_spacing(2)
		self.icon_container.set_border_width(4)
		self.icon_container.show()

		self.logo_icon = gtk.Image()
		self.logo_icon.set_from_file(path.join(self.sharepath,"ups-monitor-small.png"))
		self.logo_icon.show()
		self.icon_container.add(self.logo_icon)

		self.ac_icon = gtk.Image()
		self.ac_icon.set_from_file(path.join(self.sharepath,"ac-icon.png"))
		self.icon_container.add(self.ac_icon)

		self.bat_icon = gtk.Image()
		self.bat_icon.set_from_file(path.join(self.sharepath,"bat-icon.png"))
		self.icon_container.add(self.bat_icon)

		self.warning_icon = gtk.Image()
		self.warning_icon.set_from_file(path.join(self.sharepath,"warning-icon.png"))
		self.icon_container.add(self.warning_icon)

		self.battery_good_icon = gtk.Image()
		self.battery_good_icon.set_from_file(path.join(self.sharepath,"battery-good.png"))
		self.icon_container.add(self.battery_good_icon)

		self.battery_low_icon = gtk.Image()
		self.battery_low_icon.set_from_file(path.join(self.sharepath,"battery-low.png"))
		self.icon_container.add(self.battery_low_icon)

		self.battery_critical_icon = gtk.Image()
		self.battery_critical_icon.set_from_file(path.join(self.sharepath,"battery-critical.png"))
		self.icon_container.add(self.battery_critical_icon)


		self.event_box.add(self.icon_container)
		self.window.show()

		self.event_box.connect("event",self.event)


	def set_power_source(self,source):
		self.logo_icon.hide()
		if source == "AC":
			self.ac_icon.show()
			self.bat_icon.hide()
			if not self.alarm_message and not self.error_message:
				self.set_tooltip("UPS is drawing power from wall socket")
		else:
			self.ac_icon.hide()
			self.bat_icon.show()
			if not self.alarm_message and not self.error_message:
				self.set_tooltip("UPS is using battery backup power")

	def set_alarm(self,text):
		self.logo_icon.hide()
		self.alarm_message = text
		if text:
			self.set_tooltip(text)
			self.warning_icon.show()
		else:
			self.warning_icon.hide()

	def set_error(self,text):
		self.logo_icon.hide()
		self.error_message = text
		if text:
			self.set_tooltip(text)
			self.ac_icon.hide()
			self.bat_icon.hide()
			self.warning_icon.show()
		else:
			self.warning_icon.hide()

	def set_tooltip(self,text):
		if self.error_message:
			tip = self.error_message
		elif self.alarm_message:
			tip = self.alarm_message
		else:
			tip = text

		if tip != self.last_tooltip:
			self.window.tooltip.set_tip(self.window,tip)
		self.last_tooltip = tip

	def toggle_main_window (self):
		self.app.toggle_main_window()



	def event(self,caller=None,event=None):
		button = None
		if event.type == gtk.gdk.BUTTON_PRESS:
			try:
				button = event.button
			except AttributeError:	
				pass
		if button == 1 or button == 3 or button == 2:
			self.toggle_main_window()
		
class UPSMonitor (gtk.glade.XML):
	ups = None
	window = None
	timeout_id = None
	last_power_source = None
	little_time_left_warning = None
	session_saved = None
	tray_icon = None
	
	def __init__ (self,sharepath):
		self.sharepath = sharepath
		gtk.glade.XML.__init__(self,path.join(self.sharepath,'ups-monitor.glade'))
		self.window = self.get_widget("window")
		self.prepare_widgets()
		self.connect_signals()
		self.load_config()
		if self.config["visible"] is True:
			self.window.show()
	
	def toggle_main_window(self,caller=None,data=None):
		if self.window.get_property("visible") == False:
			self.window.present()
			self.window.grab_focus()
		else:
			self.window.hide()
			if not self.config["background_monitoring_shown"] and self.ups:
				self.show_info_dialog("UPS monitor will continue monitoring your UPS in the background.  You can access the UPS monitor window by clicking the UPS monitor status icon  in the notification area.","UPS monitor keeps monitoring your UPS")
				self.config["background_monitoring_shown"] = True
		return True

	def main_window_closed(self,caller=None,data=None):
		if self.ups is None:
			self.quit()
		return self.toggle_main_window()


	def save_session(self):
		program = get_full_path_to_program("dcop")
		if program:
			system("dcop ksmserver ksmserver saveCurrentSession")
		program = get_full_path_to_program("gnome-session-save")
		if program:
			system("gnome-session-save")
	
	def get_version(self):
		program = gnome.program_get()
		return program.get_property("app-version")
		# the following code is deprecated and will no longer be used
		file = path.join(self.sharepath,"version")
		f = open(file)
		lines = f.readlines()
		version = strip(lines[0])
		return version
		
		
	def connect_signals(self):
		self.signal_autoconnect(self)


	def prepare_widgets(self):

		self.get_widget("window").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("prefs_window").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("info_dialog").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("warning_dialog").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("error_dialog").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("about_dialog").set_icon_from_file(path.join(self.sharepath,"ups-monitor.png"))


		self.get_widget("about_image").set_from_file(path.join(self.sharepath,"ups-monitor.png"))
		self.get_widget("battery_image").set_from_file(path.join(self.sharepath,"battery-level.png"))
		self.get_widget("load_image").set_from_file(path.join(self.sharepath,"load.png"))
		self.get_widget("remaining_time_image").set_from_file(path.join(self.sharepath,"remaining-time.png"))
		
		title = "<span weight=\"bold\"><big><big>UPS monitor</big></big></span>"
		version = "<b>version "+self.get_version()+"</b>"
		subtitle = "A graphical application to monitor the status of your UPS"
		
		self.get_widget("label_about").set_markup(title + "\n" + version + "\n" + subtitle)
		
		self.get_widget("prefs_window").set_transient_for(self.get_widget("window"))

		self.tray_icon = UPSTrayMonitor(self)

	def disable_display(self):
		self.get_widget("display").set_sensitive(False)
	
	def enable_display(self):
		self.get_widget("display").set_sensitive(True)
	
	def quit(self,caller=None,extraobject=None):
		self.save_config()
		gtk.main_quit()

	def open_preferences(self,caller):
		self.show_prefs_window()
	
	def update_statusbar(self,message,ok=True):
		self.get_widget("statusbar").set_markup(message)
		if ok:
			self.get_widget("status_icon_ok").show()
			self.get_widget("status_icon_error").hide()
		else:
			self.get_widget("status_icon_ok").hide()
			self.get_widget("status_icon_error").show()
	
	def show_dialog(self,dialogtype,message,title=None):
		if title:
			dialogtitle = title
			title = "<span weight='bold' size='larger'>" + title + "</span>\n\n"
		else:
			dialogtitle = "UPS monitor - error"
			title = ""
		self.get_widget(dialogtype + "_message").set_markup(title+message)
		self.get_widget(dialogtype + "_dialog").set_title(dialogtitle)
		self.get_widget(dialogtype + "_dialog").present()

	def show_error_dialog(self,message,title=None):
		return self.show_dialog("error",message,title)
	
	def show_info_dialog(self,message,title=None):
		return self.show_dialog("info",message,title)
	
	def show_warning_dialog(self,message,title=None):
		return self.show_dialog("warning",message,title)
	
	def show_about_dialog(self,caller=None):
		self.get_widget("about_dialog").present()
		
	def dismiss_error_dialog(self,caller=None,e=None):
		self.get_widget("error_dialog").hide()
		return True
		
	def dismiss_about_dialog(self,caller=None,e=None):
		self.get_widget("about_dialog").hide()
		return True
		
	def dismiss_info_dialog(self,caller=None,e=None):
		self.get_widget("info_dialog").hide()
		return True
		
	def dismiss_warning_dialog(self,caller=None,e=None):
		self.get_widget("warning_dialog").hide()
		return True
		
	def hide_prefs_window(self,caller=None,e=None):
		self.get_widget("prefs_window").hide()
		return True
		
	def show_prefs_window(self,caller=None,e=None):

		self.get_widget("prefs_window").present()
		return True
		
		
		
	def load_config(self):
		self.config = dict()

		upsaddress = None
		username = None
		password = None
		visible = True
		background_monitoring_shown = False

		try:
			fn = path.expanduser("~") + "/.ups-monitor.conf"
			f = open(fn,"r")
			lines = f.readlines()
			
			for line in lines:
				key, value = split(line,"=")
				key = strip(key)
				value = strip(value)
				if key == "address":
					upsaddress = value
				if key == "username":
					username = value
				if key == "password":
					password = value
				if key == "app_visible":
					if value == "true":
						visible = True
					else:
						visible = False
				if key == "background_monitoring_shown":
					if value == "true":
						background_monitoring_shown = True
					else:
						background_monitoring_shown = False
			f.close()

		except IOError, e:
			pass

		if upsaddress is not None:
			self.config["ups"] = (upsaddress,username,password)

		self.config["visible"] = visible
		self.config["background_monitoring_shown"] = background_monitoring_shown

	
	def monitor_last_ups(self):
		try:
			upsaddress,username,password = self.config["ups"]
			self.monitor(upsaddress,username,password)
		except Exception, e:
			raise NoLastUPSError, "No last UPS to monitor"
			
	def save_config(self):
		debug_print( "Saving config")
		fn = path.expanduser("~") + "/.ups-monitor.conf"
		umask(077)
		f = open(fn,"w")
		if self.ups is not None:
			debug_print("Saving UPS configuration")
			string = "address = " + self.ups.get_address() + "\n"
			f.write(string)
			if  self.ups.get_username()  is not None:
				string = "username = " + self.ups.get_username() + "\n"
				f.write(string)
			if  self.ups.get_password()  is not None:
				string = "password = " + self.ups.get_password() + "\n"
				f.write(string)
		if self.window.get_property("visible"):
			string = "app_visible = true" + "\n"
		else:
			string = "app_visible = false" + "\n"
		f.write(string)
		if self.config["background_monitoring_shown"]:
			string = "background_monitoring_shown = true" + "\n"
		else:
			string = "background_monitoring_shown = false" + "\n"
		f.write(string)
		f.close()
	
	def monitor(self,ups_address,username,password):
		
		try:
			self.update_statusbar("Connecting to  <b>" + ups_address + "</b>...")
			u = UPS(ups_address,username,password)
			u.connect()
		except InvalidAddressError, e:
			self.show_error_dialog("The UPS address <b>" + ups_address + "</b> cannot be contacted or is incorrect.  Please make sure that the server address is correct, the UPS server is working and it has an active network connection.","Cannot monitor " + ups_address)
			self.update_statusbar("Cannot monitor <b>" + ups_address + "</b>",False)
			return False
		except AuthenticationFailedError, e:
			self.show_error_dialog("The supplied user name or password for <b>" + ups_address + "</b> is incorrect.  Please make sure you typed the password correctly.  If all else fails, contact your network UPS administrator.", "Cannot monitor " + ups_address)
			self.update_statusbar("Cannot monitor <b>" + ups_address + "</b>",False)
			return False
		except UPSNotFoundError, e:
			self.show_error_dialog("UPS <b>" + ups_address + "</b> is not attached to the server.  Please confirm that you entered the correct UPS name." , "Cannot monitor " + ups_address)
			self.update_statusbar("Cannot monitor <b>" + ups_address + "</b>",False)
			return False
		
 		if self.ups:
 			self.ups.stop_monitoring()
		
		self.ups = u
 		self.update_statusbar("Connected to <b>"  + get_friendly_computer_name(u.get_address()) + "</b>")
		self.ups.start_monitoring(self.refresh_display,self.refresh_display)
			
		return True


	def refresh_display(self):
		if not self.ups.is_connected() or not self.ups.is_monitoring():
			self.show_error_dialog("The network connection to <b>" + get_friendly_computer_name(self.ups.get_host()) +"</b> is lost.  Check for network availability and ensure the UPS server is still online and running.","UPS " + self.ups.get_address() + " is no longer being monitored")
			self.update_statusbar("Cannot continue monitoring <b>" + self.ups.get_address() + "</b>",False)
			self.disable_display()
			self.tray_icon.set_error("The network connection to " + get_friendly_computer_name(self.ups.get_host()) + " is lost.  UPS monitoring stopped.")

			self.ups = None
			self.timeout_id = None
			return False
		
		u = self.ups
		

		if u.status == "OK":
			self.enable_display()
			self.tray_icon.set_error(None)
		if u.status == "DRIVER-NOT-CONNECTED":
	 		self.update_statusbar(get_friendly_computer_name(u.get_host()).capitalize() + " lost contact with UPS <b>" + u.get_ups_name() + "</b>", False)
			self.disable_display()
			self.tray_icon.set_error(get_friendly_computer_name(u.get_host()).capitalize() + " lost contact with UPS " + u.get_ups_name() + "")
			return True
		if u.status == "DATA-STALE":
	 		self.update_statusbar(get_friendly_computer_name(u.get_host()).capitalize() + " has stale information about UPS <b>"  + u.get_ups_name()  + "</b>", False)
			self.disable_display()
			self.tray_icon.set_error(get_friendly_computer_name(u.get_host()).capitalize() + " has stale information about UPS "  + u.get_ups_name()  + "")
			return True
					
		if u.manufacturer:
			self.get_widget("label_manufacturer").set_text(u.manufacturer)
		else:
			self.get_widget("label_manufacturer").set_text("(unknown)")
		
		if u.model:
			self.get_widget("label_model").set_text(u.model)
		else:
			self.get_widget("label_model").set_text("(unknown)")
		
		if u.serial:
			self.get_widget("label_serial").set_text(u.serial)
		else:
			self.get_widget("label_serial").set_text("(unknown)")


		if u.power_source == "AC":
	 		self.update_statusbar("UPS <b>"  + u.get_ups_name()  + "</b> attached to <b>" + get_friendly_computer_name(u.get_host())  + "</b> is <b>on AC power</b>")
			self.tray_icon.set_alarm(None)
			self.tray_icon.set_power_source("AC")
			if self.little_time_left_warning:
				self.dismiss_warning_dialog()
	 			self.little_time_left_warning = None
			if self.session_saved:
				self.session_saved = None
			self.get_widget("label_power_source").set_text("Wall socket")

		elif u.power_source == "BAT":
			self.get_widget("label_power_source").set_text("Battery backup")
			self.tray_icon.set_power_source("BAT")
			if self.session_saved is None:
				self.session_saved = True
				self.save_session()

			if u.remaining_time is not None and u.remaining_time < 60:
				self.tray_icon.set_alarm("Less than a minute of battery power remaining")
				if self.little_time_left_warning is None:
					self.little_time_left_warning = True
			 		self.update_statusbar("UPS <b>"  + u.get_ups_name()  + "</b> attached to <b>" + get_friendly_computer_name(u.get_host())  + "</b> is <b>low on battery</b>")
					self.show_warning_dialog(get_friendly_computer_name(u.get_host()).capitalize() + " will power off soon to prevent long-term UPS battery damage, unless utility power returns. Save any open documents and close your session.","Less than a minute of battery power remaining")
			else:
		 		self.update_statusbar("UPS <b>"  + u.get_ups_name()  + "</b> attached to <b>" + get_friendly_computer_name(u.get_host())  + "</b> is <b>on battery backup</b>")
				self.tray_icon.set_alarm(None)

		else:
	 		self.update_statusbar("UPS <b>"  + u.get_ups_name()  + "</b> attached to <b>" + get_friendly_computer_name(u.get_host())  + "</b> is online")
			self.get_widget("label_power_source").set_text("(unknown)")
			
		self.last_power_source = u.power_source
		
		if u.battery_status == "NORMAL":
			self.get_widget("label_battery_status").set_text("OK")
		elif u.battery_status == "LOW":
			self.get_widget("label_battery_status").set_text("Low")
		elif u.battery_status == "REPLACE":
			self.get_widget("label_battery_status").set_text("Needs replacement")
		else:
			self.get_widget("label_battery_status").set_text("(unknown)")

		if u.ups_status == "NORMAL":
			self.get_widget("label_ups_status").set_text("Normal")
		elif u.ups_status == "BYPASS":
			self.get_widget("label_ups_status").set_text("Backup unavailable")
		elif u.ups_status == "CALIBRATING":
			self.get_widget("label_ups_status").set_text("Calibrating")
		elif u.ups_status == "OFFLINE":
			self.get_widget("label_ups_status").set_text("Offline")
		elif u.ups_status == "OVERLOADED":
			self.get_widget("label_ups_status").set_text("Overloaded")
		elif u.ups_status == "TRIMMING":
			self.get_widget("label_ups_status").set_text("Limiting high voltage")
		elif u.ups_status == "BOOSTING":
			self.get_widget("label_ups_status").set_text("Boosting low voltage")
		else:
			self.get_widget("label_ups_status").set_text("(unknown)")
		
		if u.battery_voltage:
			self.get_widget("label_battery_voltage").set_text(str(u.battery_voltage) + " V")
		else:
			self.get_widget("label_battery_voltage").set_text("(unknown)")

		if u.battery_charge:
			self.get_widget("meter_battery_charge").set_text(str(int(u.battery_charge*100)) + "%")
			self.get_widget("meter_battery_charge").set_fraction(u.battery_charge)
		else:
			self.get_widget("meter_battery_charge").set_text("(unknown)")
			self.get_widget("meter_battery_charge").set_fraction(0.0)
		
		if u.ups_load:
			self.get_widget("meter_ups_load").set_text(str(int(u.ups_load*100)) + "%")
			if u.ups_load <= 1:
				self.get_widget("meter_ups_load").set_fraction(u.ups_load)
			else:
				self.get_widget("meter_ups_load").set_fraction(1.0)
				
		else:
			self.get_widget("meter_ups_load").set_text("(unknown)")
			self.get_widget("meter_ups_load").set_fraction(0.0)
		
		if u.remaining_time:
			self.get_widget("meter_remaining_time").set_text(str(u.remaining_time) + " seconds")
			self.get_widget("meter_remaining_time").set_fraction(float(u.remaining_time)/u.max_remaining_time)
				
		else:
			self.get_widget("meter_remaining_time").set_text("(unknown)")
			self.get_widget("meter_remaining_time").set_fraction(0.0)
		

		return True
			
						
	def prepare_prefs_window(self,caller=None):

		localupses = None
		
		combobox = self.get_widget("hbox_local_upses").get_data("combo")
		if not combobox:
			combobox = gtk.Combo()
			combobox.set_sensitive(False)
			self.get_widget("hbox_local_upses").pack_end(combobox)
			self.get_widget("hbox_local_upses").set_data("combo",combobox)
			combobox.show()
		
		try:
			localupses = read_ups_config("/etc/ups/ups.conf").keys()
 			combobox.set_popdown_strings(localupses)
			self.get_widget("radio_local_upses").set_sensitive(True)
			combobox.set_sensitive(True)
			self.get_widget("radio_local_upses").set_active(True)
		except Exception:
			pass

		if self.ups:
			if find(self.ups.get_address(),"@localhost") != -1 and self.get_widget("radio_local_upses").get_property("sensitive"):
				addr = self.ups.get_address()[:find(self.ups.get_address(),"@localhost")]
				self.get_widget("hbox_local_upses").get_data("combo").get_children()[0].set_text(addr)
				self.get_widget("radio_local_upses").set_active(True)
			else:
				self.get_widget("ups_address").set_text(self.ups.get_address())
				self.get_widget("radio_network_upses").set_active(True)

			if self.ups.get_username() is not None:
				self.get_widget("authenticate").set_active(True)
				self.get_widget("username").set_text(self.ups.get_username())
			if self.ups.get_password() is not None:
				self.get_widget("authenticate").set_active(True)
				self.get_widget("password").set_text(self.ups.get_password())

		if self.get_widget("radio_local_upses").get_active():
			combobox.get_children()[0].grab_focus()
		else:
			self.get_widget("ups_address").grab_focus()
								
	def update_auth_container_status(self,caller):
		if self.get_widget("authenticate").get_active():
			for a in ["label_username","label_password","username","password"]:
				self.get_widget(a).set_sensitive(True)
		else:
			for a in ["label_username","label_password","username","password"]:
				self.get_widget(a).set_sensitive(False)

	def process_radio_local_upses(self,caller):
		self.get_widget("hbox_local_upses").get_data("combo").set_sensitive(caller.get_active())
			
	def process_radio_network_upses(self,caller):
		self.get_widget("ups_address").set_sensitive(caller.get_active())
			
	
	def process_prefs_ok(self,caller):
		cont = True
		if self.get_widget("radio_local_upses").get_active():
			combobox = self.get_widget("hbox_local_upses").get_data("combo")
			addr = combobox.get_children()[0].get_text()
		else:
			addr = self.get_widget("ups_address").get_text()
		if len(addr) < 1 :
			cont = False
			self.show_info_dialog("Please choose an UPS or enter the full UPS address (ups@server) before continuing")
		if self.get_widget("authenticate").get_active():
			user = self.get_widget("username").get_text()
			password = self.get_widget("password").get_text()
			if len(user) < 1 or len(password) < 1:
				cont = False
				self.show_info_dialog("Please type in a user name and a password before continuing")
		else:
			user = None
			password = None
		
		if cont:
			
			if self.monitor(addr,user,password) is True:
				self.hide_prefs_window()

	def process_prefs_cancel(self,caller):
		self.hide_prefs_window()
		

	def open_website(self,caller = None):
		try:
			open_webpage("http://www.amautacorp.com/staff/Rudd-O/ups-monitor/")
		except NoBrowserError, e:
			pass
		
	def open_author_website(self,caller = None):
		try:
			open_webpage("http://www.amautacorp.com/staff/Rudd-O/")
		except NoBrowserError, e:
			pass
		
	def send_mail_to_author(self,caller = None):
		try:
			compose_mail("rudd-o@amautacorp.com")
		except NoBrowserError, e:
			pass
	
	def open_gpl(self,caller = None):
		try:
			open_webpage("http://www.fsf.org/copyleft/gpl.txt")
		except NoBrowserError, e:
			pass
		
		

def main():

	program = gnome.program_init("ups-monitor","0.6")
	program.parse_args()
# 	print program.get_property("gnome-datadir")

	upsaddress = None
	counter = 1
	while counter < len(sys.argv):
		if sys.argv[counter][0:1] != "-":
			upsaddress = sys.argv[counter]
			break;
		if sys.argv[counter][0:4] == "--sm":
			counter += 1
		if sys.argv[counter] == "--screen":
			counter += 1
		
		counter += 1

	app = UPSMonitor(get_shared_path())


	if upsaddress:
		app.monitor(upsaddress,None,None)
	else:
		try:
			app.monitor_last_ups()
		except NoLastUPSError, e:
			try:
				localupses = read_ups_config("/etc/ups/ups.conf").keys()
				if len(localupses) == 1:
					app.monitor(localupses[0] + "@localhost",None,None)
			except OSError, e:
				debug_print("No ups.conf")
			except IOError, e:
				debug_print("No ups.conf")
			
	gtk.threads_init()

	gtk.main()


if __name__ == "__main__":
	main()
