#!/usr/bin/python 
import sys

import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop

import gobject
import os
import subprocess
import re
from signal import SIGKILL



timeout = 30

#support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if os.path.exists(os.path.join(_dirname,"ChangeLog")):
	sys.path.insert(0, _dirname)
	timeout = 9999

from blueman.main.NetConf import *
from blueman.Functions import dprint
from blueman.main.HalManager import HalManager

time = 0

dhcp_pids = []

def timer(*args):
	global time
	if len(dhcp_pids) == 0:
		time+=1
		if time == timeout:
			loop.quit()
	else:
		time = 0
		
	return True

class conf_service(dbus.service.Object):
	def __init__(self):

		self.bus = dbus.SystemBus();
		self.bus.request_name("org.blueman.Mechanism")
		dbus.service.Object.__init__(self, self.bus, "/")
		
		service = self.bus.get_object('org.freedesktop.PolicyKit', '/')
		self.polkit = dbus.Interface(service, 'org.freedesktop.PolicyKit')

	def confirm_authorization(self, busname, action_id):
		global time
		time = 0
		res = self.polkit.IsSystemBusNameAuthorized(action_id, busname, False)
		
		if res != "yes":
			raise dbus.DBusException, "Not authorized"
	
	
	
	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="sbs", out_signature="", sender_keyword="caller")

	def NetworkSetup(self, ip_address, allow_nat, server_type, caller):
		dprint(ip_address, allow_nat, server_type)
		if ip_address == "reload":
			info = netstatus()
			nc = None
			if info["ip"] != "0" and not nc_is_running():
				if info["type"] == "dnsmasq":
					nc = NetConfDnsMasq(None)
				elif info["type"] == "dhcpd":
					nc = NetConfDhcpd(None)
				
				if nc:
					nc.reload_settings()
			
			return
		
		self.confirm_authorization(caller, "org.blueman.network.setup")
		if ip_address == "0":
			info = netstatus()
			nc = None
			try:
				if info["type"] == "dnsmasq":
					nc = NetConfDnsMasq(None)
				elif info["type"] == "dhcpd":
					nc = NetConfDhcpd(None)
			except:
				#fallback
				nc = NetConf(None)
			
			nc.uninstall()

		else:
			if ip_chk(ip_address):
				nc = None
				if server_type == "dnsmasq":
					nc = NetConfDnsMasq(ip_address, allow_nat)
				elif server_type == "dhcpd":
					nc = NetConfDhcpd(ip_address, allow_nat)
				if nc:
					nc.install()

			else:
				return dbus.DBusException("IP Invalid")
	
	
	#@dbus.service.signal(dbus_interface='org.blueman.Mechanism', signature='ss')
	#def dhcpStatus(self, interface, status_str):
	#	pass

	#@dbus.service.signal(dbus_interface='org.blueman.Mechanism', signature='sus')
	#def dhcpReturn(self, interface, return_code, bound_to):
	#	pass


	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="s", out_signature="sus", sender_keyword="caller", async_callbacks=("ok", "err"))

	def DhcpClient(self, net_interface, caller, ok, err):
		global bound_to
		self.confirm_authorization(caller, "org.blueman.dhcp.client")
		
		bound_to = "None"
	
		rxp = re.compile("bound to (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) .*")
		
		
		p = subprocess.Popen(["/sbin/dhclient", "-d", "-e", "IF_METRIC=100", "-1", net_interface], bufsize=128, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
		dhcp_pids.append(p.pid)
		
		def on_timeout():
			dprint("Killing dhcpd")
			os.kill(p.pid, SIGKILL)
			return False
		
		
		timeout = gobject.timeout_add(20000, on_timeout)


		def io_callback(source, condition):
			global time, bound_to
			time = 0
			line = p.stdout.readline()
			
			match = rxp.search(line)

			if match:
				bound_to = match.groups()[0]
			
			#line = line.strip("\n")
			
			#self.dhcpStatus(net_interface, line)
			
			if condition != gobject.IO_IN:
				return False
	
			return True

		def child_closed(pid, cond):
			global bound_to
			dprint("closed ", cond)
			gobject.source_remove(timeout)
			dhcp_pids.remove(pid)
			ok(net_interface, int(cond), bound_to)


		gobject.io_add_watch(p.stdout, gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR, io_callback)

		gobject.child_watch_add(p.pid, child_closed)


			
	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="ss", out_signature="", async_callbacks=("ok", "err"))	
	def HalRegisterModemPort(self, rfcomm_device, bd_addr, ok, err):
		halmgr = HalManager()
		dprint("** Registering modem")
		halmgr.register(rfcomm_device, bd_addr, ok, err)

	
	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="s", out_signature="")
	def HalUnregisterModemPortAddr(self, address):
		halmgr = HalManager()
		dprint("** Unregistering modem")
		halmgr.unregister_addr(address)
		
	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="s", out_signature="")
	def HalUnregisterModemPortDev(self, rfcomm_device):
		halmgr = HalManager()
		dprint("** Unregistering modem")
		halmgr.unregister_dev(rfcomm_device)
		
	
	#@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="", out_signature="")
	#def HalUnregisterAllModemPorts(self):
	#	pass
		
		
	@dbus.service.method(dbus_interface='org.blueman.Mechanism', in_signature="", out_signature="")
	def HalRegisterNetDev(self, devicename):
		halmgr = HalManager()
		halmgr.register_netdev(devicename)
	

DBusGMainLoop(set_as_default=True)
loop = gobject.MainLoop()

conf_service()
gobject.timeout_add(1000, timer)


loop.run()

