#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
#
"""Univention Directory Manager command line client program"""
#
# Copyright 2004-2014 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

import locale
import socket
import time
import os
import sys
from univention.config_registry import ConfigRegistry


def get_logfile():
	"""Extract logfile from command line arguments."""
	logfile = ''
	for pos, arg in enumerate(sys.argv):
		if arg.startswith('--logfile='):
			logfile = arg[len('--logfile='):]
		elif arg.startswith('--logfile'):
			try:
				logfile = sys.argv[pos + 1]
			except IndexError:
				print >> sys.stderr, "E: Option --logfile requires an argument"
				sys.exit(1)
	return logfile


def fork_server(sock, socket_path):
	"""Fork UDM command line server."""
	# start new server
	pid = os.fork()
	if pid == 0:  # child
		null = os.open(os.path.devnull, os.O_RDWR)
		os.dup2(null, sys.stdin.fileno())
		os.dup2(null, sys.stdout.fileno())
		os.dup2(null, sys.stderr.fileno())
		argv = ['univention-cli-server']
		logfile = get_logfile()
		if logfile:
			argv.append(logfile)
		os.execv(
				'/usr/share/univention-directory-manager-tools/univention-cli-server',
				argv
				)
	else:  # parent
		os.waitpid(pid, os.P_NOWAIT)

	ucr = ConfigRegistry()
	ucr.load()
	socket_timeout = float(ucr.get('directory/manager/cmd/sockettimeout', 50))
	stime = time.time() + socket_timeout
	while not os.path.exists(socket_path):
		time.sleep(0.1)
		if time.time() > stime:
			print >> sys.stderr, \
					'E: Can`t find running daemon after %s seconds. (No socketfile)' % \
					socket_timeout
			sys.exit(1)

	# this takes a long time if getfqdn(host) is used in cli-server
	connection_timeout = 30
	stime = time.time() + connection_timeout
	while True:
		try:
			sock.connect(socket_path)
			break
		except socket.error:
			time.sleep(0.1)
			if time.time() > stime:
				print >> sys.stderr, \
						'W: Can`t connect daemon after %s seconds.' % \
						connection_timeout
				raise


def get_password():
	"""Query for interactive password."""
	while True:
		pwd1 = raw_input('New password ')
		pwd2 = raw_input('Re-enter new password ')
		if pwd1 == pwd2:
			return pwd1
		print >> sys.stderr, 'password missmatch'


def receive_answer(sock):
	"""Receive complete answer from server."""
	data = ''
	while True:
		buf = sock.recv(1024)
		if len(buf) == 0:
			print >> sys.stderr, 'E: Daemon died.'
			sys.exit(1)
		elif buf[-1] == '\0':
			buf = buf[0:-1]
			data += buf
			break
		else:
			data += buf
	return data


def process_output(output, cmdfile):
	"""Print output and check for errors."""
	result = 0
	if cmdfile == 'univention-passwd':
		for line in output:
			if line == 'passwd error: password alreay used':
				result = 1
			elif line.startswith('passwd error: The password is to short'):
				result = 2
			print line
	else:
		if output[-1] == "OPERATION FAILED":
			result = 3
			output = output [:-1]
		for line in output:
			if isinstance(line, unicode):
				line = line.encode(locale.getpreferredencoding(), 'replace')
			print line
	return result

def _create_socket():
	socket_path = '/tmp/admincli_%d/sock' % os.getuid()
	sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
	try:
		# connect to already running server
		sock.connect(socket_path)
	except socket.error:
		fork_server(sock, socket_path)
	return sock

def _re_create_socket():
	try:
		sock = _create_socket()
	except socket.error:
		print >> sys.stderr, 'E: Can`t connect daemon. Giving up.'
		sys.exit(1)
	return sock

def main():
	"""Forward request to udm-cli-server."""

	try:
		sock = _create_socket()
	except socket.error:
		# try once again
		sock = _re_create_socket()

	cmdfile = os.path.basename(sys.argv[0])
	if cmdfile == 'univention-passwd':
		password = get_password()
		sys.argv += ['--pwd', password]

	sock.send(repr(sys.argv) + '\0')
	data = receive_answer(sock)
	sock.close()

	output = eval(data)
	result = process_output(output, cmdfile)
	sys.exit(result)


if __name__ == '__main__':
	main()
