#!/usr/bin/env python
# DHCP Client Exit Hooks Installer
#
# Douglas Thrift
#
# $Id$

import optparse
import os
import re
import sys
import tempfile

HOOKS = 'dhclient-exit-hooks'
VARIABLES = {
	'tunnelbroker': {
		'pass': None,
		'user_id': None,
		'tunnel_id': None,
	},
	'dns': {
		'key': None,
		'secret': None,
	},
}

def parse(hooks, callback):
	functions = re.compile(r'^(%s)\(\)$' % '|'.join(VARIABLES.iterkeys()))
	function = None

	with open(hooks, 'rb') as hooks:
		for line in hooks:
			if line == '}\n':
				function = None
			else:
				match = functions.match(line)

				if match is not None:
					function = match.group(1)

			callback(line, function, VARIABLES.get(function))

if __name__ == '__main__':
	import readline

	parser = optparse.OptionParser(usage = '%prog [options] [DIRECTORY]')

	def variables(option, opt, value, parser, *args, **kwargs):
		variables = VARIABLES.get(value[0])

		if variables is None:
			raise optparse.OptionValueError, '%s unknown function "%s"' % (opt, value[0])

		if value[1] not in variables:
			raise optparse.OptionValueError, '%s unknown variable "%s"' % (opt, value[1])

		parser.values.ensure_value(option.dest, set()).add(value)

	parser.add_option('-f', '--force', action = 'callback', type = 'string', dest = 'force', default = set(), nargs = 2, callback = variables, metavar = 'FUNCTION VARIABLE')

	options, args = parser.parse_args()

	if len(args) != 1:
		parser.error('no directory specified')

	os.umask(077)

	hooks = os.path.join(args[0], HOOKS)

	if os.path.exists(hooks):
		def read(line, function, variables):
			if function is not None:
				match = re.match(r"^\tlocal (%s)='(.*)'$" % '|'.join(variables.iterkeys()), line)

				if match is not None:
					variable, value = match.group(1, 2)

					if (function, variable) not in options.force:
						variables[variable] = value

		parse(hooks, read)

	with tempfile.NamedTemporaryFile('wb', prefix = HOOKS + '.', dir = args[0]) as temp:
		def write(line, function, variables):
			if function is not None:
				match = re.match(r'''^\t(?:read -p '{0} ({1}): ' -r \1|local ({1})=`python -c "(import .+); print (.*'{0} \2: '.*)"`)$'''.format(function, '|'.join(variables.iterkeys())), line)

				if match is not None:
					variable = match.group(1)

					if variable is None:
						variable, imports, python = match.group(2, 3, 4)
					else:
						imports, python = None, None

					value = variables[variable]

					if value is None:
						if python is not None:
							exec imports

							value = eval(python)
						else:
							value = raw_input('%s %s: ' % (function, variable))

					line = "\tlocal %s='%s'\n" % (variable, value)

			temp.write(line)

		parse(HOOKS, write)

		temp.delete = False

	os.rename(temp.name, hooks)
