#!/usr/bin/python2.7 -OO
# -*- coding: utf-8 -*-
#
# Univention UCS@school
#
# Copyright 2007-2017 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/>.

#-> doesn't do:
# check usernames for correct values (no spaces)
# change the user's position in the tree (change the school i.e.)
# select Schools that are separated by kommata
# modify users school or type (pupil/teacher)

#-> needs definition:
# import access rights

# string of problems during process
problem_hints = ""
# separator char in infile (default: \t for Tabulator)
sepchar = '\t'

# wipe the following trailing and leading characters from group names
wipe_char_group = '-'

# dict of existing mail domains
mailDomains = {}

import codecs
import copy
import ipaddr
import optparse
import os
import re
import string
import subprocess
import sys
import tempfile
import time
import traceback

import univention.debug
univention.debug.init('/var/log/univention/ucs-school-import.log', 1, 0)
univention.debug.set_level(univention.debug.MAIN, 4)

import ldap
import ldap.filter
import univention.admin.uldap
import univention.admin.uexceptions
import univention.admin.modules
import univention.admin.objects
import univention.admin.config
import univention.config_registry
import univention.lib.policy_result
from ucsschool.lib.roles import role_pupil, role_teacher, role_staff
from ucsschool.lib.roleshares import roleshare_home_subdir
from ucsschool.lib.models.utils import stopped_notifier, add_stream_logger_to_schoollib
from ucsschool.lib.models.utils import create_passwd


ldap_errors = (ldap.LDAPError, univention.admin.uexceptions.base,)

configRegistry = univention.config_registry.ConfigRegistry()
configRegistry.load()

add_stream_logger_to_schoollib(stream=sys.stdout, name="legacy-import")

baseDN = configRegistry['ldap/base']
domainname = configRegistry['domainname']

emptyLineRe = re.compile(r'^\W*$')

district_enabled = False
if configRegistry.is_true('ucsschool/ldap/district/enable'):
	district_enabled = True

# create edukativ DC by default
school_dcs = configRegistry.get('ucsschool/ldap/default/dcs', 'edukativ')

verified_ous = []
verified_groups = []
verified_group_shares = []

pwLengthOu = {}

cn_pupils = configRegistry.get('ucsschool/ldap/default/container/pupils', 'schueler')
cn_teachers = configRegistry.get('ucsschool/ldap/default/container/teachers', 'lehrer')
cn_teachers_staff = configRegistry.get('ucsschool/ldap/default/container/teachers-and-staff', 'lehrer und mitarbeiter')
cn_admins = configRegistry.get('ucsschool/ldap/default/container/admins', 'admins')
cn_staff = configRegistry.get('ucsschool/ldap/default/container/staff', 'mitarbeiter')

grp_prefix_pupils = configRegistry.get('ucsschool/ldap/default/groupprefix/pupils', 'schueler-')
grp_prefix_teachers = configRegistry.get('ucsschool/ldap/default/groupprefix/teachers', 'lehrer-')
grp_prefix_admins = configRegistry.get('ucsschool/ldap/default/groupprefix/admins', 'admins-')
grp_prefix_staff = configRegistry.get('ucsschool/ldap/default/groupprefix/staff', 'mitarbeiter-')

grp_policy_pupils = configRegistry.get('ucsschool/ldap/default/policy/umc/pupils', 'cn=ucsschool-umc-pupils-default,cn=UMC,cn=policies,%s' % baseDN)
grp_policy_teachers = configRegistry.get('ucsschool/ldap/default/policy/umc/teachers', 'cn=ucsschool-umc-teachers-default,cn=UMC,cn=policies,%s' % baseDN)
grp_policy_admins = configRegistry.get('ucsschool/ldap/default/policy/umc/admins', 'cn=ucsschool-umc-admins-default,cn=UMC,cn=policies,%s' % baseDN)
grp_policy_staff = configRegistry.get('ucsschool/ldap/default/policy/umc/staff', 'cn=ucsschool-umc-staff-default,cn=UMC,cn=policies,%s' % baseDN)

UCRV_serverprofile_option = configRegistry.get('ucsschool/import/set/serverprofile/path', None)
UCRV_netlogon_script_path = configRegistry.get('ucsschool/import/set/netlogon/script/path', None)
UCRV_sambahome = configRegistry.get('ucsschool/import/set/sambahome', None)
UCRV_homedrive = configRegistry.get('ucsschool/import/set/homedrive')
UCRV_create_mail_domain = configRegistry.is_true("ucsschool/import/generate/mail/domain")

generate_logins = configRegistry.is_true('ucsschool/import/generate/logins')

TYPE_DC_ADMINISTRATIVE = 'administrative'
TYPE_DC_EDUCATIONAL = 'educational'


# IP address prefix len conecerning the netmask
default_prefixlen = 24

if not (cn_pupils and cn_teachers and cn_teachers_staff and cn_admins and cn_staff):
	print '''ERROR: Unable to proceed: one of the following UCR variables is not set correctly:
	ucsschool/ldap/default/container/pupils
	ucsschool/ldap/default/container/teachers
	ucsschool/ldap/default/container/teachers-and-staff
	ucsschool/ldap/default/container/staff
	ucsschool/ldap/default/container/admins
'''
	sys.exit(1)


def is_valid_ou_name(name):
	""" check if given OU name is valid """
	return bool(re.match('^[a-zA-Z0-9](([a-zA-Z0-9_]*)([a-zA-Z0-9]$))?$', name))


def is_valid_hostname(name):
	""" check if given hostname is valid """
	return bool(re.match('^[a-zA-Z0-9](([a-zA-Z0-9-_]*)([a-zA-Z0-9]$))?$', name))


# exception classes
class DeleteObjectError(Exception):
	pass


class CreateObjectError(Exception):
	pass


class Hooks(object):
	OBJECTS = ('user', 'group', 'printer', 'computer', 'network', 'router', 'ou')
	OPERATIONS = {'A': 'create', 'M': 'modify', 'D': 'remove'}

	PATH = '/usr/share/ucs-school-import/hooks/'

	def _create_temp_file(self, line):
		tmpfile = tempfile.NamedTemporaryFile()
		tmpfile.write(line)
		tmpfile.flush()
		return tmpfile

	def __run(self, phase, module, action, **kwargs):
		# verify phase
		if action not in Hooks.OPERATIONS:
			return False

		# verify path
		path = os.path.join(Hooks.PATH, '%s_%s_%s.d' % (module, Hooks.OPERATIONS[action], phase))
		if not os.path.isdir(path) or not os.listdir(path):
			return False

		# create temporary file with data
		if 'line' in kwargs:
			kwargs['line'] = kwargs['line'].strip() + "\n"
			tmpfile = self._create_temp_file(kwargs.get('line'))

		# invoke hook scripts
		# <script> <temporary file> [<ldap dn>]
		command = ['run-parts', path]
		if 'line' in kwargs:
			command.extend(('--arg', tmpfile.name))
		if 'dn' in kwargs:
			command.extend(('--arg', kwargs['dn']))

		sys.stdout.flush()
		sys.stderr.flush()
		ret_code = subprocess.call(command)

		# close temporary file (also deletes the file)
		if 'line' in kwargs:
			tmpfile.close()

		return ret_code == 0

	def pre(self, module, action, **kwargs):
		return self.__run('pre', module, action, **kwargs)

	def post(self, module, action, **kwargs):
		return self.__run('post', module, action, **kwargs)


hooks = Hooks()


class ucsschool_person_modify:

	def __init__(self, line):

		# parse line here
		parsed = line.strip('\r\n').split(sepchar)

		self.modtype = parsed[0]  # A,M or D: add, modify or delete
		self.login = parsed[1].lower()
		self.sname = parsed[2]  # surename
		self.name = parsed[3]  # first name
		self.sNr = parsed[4]  # schoolNr(s)
		self.cNr = parsed[5]  # classNr
		self.rights = parsed[6]  # users which may change this entry
		self.mail = parsed[7]

		def parseBoolstring(parsed, idx, default='0'):
			res = default
			if len(parsed) > idx:
				if parsed[idx].strip().startswith('1'):
					res = '1'
				elif parsed[idx].strip().startswith('0'):
					res = '0'
			return res

		self.isTeacher = parseBoolstring(parsed, 8)
		self.isActive = parseBoolstring(parsed, 9, default='1')
		self.isStaff = parseBoolstring(parsed, 10)

		if len(parsed) > 11:
			self.password = parsed[11]
		else:
			self.password = None

		self.problem_hints = ""

		if generate_logins:
			if self.isTeacher == "1" or self.isStaff == "1":
				self.login = ('%s.%s' % (self.name[0], self.sname[:8])).lower()
				print "DEBUG: Teacher found: creating login name " + self.login
			else:
				self.login = self.name[:6].lower()
				print "DEBUG: Student found: creating login name " + self.login

		if ',' in self.sNr:
			self.allsNrs = self.sNr.split(',')
			self.sNr = self.allsNrs[0]
			self.other_sNr = self.allsNrs[1:]
		else:
			self.allsNrs = [self.sNr]
			self.other_sNr = []

		# split into multiple class number if comma is present
		if ',' in self.cNr:
			self.cNr = self.cNr.split(',')
		else:
			self.cNr = [self.cNr]
		# wipe invalid character from class numbers
		for i in range(len(self.cNr)):
			self.cNr[i] = self.wipeInvalidCharGroup(self.cNr[i])
		# remove empty strings
		self.cNr = [x for x in self.cNr if x]
		# sort classes
		self.cNr.sort()

	def wipeInvalidCharGroup(self, groupName):
		global wipe_char_group

		ok = False
		while groupName and not ok:
			if groupName[0] in wipe_char_group:
				groupName = groupName[1:]
			else:
				ok = True
		ok = False
		while groupName and not ok:
			if groupName[-1] in wipe_char_group:
				groupName = groupName[0:-1]
			else:
				ok = True
		return groupName

	def getOtherPersons(self):
		persons = []

		for schoolNr in self.other_sNr:
			person = copy.deepcopy(self)
			person.login = ("%s_%s" % (self.login, schoolNr)).lower()
			person.sNr = schoolNr
			person.other_sNr = []  # has no "slave"-accounts
			self.mail = ""  # no extra mail address
			person.cNr = []  # no class in other ou
			person.isTeacher = '0'
			person.isStaff = '0'
			if role_teacher in self.getRole():
				person.isTeacher = '1'
			if role_staff in self.getRole():
				person.isStaff = '1'

			persons.append(person)

		return persons

	def getPosition_dn(self):
		# resolution order for the position is pupil, teacher, staff
		cn = cn_pupils
		if role_teacher in self.getRole() and role_staff in self.getRole():
			cn = cn_teachers_staff
		elif role_teacher in self.getRole():
			cn = cn_teachers
		elif role_staff in self.getRole():
			cn = cn_staff
		return "cn=%s,cn=users,%s" % (cn, getDN(self.sNr))

	def getDN(self):
		return "uid=" + self.login + "," + self.getPosition_dn()

	def default_groups(self):
		default_groups = []

		# default group
		default_groups.append("cn=Domain Users " + self.sNr + ",cn=groups,%s" % (getDN(self.sNr), ))

		for role in self.getRole():
			user_grp_prefix = {role_teacher: grp_prefix_teachers, role_pupil: grp_prefix_pupils, role_staff: grp_prefix_staff}[role]
			if role == role_staff and not configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
				continue
			# class if available
			for cnr in self.cNr:
				default_groups.append("cn=" + cnr + ",cn=klassen,cn=%s,cn=groups,%s" % (cn_pupils, getDN(self.sNr)))

			default_groups.append("cn=%s%s,cn=groups,%s" % (user_grp_prefix, self.sNr, getDN(self.sNr)))

		return default_groups

	def getRole(self):
		"""returns the user's roles"""
		roles = []
		if self.isTeacher == '1':
			roles.append(role_teacher)
		if self.isStaff == '1':
			roles.append(role_staff)
		if not roles:
			roles.append(role_pupil)
		return roles


def extract_district(schoolNr):
	try:
		return schoolNr[:2]
	except IndexError:
		# TODO: add more debug output
		print "ERROR: Unable to extract district from school number: %s' % schoolNr + \
			'\n\tIf you don't use the district model deactivate UCR variable ucsschool/ldap/district/enable"


def getDN(schoolNr, base='school', basedn=baseDN):
	"""
	@param	base Values are either school, district or base
	@return	According to the base a specific part of dn is returned.
			Let's suppose the following school dn:
			ou=SCHOOL,ou=DISTRICT,dc=BASE,dc=DN

			The following is returned
			'base'		-> dc=BASE,dc=DN
			'district'	-> ou=DISTRICT,dc=BASE,dc=DN
			'school'	-> ou=SCHOOL,ou=DISTRICT,dc=BASE,dc=DN
	"""
	dn = '%(school)s%(district)s%(basedn)s'
	values = {'school': 'ou=%s,' % schoolNr, 'district': '', 'basedn': basedn}
	if district_enabled:
		district = extract_district(schoolNr)
		if not district:
			print "ERROR: Unable to continue execution without district number. School number: %s" % schoolNr
			sys.exit(1)
		values['district'] = 'ou=%s,' % district
	if base == 'district':
		values['school'] = ''
	elif base == 'base':
		values['district'] = ''
		values['school'] = ''
	return dn % values


def verify_policy(objdn, schoolNr, policy_dn_list):
	# test if all policy objects exist and if all referenced objects are policy objects
	global problem_hints
	for poldn in policy_dn_list:
		oc = lo.get(poldn, ['objectClass'])
		if not oc:
			print "Object to be referenced does not exist: " + poldn
			problem_hints = problem_hints + "there were problems verifying ou %s: Object to be referenced does not exist: %s\n" % (schoolNr, poldn)
			break
		elif 'univentionPolicy' not in oc['objectClass']:
			print "Object to be referenced is no valid policy: " + poldn
			problem_hints = problem_hints + "there were problems verifying ou %s: Object to be referenced is no valid policy: %s\n" % (schoolNr, poldn)
			break
	else:
		# add univentionPolicyReference if neccessary
		oc = lo.get(objdn, ['objectClass'])
		if 'univentionPolicyReference' not in oc.get('objectClass', []):
			try:
				lo.modify(objdn, [('objectClass', '', 'univentionPolicyReference')])
			except:
				print 'Objectclass univentionPolicyReference cannot be added to %s\n' % (objdn)
				problem_hints = problem_hints + "there were problems verifying ou %s: Objectclass univentionPolicyReference cannot be added to %s\n" % (schoolNr, objdn)
		# add all missing policies
		pl = lo.get(objdn, ['univentionPolicyReference'])
		modlist = []
		for poldn in policy_dn_list:
			if poldn not in pl.get('univentionPolicyReference', []):
				modlist.append(('univentionPolicyReference', '', poldn))
				print 'need to attach policy: %s' % poldn
		try:
			lo.modify(objdn, modlist)
		except:
			print 'Policies %s cannot be referenced to %s\n' % (policy_dn_list, objdn)
			problem_hints = problem_hints + "there were problems verifying ou %s: policies %s cannot be referenced to %s\n" % (schoolNr, policy_dn_list, objdn)


def create_policy(cn, container, values, policy_module):
	"""
	@param cn					name of policy
	@param container			target ldap container
	@param properties			policy object properties
	@param policy_module		UDM module
	returns DN if policy has been created, otherwise None
	"""
	created = False
	exists = False
	verify_containers(container, cn_module, co, lo, superordinate, baseDN, path='policyPath')

	objlist = univention.admin.modules.lookup(
		policy_module, co, lo, scope='one', superordinate=superordinate,
		base=container, filter=univention.admin.filter.expression('cn', cn)
	)
	exists = bool(objlist)
	if not objlist:
		cnpos = univention.admin.uldap.position(baseDN)
		cnpos.setDn(container)
		policy_object = policy_module.object(co, lo, position=cnpos, superordinate=superordinate)
		policy_object.open()
		for k, v in values.iteritems():
			policy_object[k] = v
		try:
			# FIXME: the UDM function create() of simplePolicy does not have a return value
			create_object(policy_object)
			created = True
		except:
			print "WARNING: Error creating policy cn=%s,%s failed" % (cn, container)
			traceback.print_exc(100, sys.stdout)
	return (exists, created)


def object_exists(module, co, lo, scope, superordinate, base, filter, dn):

	objects = univention.admin.modules.lookup(
		module, co, lo, scope=scope,
		superordinate=superordinate,
		base=base, filter=filter)

	if objects:
		if not dn:
			if len(objects) == 1:
				return objects[0]
			return None
		for o in objects:
			if o.dn.lower() == dn.lower():
				return o

	return None


def verify_school_ou(schoolNr, co, lo, baseDN):
	from ucsschool.lib.models import School
	if not School(name=schoolNr).get_udm_object(lo):
		raise SystemExit('ERROR: The specified school %r does not exist.' % (schoolNr,))


def create_school_ou(schoolNr, co, lo, baseDN, dcName=None, ShareFileServer=None, displayName=None, dcNameAdministrative=None):
	global problem_hints

	for verified_ou in verified_ous:
		if schoolNr.lower() == verified_ou.lower():
			print "verify ou for school nr %s already done" % schoolNr
			return True

	# create ucsschool container if it does not exists
	created, dn = verify_container('cn=ucsschool,cn=groups,%s' % baseDN, cn_module, co, lo, superordinate, baseDN, 'groupPath')

	if district_enabled:
		verify_container(getDN(schoolNr, base='district'), ou_module, co, lo, superordinate, baseDN)

	print "verify ou for school nr %s" % schoolNr
	# list of needed sub-containers, the dictionary-key adds the container as default during create in verify_container
	container = {
		'0printerPath': ['cn=printers'],
		'1userPath': ['cn=users', 'cn=%s,cn=users' % cn_pupils, 'cn=%s,cn=users' % cn_teachers, 'cn=%s,cn=users' % cn_admins],
		'2computerPath': ['cn=computers', 'cn=server,cn=computers', 'cn=dc,cn=server,cn=computers'],
		'3networkPath': ['cn=networks'],
		'4groupPath': ['cn=groups', 'cn=%s,cn=groups' % cn_pupils, 'cn=%s,cn=groups' % cn_teachers, 'cn=klassen,cn=%s,cn=groups' % cn_pupils, 'cn=raeume,cn=groups'],
		'5dhcpPath': ['cn=dhcp'],
		'6policyPath': ['cn=policies'],
		'7sharePath': ['cn=shares', 'cn=klassen,cn=shares'],
		'8none': ['cn=dc,cn=server,cn=computers']
	}
	if configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
		container['1userPath'].extend(['cn=%s,cn=users' % cn_staff, 'cn=%s,cn=users' % cn_teachers_staff])
		container['4groupPath'].append('cn=%s,cn=groups' % cn_staff)
	# FIXME: die Policies sollten besser mit der Gruppe verknüpft werden, um
	# z.B. Mitarbeiter und Lehrer im selben Container pflegen zu können
	# container_policies = { 'cn=%s,cn=users' % cn_teachers: ['cn=default-lehrer,cn=UMC,cn=policies,' + baseDN] }
	container_policies = {}

	ou_base = getDN(schoolNr)

	# invoke pre hooks
	if dcName:
		dccn = dcName
	else:
		dccn = ''
	myline = '%s\t%s' % (schoolNr, dccn)
	hooks.pre('ou', 'A', line=myline)

	# verify global dc groups
	groups_administrative = [
		"cn=DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % baseDN,
		"cn=Member-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % baseDN]
	groups_education = [
		"cn=DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % baseDN,
		"cn=Member-Edukativnetz,cn=ucsschool,cn=groups,%s" % baseDN]
	groups_administrativeOU = [
		"cn=OU%s-DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN),
		"cn=OU%s-Member-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN)]
	groups_educationOU = [
		"cn=OU%s-DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN),
		"cn=OU%s-Member-Edukativnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN)]

	if configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
		groups = groups_administrative + groups_education + groups_administrativeOU + groups_educationOU
	else:
		groups = groups_education + groups_educationOU
	for group in groups:
		verify_group(group, co, lo, superordinate, baseDN)

	# add already existing dc (slave) to global dc groups
	# for proper ldap replication
	if dccn:
		dcobject = object_exists(
			server_module, co, lo, 'sub', superordinate, baseDN,
			univention.admin.filter.expression('cn', dccn), None)

		if dcobject:
			zone = "edukativ"
			dcobject.open()
			# TODO FIXME The following snippet does not make any sense:
			# if the DC is member of DC-Verwaltungsnetz then is added again to that group?!? Looks like this code is unused.
			for grp in dcobject['groups']:
				if grp.startswith("cn=DC-Verwaltungsnetz,"):
					zone = "verwaltung"
			groups = []
			if zone == "edukativ":
				groups.append("cn=DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % baseDN)
				groups.append("cn=OU%s-DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN))
			if zone == "verwaltung":
				groups.append("cn=DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % baseDN)
				groups.append("cn=OU%s-DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN))
			modified = False
			for grp in groups:
				if grp not in dcobject['groups']:
					modified = True
					dcobject['groups'].append(grp)
			if modified:
				dcobject.modify()

	created, dn = verify_container(ou_base, ou_module, co, lo, superordinate, baseDN, path='')
	if created:
		# get name of new dc
		finalDCname = 'dc%s-01' % schoolNr.lower()
		if configRegistry.is_true('ucsschool/singlemaster', False):
			finalDCname = configRegistry.get('hostname')
		if dcName:
			finalDCname = dcName

		# if fileserver is not set then use dc name
		if ShareFileServer is None:
			ShareFileServer = finalDCname

		# looking for DN of fileserver
		objects = lo.searchDn(filter='(&(objectClass=univentionHost)(cn=%s))' % ShareFileServer, base=baseDN)
		if len(objects) != 1:
			# no object found
			if ShareFileServer == 'dc%s-01' % schoolNr.lower() or (dcName and ShareFileServer == dcName):
				# ignore warning - dc object will be created later
				ShareFileServer = "cn=%s,cn=dc,cn=server,cn=computers,%s" % (ShareFileServer, getDN(schoolNr))
			else:
				print 'WARNING: sharefileserver "%s" not found! Using "%s" as sharefileserver' % (ShareFileServer, configRegistry.get('hostname'))
				ShareFileServer = configRegistry.get('ldap/hostdn')
		else:
			# use found dn
			ShareFileServer = objects[0]

		lo.modify(dn, [
			('objectClass', '', 'ucsschoolOrganizationalUnit'),
			('ucsschoolClassShareFileServer', '', ShareFileServer),  # set file server for class shares
			('ucsschoolHomeShareFileServer', '', ShareFileServer),  # set file server for home shares
			('displayName', '', displayName),                       # set display name for UCS@school
		])
	else:
		if ShareFileServer is not None:
			print "WARNING: sharefileserver ignored because OU already exists!"
			print "WARNING: please modify school OU via UDM or UMC"
		if displayName is not None:
			lo.modify(ou_base, [('displayName', lo.get(ou_base, ['displayName']).get('displayName', []), [displayName])])

	keys = container.keys()
	keys.sort()
	for path in keys:
		for dn in container[path]:
			if path[1:] == 'none':
				path = ' '
			verify_container('%s,%s' % (dn, ou_base), cn_module, co, lo, superordinate, baseDN, path=path[1:])

	# create groups if not existant
	grp_ouadmins = "cn=%s%s,cn=ouadmins,cn=groups,%s" % (grp_prefix_admins, schoolNr.lower(), baseDN)
	groups = [
		(grp_ouadmins, grp_policy_admins),
		("cn=%s%s,cn=groups,%s" % (grp_prefix_pupils, schoolNr.lower(), getDN(schoolNr)), grp_policy_pupils),
		("cn=%s%s,cn=groups,%s" % (grp_prefix_teachers, schoolNr.lower(), getDN(schoolNr)), grp_policy_teachers),
	]

	if configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
		groups.append(("cn=%s%s,cn=groups,%s" % (grp_prefix_staff, schoolNr.lower(), getDN(schoolNr)), grp_policy_staff), )
	if configRegistry.is_true('ucsschool/import/attach/policy/default-umc-users', True):
		domain_users_school = "cn=Domain Users %s,cn=groups,%s" % (schoolNr.lower(), getDN(schoolNr))
		groups.append((domain_users_school, "cn=default-umc-users,cn=UMC,cn=policies,%s" % (baseDN,)))

	for group, grppolicy in groups:
		verify_group(group, co, lo, superordinate, baseDN)
		if grppolicy and grppolicy.lower() != 'none':
			verify_policy(group, schoolNr, [grppolicy])

	# verify that ouadmin group contains correct OU
	obj = univention.admin.objects.get(group_module, co, lo, position='', dn=grp_ouadmins)
	obj.open()
	admin_option = 'ucsschoolAdministratorGroup'
	if admin_option not in obj.options:
		obj.options.append(admin_option)
	obj['school'] = schoolNr
	obj.modify()

	# In a single server environment the default DHCP container must
	# be set to the DHCP container in the school ou. Otherwise newly
	# imported computers have the DHCP objects in the wrong DHCP container
	dhcpd_ldap_base = configRegistry.get('dhcpd/ldap/base')
	if configRegistry.is_true('ucsschool/singlemaster', False):
		if not dhcpd_ldap_base:
			dhcpd_ldap_base = 'cn=dhcp,%s' % (getDN(schoolNr),)
			univention.config_registry.handler_set(['dhcpd/ldap/base=%s' % (dhcpd_ldap_base,)])

	for dc in school_dcs.split():
		if dcName:
			dccn = dcName
		else:
			if configRegistry.is_true('ucsschool/singlemaster', False):
				dccn = configRegistry.get('hostname')
			else:
				dccn = 'dc%s-01' % schoolNr.lower()

		dcgroups = ["cn=OU%s-DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN), "cn=DC-Edukativnetz,cn=ucsschool,cn=groups,%s" % (baseDN, )]

		if dc == 'verwaltung':
			if not configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
				continue
			if dcName:
				dccn = '%sv' % dcName
			else:
				if configRegistry.is_true('ucsschool/singlemaster', False):
					dccn = configRegistry.get('hostname')
				else:
					dccn = 'dc%sv-01' % schoolNr.lower()  # this is the naming convention, a trailing v for Verwaltungsnetz DCs
			dcgroups = [
				"cn=OU%s-DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN),
				"cn=DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (baseDN, )
			]

		# create server if not exsistant
		objects = univention.admin.modules.lookup(
			computer_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
			filter=univention.admin.filter.expression('cn', dccn)
		)

		# * check if computer exists
		# * if computer is exists, test the following things
		#   * is computer a dc master or dc backup ==> do not add computer to any groups
		#   * is computer a dc slave ==> add computer to groups specified by dcgroups
		#   * is computer no dc ==> return error and exit
		#

		# create server if not existent
		server_exists = (len(objects) > 0)  # cannot create another server with this id
		is_master_or_backup = False
		is_slave = False

		if not server_exists and not dcName:
			try:
				if dc == 'verwaltung':
					grpdn = 'cn=OU%s-DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s' % (schoolNr.lower(), baseDN)
				else:
					grpdn = 'cn=OU%s-DC-Edukativnetz,cn=ucsschool,cn=groups,%s' % (schoolNr.lower(), baseDN)
				hostlist = lo.get(grpdn, ['uniqueMember']).get('uniqueMember', [])
			except ldap.NO_SUCH_OBJECT:
				hostlist = []
			except Exception, e:
				print 'ERROR: cannot read %s: %s' % (grpdn, e)

			if hostlist:
				continue  # if at least one DC has control over this OU then jump to next 'school_dcs' item

		if server_exists:
			# check if existing system is a DC master or DC backup
			masterobjs = univention.admin.modules.lookup(
				dcmaster_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
				filter=univention.admin.filter.expression('cn', dccn)
			)
			backupobjs = univention.admin.modules.lookup(
				dcbackup_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
				filter=univention.admin.filter.expression('cn', dccn)
			)
			is_master_or_backup = (masterobjs or backupobjs)
			# check if existing system is a DC slave
			slaveobjs = univention.admin.modules.lookup(
				server_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
				filter=univention.admin.filter.expression('cn', dccn)
			)
			is_slave = len(slaveobjs) > 0

			if dcName:
				# manual dc name has been specified by user

				if not is_master_or_backup and not is_slave:
					print 'WARNING: given system name %s is already in use and no domaincontroller system. Please choose another name' % dcName
					sys.exit(1)

				if is_master_or_backup and is_slave:
					print 'ERROR: implementation error: %s seems to be dc slave and dc master at the same time' % dcName
					sys.exit(1)

				if len(slaveobjs) > 1:
					print 'ERROR: more than one system with cn=%s found' % dcName
					sys.exit(1)

				if is_slave:
					obj = slaveobjs[0]
					obj.open()
					for dcgroup in dcgroups:
						if dcgroup not in obj["groups"]:
							obj["groups"].append(dcgroup)
					modify_object(obj)

		if not server_exists:
			position.setDn("cn=dc,cn=server,cn=computers," + getDN(schoolNr))
			object = server_module.object(co, lo, position=position, superordinate=superordinate)
			object.open()
			object["name"] = dccn
			object["unixhome"] = "/dev/null"
			object["shell"] = "/bin/bash"
			object["primaryGroup"] = "cn=DC Slave Hosts,cn=groups,%s" % baseDN
			for dcgroup in dcgroups:
				if dcgroup not in object["groups"]:
					object["groups"].append(dcgroup)
			try:
				create_object(object)
			except:
				pass
			print "need to create server: %s" % object.dn

		move_dhcp_server(schoolNr, dccn, dhcpd_ldap_base)

	if schoolNr not in verified_ous:
		verified_ous.append(schoolNr)

	# if requested, then create dhcp_dns policy that clears univentionDhcpDomainNameServers at OU level
	# to prevent problems with "wrong" DHCP DNS policy connected to ldap base
	if configRegistry.is_true('ucsschool/import/generate/policy/dhcp/dns/clearou', False):
		name = 'dhcp-dns-clear'
		container = 'cn=policies,%s' % getDN(schoolNr)
		dn = 'cn=%s,%s' % (name, container)
		values = {
			'name': name,
			'emptyAttributes': ['univentionDhcpDomainNameServers'],
		}
		exists, created = create_policy(name, container, values, policy_dhcp_dns_module)
		if not created and not exists:
			print "Policy object %s cannot be created" % dn
			problem_hints = problem_hints + "there were problems creating policy object %s\n" % dn
		else:
			if not getDN(schoolNr) in container_policies:
				container_policies[''] = [dn]
			else:
				container_policies[''].append(dn)

	# attach policies if needed
	for cnpart in container_policies.keys():
		# verify for each container that container does exist
		containerdn = '%s,%s' % (cnpart, ou_base)
		if not cnpart:
			containerdn = ou_base
		else:
			verify_container(containerdn, cn_module, co, lo, superordinate, baseDN, '')
		pollist = container_policies[cnpart]

		# test if all policy objects exist and if all referenced objects are policy objects
		for poldn in pollist:
			oc = lo.get(poldn, ['objectClass'])
			if not oc:
				print "Object to be referenced does not exist: " + poldn
				problem_hints = problem_hints + "there were problems verifying this ou %s\n" % schoolNr
				break
			elif 'univentionPolicy' not in oc['objectClass']:
				print "Object to be referenced is no valid policy: " + poldn
				problem_hints = problem_hints + "there were problems verifying this ou %s\n" % schoolNr
				break
		else:
			# add univentionPolicyReference if neccessary
			oc = lo.get(containerdn, ['objectClass'])
			if 'univentionPolicyReference' not in oc.get('objectClass', []):
				lo.modify(containerdn, [('objectClass', '', 'univentionPolicyReference')])
			# add all missing policies
			pl = lo.get(containerdn, ['univentionPolicyReference'])
			modlist = []
			for poldn in pollist:
				if not poldn.lower() in map(lambda x: x.lower(), pl.get('univentionPolicyReference', [])):
					modlist.append(('univentionPolicyReference', '', poldn))
					print 'need to attach policy: %s' % poldn
			lo.modify(containerdn, modlist)

	# invoke post hooks
	if created:
		# for OUs the temporary file contains the LDAP DN
		hooks.post('ou', 'A', dn=ou_base, line=myline)

	if dcNameAdministrative:
		create_dc(co, lo, baseDN, schoolNr, dcNameAdministrative, TYPE_DC_ADMINISTRATIVE)
		move_dhcp_server(schoolNr, dcNameAdministrative, dhcpd_ldap_base)


def move_dhcp_server(schoolNr, dccn, dhcpd_ldap_base):
	global problem_hints
	# create dhcp-service if not existant
	objects = univention.admin.modules.lookup(
		dhcp_service_module, co, lo, scope='sub', superordinate=superordinate,
		base=baseDN, filter=univention.admin.filter.expression('cn', schoolNr.lower()))
	service_exists = 0
	if objects:
		service = "cn=%s,cn=dhcp,%s" % (schoolNr, getDN(schoolNr))
		for object in objects:
			if object.dn.lower() == service.lower():
				service_exists = 1
				dhcp_service_object = object
				break
	if not service_exists:
		position.setDn("cn=dhcp,%s" % (getDN(schoolNr), ))
		object = dhcp_service_module.object(co, lo, position=position, superordinate=superordinate)
		object.options.append('options')
		object.open()
		object["service"] = schoolNr.lower()
		object['option'] = ['wpad "http://%s.%s/proxy.pac"' % (dccn, domainname)]
		try:
			create_object(object)
		except:
			pass
		dhcp_service_object = object
		print "need to create dhcp service: %s" % object.dn

	# create dhcp-server if not exsistant
	objects = lo.searchDn(filter='(&(objectClass=dhcpServer)(cn=%s))' % dccn, base=baseDN)
	if objects:
		# move existing dhcp server object to OU
		newDHCPServerDN = "cn=%s,cn=%s,cn=dhcp,%s" % (dccn, schoolNr.lower(), getDN(schoolNr))
		if len(objects) > 1:
			print 'WARNING: more than one dhcp-server object found! Moving only one!'
		obj = univention.admin.objects.get(dhcp_server_module, co, lo, position='', dn=objects[0])
		obj.open()
		dhcpServerContainer = ','.join(objects[0].split(',')[1:])

		# only move if
		# - in multiserver environments OR
		# - desired dhcp server DN matches with UCR config
		if not(configRegistry.is_true('ucsschool/singlemaster', False)) or (newDHCPServerDN.endswith(',%s' % dhcpd_ldap_base)):
			if obj.dn.lower() != newDHCPServerDN.lower():
				attr_server = obj["server"]
				print "need to remove dhcp server: %s" % obj.dn
				try:
					obj.remove()
				except:
					print "Failed to remove dhcp server: %s" % (obj.dn, )
					problem_hints = problem_hints + "there were problems verifying this ou %s\n" % schoolNr
				position.setDn("cn=%s,cn=dhcp,%s" % (schoolNr.lower(), getDN(schoolNr)))
				print "need to create dhcp server: %s" % (position.getDn(), )
				object = dhcp_server_module.object(co, lo, position=position, superordinate=dhcp_service_object)
				object.open()
				object["server"] = attr_server
				try:
					create_object(object)
				except:
					print "Failed to create dhcp server: %s" % (position.getDn(), )
					problem_hints = problem_hints + "there were problems verifying this ou %s\n" % schoolNr
		#
		# copy subnets #
		#
		# find local interfaces
		interfaces = []
		for interface_name in set([key.split('/')[1] for key in configRegistry.keys() if key.startswith('interfaces/eth')]):
			try:
				address = ipaddr.IPv4Network('%s/%s' % (
					configRegistry['interfaces/%s/address' % interface_name],
					configRegistry['interfaces/%s/netmask' % interface_name],
				))
				interfaces.append(address)
			except ValueError, error:
				print "Skipping invalid interface %s:\n%s" % (interface_name, error, )
		objects = lo.searchDn(filter='(objectClass=univentionDhcpSubnet)', base=dhcpServerContainer)
		for objectDN in objects:
			object = univention.admin.objects.get(dhcp_subnet_module, co, lo, position='', dn=objectDN)
			object.open()
			subnet = ipaddr.IPv4Network('%s/%s' % (object['subnet'], object['subnetmask'], ))
			if subnet in interfaces:  # subnet matches any local subnet
				position.setDn("cn=%s,cn=dhcp,%s" % (schoolNr.lower(), getDN(schoolNr)))
				if lo.searchDn(filter='(&(objectClass=univentionDhcpSubnet)(cn=%s))' % object['subnet'], base=position.getDn()):
					print "do not need to copy dhcp subnet %s: %s (target already exists)" % (subnet, object.dn, )
				else:
					print "need to copy dhcp subnet %s: %s" % (subnet, object.dn, )
					newobject = dhcp_subnet_module.object(co, lo, position=position, superordinate=dhcp_service_object)
					newobject.open()
					for key in object.keys():
						value = object[key]
						newobject[key] = value
					try:
						create_object(newobject)
					except:
						print "Failed to copy dhcp subnet %s to %s" % (object.dn, position.getDn(), )
						problem_hints = problem_hints + "there were problems verifying this ou %s\n" % schoolNr
			else:
				print "Skipping non-local subnet %s" % subnet
	else:
		# create fresh dhcp server object
		position.setDn("cn=%s,cn=dhcp,%s" % (schoolNr.lower(), getDN(schoolNr)))
		object = dhcp_server_module.object(co, lo, position=position, superordinate=dhcp_service_object)
		object.open()
		object["server"] = dccn
		print "need to create dhcp server: %s" % object.dn
		try:
			create_object(object)
		except:
			pass


def move_object(o, newdn):
	if o.dn == newdn:
		return

	try:
		print 'moving object: old DN=%s   new DN=%s' % (o.dn, newdn)
		o.move(newdn)
	except univention.admin.uexceptions.noObject:
		print "ERROR while moving object %s: object not found" % o.dn
		print 'ERROR:', sys.exc_info()[0], sys.exc_info()[1]
		traceback.print_exc(100, sys.stdout)
	except univention.admin.uexceptions.ldapError:
		print "ERROR while moving object %s: ldap error" % o.dn
		print 'ERROR:', sys.exc_info()[0], sys.exc_info()[1]
		traceback.print_exc(100, sys.stdout)
	except univention.admin.uexceptions.invalidOperation, msg:
		print "ERROR while moving object %s: invalid operation: %s" % (o.dn, msg)
		print 'ERROR:', sys.exc_info()[0], sys.exc_info()[1]
		traceback.print_exc(100, sys.stdout)


def modify_object(o):
	try:
		o.modify()
		print 'modifed object:', o.dn
	except:
		print "ERROR while modifying object %s" % o.dn
		print 'ERROR:', sys.exc_info()[0], sys.exc_info()[1]
		traceback.print_exc(100, sys.stdout)


def create_object(o, ignore_exists=False):
	exists = False
	msg = ''
	dn = None
	try:
		dn = o.create()
		print 'creating object', dn
	except univention.admin.uexceptions.objectExists:
		if not ignore_exists:
			msg = 'ERROR: Object exists-1 (objectExists)'
		else:
			exists = True
	except univention.admin.uexceptions.uidAlreadyUsed:
		if not ignore_exists:
			msg = 'ERROR: Object exists-2 (uidAlreadyUsed)'
		else:
			exists = True
	except univention.admin.uexceptions.dhcpServerAlreadyUsed:
		if not ignore_exists:
			msg = 'ERROR: Object exists-3 (dhcpServerAlreadyUsed)'
		else:
			exists = True
	except univention.admin.uexceptions.noLock:
		if not ignore_exists:
			msg = 'ERROR: Object exists-4 (noLock)'
		else:
			exists = True

	if msg:
		print msg
		raise CreateObjectError(exists, dn)

	return (exists, dn)


def verify_containers(position_dn, module, co, lo, superordinate, base, path=""):
	"""
	verifies all containers starting at the ldap base

	@param	module	Param is ignored! cn_module is the only supported module!!
	"""
	split_dn = position_dn.split(',')
	# with this variable it's ensured that within a row of containers there is
	# no other object/container which can not be created with method
	started_cn_row = False
	for i in xrange(len(split_dn) - 1, -1, -1):
		if split_dn[i].startswith('cn='):
			verify_container(','.join(split_dn[i:]), cn_module, co, lo, superordinate, base, path=path)
			started_cn_row = True
		elif started_cn_row:
			# found an object/container that can not be created
			break


def verify_container(position_dn, module, co, lo, superordinate, base, path="userPath"):
	"""
	look if goal-container exists, else create it
	"""
	container_exists = 0
	type = position_dn[0:string.find(position_dn, "=")]
	name = position_dn[string.find(position_dn, "=") + 1:string.find(position_dn, ",")]
	position = position_dn[string.find(position_dn, ",") + 1:]
	objects = ''
	try:
		objects = univention.admin.modules.lookup(
			module, co, lo, scope='sub', superordinate=superordinate,
			base=position, filter=univention.admin.filter.expression(type, name))
	except:
		pass
	if objects:
		for object in objects:
			if codecs.latin_1_encode(univention.admin.objects.dn(object))[0].lower() == position_dn.lower():
				container_exists = 1
				break

	created = False
	dn = None
	if not container_exists:
		print "need to create container %s" % position_dn
		position = univention.admin.uldap.position(base)
		position.setDn(position_dn[string.find(position_dn, ",") + 1:])
		object = module.object(co, lo, position, superordinate=superordinate)
		object.open()
		object["name"] = position_dn[3:string.find(position_dn, ",")]

		if position_dn[:2] == "cn" and path and not name == "users":  # is path container
			object[path] = codecs.latin_1_encode("1")[0]

		try:
			exists, dn = create_object(object)
			created = True
		except CreateObjectError, e:
			exists, dn = e.args

	return (created, dn)


def verify_group_share(schoolNr, classNr, co, lo, superordinate, base):

	if (schoolNr, classNr.lower()) in verified_group_shares:
		return True

	position_dn = "cn=%s,cn=klassen,cn=shares,%s" % (classNr, getDN(schoolNr, basedn=base))
	module = univention.admin.modules.get("shares/share")
	position_basedn = univention.admin.uldap.position(baseDN)
	univention.admin.modules.init(lo, position_basedn, module)
	more_instances = 1
	container_position = base
	while more_instances:
		container_position = position_dn[string.rfind(position_dn, ",", 0, len(position_dn) - len(container_position) - 1) + 1:]
		if container_position == position_dn:
			more_instances = 0
		elif container_position[:2] == "cn":
			verify_container(container_position, cn_module, co, lo, superordinate, base, path="groupPath")
		elif container_position[:2] == "ou":
			verify_container(container_position, ou_module, co, lo, superordinate, base)
		else:
			print "WARNING: unknown container type", container_position

	# look if share exists, else create it
	share_exists = 0
	type = position_dn[0:string.find(position_dn, "=")]
	name = position_dn[string.find(position_dn, "=") + 1:string.find(position_dn, ",")]
	position = position_dn[string.find(position_dn, ",") + 1:]
	objects = univention.admin.modules.lookup(
		module, co, lo, scope='sub', superordinate=superordinate, base=position,
		filter=univention.admin.filter.expression(type, name)
	)
	if objects:
		for object in objects:
			if codecs.latin_1_encode(univention.admin.objects.dn(object))[0].lower() == position_dn.lower():
				share_exists = 1
				break

	if not share_exists:
		print "need to create groupshare %s" % position_dn

		# get gid form corresponding group
		group_dn = "cn=%s,cn=klassen,cn=%s,cn=groups,%s" % (classNr, cn_pupils, getDN(schoolNr, basedn=base))
		gids = lo.get(group_dn, ['gidNumber'])
		gid = 0
		if len(gids) > 1:  # TODO FIXME This doesn't look correct to me - gids is a dict and not a list!
			print "WARNING: more than one corresponding gid found"
			gid = gids["gidNumber"][0]
		elif len(gids) < 1:  # TODO FIXME This doesn't look correct to me - gids is a dict and not a list!
			print "WARNING: no corresponding gid found"
		else:
			gid = gids["gidNumber"][0]

		# set default server
		serverfqdn = "dc%s-01.%s" % (schoolNr.lower(), domainname)

		# get alternative server (defined at ou object if a dc slave is responsible for more than one ou)
		ou_dn = getDN(schoolNr, basedn=base)
		ou_attr_LDAPAccessWrite = lo.get(ou_dn, ['univentionLDAPAccessWrite'])
		alternativeServer_dn = None
		if len(ou_attr_LDAPAccessWrite) > 0:
			alternativeServer_dn = ou_attr_LDAPAccessWrite["univentionLDAPAccessWrite"][0]
			if len(ou_attr_LDAPAccessWrite) > 1:  # TODO FIXME This doesn't look correct to me - ou_attr_LDAPAccessWrite is a dict and not a list!
				print "WARNING: more than one corresponding univentionLDAPAccessWrite found at ou=%s" % schoolNr

		# build fqdn of alternative server and set serverfqdn
		if alternativeServer_dn:
			alternativeServer_attr = lo.get(alternativeServer_dn, ['uid'])
			if len(alternativeServer_attr) > 0:
				alternativeServer_uid = alternativeServer_attr['uid'][0]
				alternativeServer_uid = alternativeServer_uid.replace('$', '')
				if len(alternativeServer_uid) > 0:
					serverfqdn = "%s.%s" % (alternativeServer_uid, domainname)
		# fetch serverfqdn from OU
		result = lo.get(getDN(schoolNr, basedn=base), ['ucsschoolClassShareFileServer'])
		if result:
			serverDomainName = lo.get(result['ucsschoolClassShareFileServer'][0], ['associatedDomain'])
			if serverDomainName:
				serverDomainName = serverDomainName['associatedDomain'][0]
			else:
				serverDomainName = domainname
			result = lo.get(result['ucsschoolClassShareFileServer'][0], ['cn'])
			if result:
				serverfqdn = "%s.%s" % (result['cn'][0], serverDomainName)

		position = univention.admin.uldap.position(base)
		position.setDn(position_dn[string.find(position_dn, ",") + 1:])
		object = module.object(co, lo, position, superordinate=superordinate)
		object.open()
		object["name"] = "%s" % classNr
		object["host"] = serverfqdn
		if configRegistry.is_true('ucsschool/import/roleshare', True):
			object["path"] = "/home/" + os.path.join(schoolNr, "groups/klassen/%s" % (classNr,))
		else:
			object["path"] = "/home/groups/klassen/%s" % (classNr,)
		object["writeable"] = "1"
		object["sambaWriteable"] = "1"
		object["sambaBrowseable"] = "1"
		object["sambaForceGroup"] = "+%s" % classNr
		object["sambaCreateMode"] = "0770"
		object["sambaDirectoryMode"] = "0770"
		object["owner"] = "0"
		object["group"] = gid
		object["directorymode"] = "0770"
		if configRegistry.is_false('ucsschool/default/share/nfs', True):
			try:
				object.options.remove('nfs')  # deactivate NFS
			except ValueError:
				pass
		try:
			create_object(object)
		except:
			pass

	if classNr not in verified_group_shares:
		verified_group_shares.append((schoolNr, classNr.lower()))


def verify_group(position_dn, co, lo, superordinate, base):
	# look if group exists, else create it

	if position_dn in verified_groups:
		return True

	group_exists = 0
	type = position_dn[0:string.find(position_dn, "=")]
	name = position_dn[string.find(position_dn, "=") + 1:string.find(position_dn, ",")]
	position = position_dn[string.find(position_dn, ",") + 1:]

	more_instances = 1
	container_position = base
	while more_instances:
		container_position = position_dn[string.rfind(position_dn, ",", 0, len(position_dn) - len(container_position) - 1) + 1:]
		if container_position == position_dn:
			more_instances = 0
		elif container_position[:2] == "cn":
			verify_container(container_position, cn_module, co, lo, superordinate, base, path="groupPath")
		elif container_position[:2] == "ou":
			verify_container(container_position, ou_module, co, lo, superordinate, base)
		else:
			print "WARNING: unknown container type", container_position

	objects = univention.admin.modules.lookup(
		group_module, co, lo, scope='sub', superordinate=superordinate, base=position,
		filter=univention.admin.filter.expression(type, name)
	)
	if objects:
		for object in objects:
			if codecs.latin_1_encode(univention.admin.objects.dn(object))[0].lower() == position_dn.lower():
				group_exists = 1
				break

	if not group_exists:
		print "need to create group %s" % position_dn
		position = univention.admin.uldap.position(base)
		position.setDn(position_dn[string.find(position_dn, ",") + 1:])
		object = group_module.object(co, lo, position, superordinate=superordinate)
		object.open()
		object["name"] = position_dn[3:string.find(position_dn, ",")]

		try:
			create_object(object)
		except:
			pass

	if position_dn not in verified_groups:
		verified_groups.append(position_dn)


def delete_dn(dn, module, co, lo):

	try:
		lo.search(base=dn, scope="base")
	except univention.admin.uexceptions.noObject:
		return

	position.setDn(dn[string.find(dn, ",") + 1:])
	object = univention.admin.objects.get(module, co, lo, position=position, dn=dn)
	try:
		object.open()
		object.remove()
		print "deleted:", dn
		return True
	except univention.admin.uexceptions.noObject:
		message = 'ERROR: delete this user manually (not found): ' + dn
	except:
		message = 'ERROR: delete this user manually (maybe not found):' + dn

	print message
	traceback.print_exc(100, sys.stdout)
	raise DeleteObjectError(message)


def delete_user(person, module, co, lo):

	success = True

	# delete account
	try:
		delete_dn(person.getDN(), module, co, lo)
	except DeleteObjectError, e:
		person.problem_hints += str(e) + '\n'
		success = False

	return success


def verifyMailDomain(email):

	global mailDomains

	if not UCRV_create_mail_domain:
		return

	if "@" not in email:
		return

	domain = email.rsplit("@", 1)[-1]
	if not mailDomains.get(domain):
		print "need to create mail domain %s " % domain
		pos = univention.admin.uldap.position("cn=domain,cn=mail,%s" % baseDN)
		obj = maildomain_module.object(co, lo, position=pos)
		obj["name"] = domain
		create_object(obj)
		mailDomains[domain] = 1
	return


def modify_user(person, module, co, lo):
	default_groups = person.default_groups()
	object = univention.admin.objects.get(module, co, lo, position='', dn=person.getDN())
	object.open()
	object["username"] = person.login
	object["primaryGroup"] = default_groups[0]
	subdir = roleshare_home_subdir(person.sNr, person.getRole(), configRegistry)
	object["unixhome"] = "/home/" + os.path.join(subdir, person.login)
	object["firstname"] = person.name
	object["lastname"] = person.sname
	object["e-mail"] = person.mail
	if object.has_key('mailPrimaryAddress'):
		object['mailPrimaryAddress'] = person.mail
		verifyMailDomain(person.mail)
	if person.isActive == "1":
		object["disabled"] = "none"
	else:
		object["disabled"] = "all"

	remove_groups = []
	for group in object['groups']:
		if group not in default_groups:
			parts = univention.admin.uldap.explodeDn(group)
			if len(parts) <= 2:
				continue

			# FIXME / TODO
			# Test should be following:
			# if ( ( ( parts[0].startswith( 'cn=%s' % grp_prefix_pupils) or parts[0].startswith( 'cn=%s' % grp_prefix_pupils) ) and parts[1] == 'cn=groups' and parts[2].startswith('ou=') ) or
			# 	 ( parts[1] == 'cn=klassen' and parts[2] == 'cn=%s' % cn_pupils and parts[3] == 'cn=groups' and parts[4].startswith('ou=') ) ):

			if (
				parts[0].startswith('cn=%s' % grp_prefix_pupils) or
				parts[0].startswith('cn=%s' % grp_prefix_teachers) or
				(parts[1] == 'cn=klassen' and parts[2] == 'cn=%s' % cn_pupils)
			):
				# group looks like a default group, so we don't need it anymore
				print "remove from group: %s" % group
				remove_groups.append(group)
	for group in remove_groups:
		object['groups'].remove(group)

	for group in default_groups:
		if group not in object["groups"]:
			object["groups"].append(group)
			verify_group(group, co, lo, superordinate, baseDN)
			print "need to add group %s" % group

	# print "user is in groups: %s" % object['groups']

	for cnr in person.cNr:
		verify_group_share(person.sNr, cnr, co, lo, superordinate, baseDN)

	try:
		object.modify()
		o_sNr = lo.get(person.getDN(), attr=['departmentNumber']).get('departmentNumber', [])
		if not set(o_sNr) == set(person.allsNrs):
			lo.modify(person.getDN(), [("departmentNumber", o_sNr, person.allsNrs)])
		print "modified:", person.getDN()
	except:
		print "ERROR:", sys.exc_info()[0], sys.exc_info()[1]
		traceback.print_exc(100, sys.stdout)
		print "modify this user manually:", person.getDN()
		person.problem_hints = person.problem_hints + "modify this user manually: " + person.getDN() + "\n"


def check_user(person, baseDN, module):
	objects = univention.admin.modules.lookup(
		module, co, lo, scope='sub', superordinate=superordinate,
		base=person.getPosition_dn(),
		filter=univention.admin.filter.expression('uid', person.login))
	if objects:
		for object in objects:
			if object.dn == person.getDN():
				return 1
	return None


def findComputerNameWithService(service, ou):
	computers = univention.admin.modules.lookup(computer_module, co, lo, scope='sub', base=ou, filter=univention.admin.filter.expression('univentionService', service))
	for computer in computers:
		return computer['name']
	return None


def calculateProfilePath(ou):
	if UCRV_serverprofile_option is not None:
		return UCRV_serverprofile_option
	if ou in calculateProfilePath.results:
		return calculateProfilePath.results[ou]
	computer = findComputerNameWithService('Windows Profile Server', ou)
	if computer is not None:
		calculateProfilePath.results[ou] = calculateProfilePath.string % ('\\\\%s' % (computer, ), )
	else:
		calculateProfilePath.results[ou] = calculateProfilePath.string % ('%LOGONSERVER%', )
	return calculateProfilePath.results[ou]


calculateProfilePath.results = {}
calculateProfilePath.string = '%s\\%%USERNAME%%\\windows-profiles\\default'


def tryFindHomeShareFileServer(ouDn):
	# if defined then use UCR value
	if UCRV_sambahome is not None:
		return '\\\\%s' % UCRV_sambahome.strip('\\')
	# in single server environments the master is always the fileserver
	if configRegistry.is_true('ucsschool/singlemaster', False):
		return '\\\\%s' % configRegistry.get('hostname')
	# if there's a cached result then use it
	if ouDn in tryFindHomeShareFileServer.results:
		return tryFindHomeShareFileServer.results[ouDn]
	# get windows home server from OU object
	oulist = univention.admin.modules.lookup(ou_module, co, lo, base=ouDn, scope='base')
	for ou in oulist:
		if ou['ucsschoolHomeShareFileServer']:
			serverlist = univention.admin.modules.lookup(computer_module, co, lo, base=ou['ucsschoolHomeShareFileServer'], scope='base')
			for server in serverlist:
				tryFindHomeShareFileServer.results[ouDn] = '\\\\%s' % server['name']
	return tryFindHomeShareFileServer.results.get(ouDn)


tryFindHomeShareFileServer.results = {}


def calculateSambahomePath(ouDn, username):
	if tryFindHomeShareFileServer(ouDn) is not None:
		return "%s\\%s" % (tryFindHomeShareFileServer(ouDn), username, )


def create_user(person, baseDN, module, password, OUTFILE, line):
	success = True

	if generate_logins:
		try:
			loginname = person.login
			i = 1
			while(check_user(person, baseDN, user_module)):
				print "WARNING: User already exists: %s" % person.getDN()
				person.problem_hints += "WARNING: Username already exists: %s" % person.getDN() + " appended counted number\n"
				person.login = loginname + str(i)
				print "INFO: Trying with new username: ", person.login
				i = i + 1
		except:  # happens if container does not exsist
			pass

	verify_school_ou(person.sNr, co, lo, baseDN)
	# check if needed subtree exists, this should not be neccessary be after
	# verify of the ou but we may crash if someone makes changes by hand
	more_instances = 1
	container_position = baseDN
	while more_instances:
		container_position = person.getPosition_dn()[string.rfind(person.getPosition_dn(), ",", 0, len(person.getPosition_dn()) - len(container_position) - 1) + 1:]
		if container_position == person.getPosition_dn():
			more_instances = 0
		if container_position[:2] == "cn":
			verify_container(container_position, cn_module, co, lo, superordinate, baseDN)
		elif container_position[:2] == "ou":
			verify_container(container_position, ou_module, co, lo, superordinate, baseDN)
		else:
			print "WARNING: unknown container type", container_position

	groups = person.default_groups()
	for group in groups:
		verify_group(group, co, lo, superordinate, baseDN)
	for cnr in person.cNr:
		verify_group_share(person.sNr, cnr, co, lo, superordinate, baseDN)

	position = univention.admin.uldap.position(baseDN)
	position.setDn(person.getPosition_dn())

	object = user_module.object(co, lo, position=position, superordinate=superordinate)
	object.open()

	object["username"] = person.login
	object["primaryGroup"] = groups[0]
	if len(groups) > 1:
		object["groups"] = groups[1:]
	subdir = roleshare_home_subdir(person.sNr, person.getRole(), configRegistry)
	object["unixhome"] = "/home/" + os.path.join(subdir, person.login)
	if object.has_key('mailbox'):
		object["mailbox"] = "/var/spool/%s/" % person.login
	object["password"] = password
	object['overridePWHistory'] = '1'
	object['overridePWLength'] = '1'
	object["firstname"] = person.name
	object["lastname"] = person.sname
	object["e-mail"] = person.mail
	if object.has_key('mailPrimaryAddress'):
		object['mailPrimaryAddress'] = person.mail
		verifyMailDomain(person.mail)
	if person.isActive == "1":
		object["disabled"] = "none"
	else:
		object["disabled"] = "all"

	# Bug #34179: do not set sambaHomePath for staff users
	if set(person.getRole()) != set([role_staff]):
		if UCRV_netlogon_script_path is not None:
			object["scriptpath"] = UCRV_netlogon_script_path
		if calculateSambahomePath(getDN(person.sNr, basedn=baseDN), object["username"]) is not None:
			object["sambahome"] = calculateSambahomePath(getDN(person.sNr, basedn=baseDN), object["username"])
		if UCRV_homedrive:
			object["homedrive"] = UCRV_homedrive
		profilePath = calculateProfilePath(getDN(person.sNr, basedn=baseDN))
		if profilePath:
			object["profilepath"] = profilePath

	try:
		try:
			exists, dn = create_object(object)
			lo.modify(person.getDN(), [("departmentNumber", [], person.allsNrs)])
			print "created:", person.getDN()
			if OUTFILE:
				OUTFILE.write("%s\t%s\t%s" % (person.login, password, line))
		except CreateObjectError:
			success = False
			print "ERROR: there were problems creating this user:", person.getDN()
			person.problem_hints += "ERROR: there were problems creating this user: " + person.getDN() + "\n"

	except:
		success = False
		print "ERROR:", sys.exc_info()[0], sys.exc_info()[1]
		print "ERROR: create this user manually:", person.getDN()
		traceback.print_exc(100, sys.stdout)
		person.problem_hints += "ERROR: create this user manually: " + person.getDN() + "\n"

	return success


def import_user():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  creates/modifies/deletes user accounts according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> user import file"
	parser = optparse.OptionParser(usage=usage)
	parser.add_option("-o", "--outfile", dest="outfile", help="output file with passwords of created users")
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "ERROR: must have one argument for infile"
		sys.exit(1)

	print "infile is: " + infile
	inf = open(infile, 'r')

	# output file
	OUT = None
	if options.outfile:
		if os.path.isfile(options.outfile):
			print "ERROR: outfile exists, will not overwrite existing file"
			sys.exit(1)
		print "outfile is: " + options.outfile
		OUT = open(options.outfile, "w")

	with stopped_notifier():
		problem_hints = ""
		linecnt = 0

		for line in inf:
			linecnt += 1

			if emptyLineRe.match(line):
				print 'Skipping empty line'
				continue

			print 'Processing line %d: %s' % (linecnt, line),
			try:
				main_person = ucsschool_person_modify(line)
			except:
				msg = 'ERROR: Problems parsing line, skipped: %d: %s' % (linecnt, line)
				print msg
				traceback.print_exc(100, sys.stdout)
				problem_hints += msg + '\n'
				continue

			persons = [main_person]
			persons.extend(main_person.getOtherPersons())
			if main_person.password:
				passwd = main_person.password
			else:
				passwd = create_passwd(dn=persons[0].getDN())

			# invoke pre hooks
			hooks.pre('user', main_person.modtype, line=line)

			# variable to store success of operation and LDAP dn
			success = True
			dn = None
			if main_person.modtype == "A":
				for person in persons:
					try:
						result = create_user(person, baseDN, user_module, passwd, OUT, line)
						success = result
					except:
						msg = "ERROR: There were problems creating this user: " + str(person.getDN())
						print msg
						traceback.print_exc(100, sys.stdout)
						person.problem_hints += msg + "\n"
						success = False
					if not dn:
						dn = person.getDN()
			elif main_person.modtype in ["M", "D"]:
				# look if there are existing persons in other ou's remaining, this will fail if the users's departmentNumbers
				# are changed manually
				filter = univention.admin.filter.conjunction("|", [
					univention.admin.filter.expression('uid', "%s_*" % main_person.login),
					univention.admin.filter.expression('uid', "%s" % main_person.login)
				])
				objects = univention.admin.modules.lookup(
					user_module, co, lo, scope='sub', superordinate=superordinate,
					base=baseDN, filter=filter)
				found = []
				for object in objects:
					ou = object.dn[string.find(object.dn, "ou=") + 3:string.find(object.dn, ",", string.find(object.dn, "ou=") + 3)]
					# get from LDAP the user type: teacher, staff or student
					main_person.isTeacher = '0'
					main_person.isStaff = '0'

					if object.dn.endswith(',cn=%s,cn=users,%s' % (cn_teachers_staff, getDN(ou))):
						main_person.isTeacher = '1'
						main_person.isStaff = '1'
					elif object.dn.endswith(',cn=%s,cn=users,%s' % (cn_teachers, getDN(ou))):
						main_person.isTeacher = '1'
					elif object.dn.endswith(',cn=%s,cn=users,%s' % (cn_staff, getDN(ou))):
						main_person.isStaff = '1'

					if ou in main_person.allsNrs:
						found.append(ou)
					else:
						main_person.problem_hints += "delete unmentioned user %s \n" % object.dn
						try:
							delete_dn(object.dn, user_module, co, lo)
						except DeleteObjectError, e:
							success = False
							main_person.problem_hints += str(e) + '\n'

				for person in persons:
					if person.modtype == "M":
						if person.sNr in found:
							try:
								modify_user(person, user_module, co, lo)
							except:
								msg = "ERROR: There were problems modifying this user: " + str(person.getDN())
								print msg
								traceback.print_exc(100, sys.stdout)
								person.problem_hints += msg + "\n"
								success = False
						else:
							try:
								print "WARNING: user to modify not found, ",
								result = create_user(person, baseDN, user_module, passwd, OUT, line)
							except:
								msg = "ERROR: There were problems creating this user: " + str(person.getDN())
								print msg
								traceback.print_exc(100, sys.stdout)
								person.problem_hints += msg + "\n"
								success = False

					else:  # main_person.modtype == "D":
						# NOTE: there is no need for this try-catch-block because delete_dn handles exceptions by itself
						success = delete_user(person, user_module, co, lo)

					if not dn:
						dn = person.getDN()
					main_person.problem_hints += person.problem_hints
			else:
				print "WARNING: unknown operation type:", main_person.modtype
				main_person.problem_hints += "unknown operation type for this user: " + main_person.getDN() + "\n"
				success = False

			problem_hints += main_person.problem_hints

			# invoke post hooks on success
			if success:
				hooks.post('user', main_person.modtype, dn=dn, line=line)

		# close files
		inf.close()
		if OUT:
			OUT.close()

		# report created users
		message = ""
		if not problem_hints == "":
			message = message + "\n\nProblems during last run:\n\n" + problem_hints

		print message


def create_network(schoolNr, network, iprange=None, defaultrouter=None, nameserver=None, netbiosserver=None):
	"""
	@param	network	The network address MUST contain the netmask!! it could also be a ipaddr.IPv4Network object
	@param	defaultrouter	IP-Adress, if no netmask is profided it's derived from network
	@param	nameserver	IP-Adress, if no netmask is profided it's derived from network
	@param	netbiosserver	IP-Adress, if no netmask is profided it's derived from network
	"""
	success = True
	dn = None
	verify_school_ou(schoolNr, co, lo, baseDN)

	if check_network(schoolNr, network):
		print "Network %s/%d exists in school %s!" % (network.network, network.prefixlen, schoolNr)
		return (False, dn)

	print "generate network %s/%d" % (network.network, network.prefixlen)
	if iprange:
		print "iprange: %s-%s" % (iprange[0], iprange[1])
	if defaultrouter:
		print "defaultrouter: %s" % defaultrouter
	if nameserver:
		print "nameserver: %s" % nameserver
	if netbiosserver:
		print "netbiosserver: %s" % netbiosserver

	# WORKAROUND for Bug #14795
	subnetbytes = 0
	tmp = str(network.netmask).split('.')
	for i in tmp:
		if i == '255':
			subnetbytes += 1
		else:
			break
	subnet = '.'.join(str(network.network).split('.')[:subnetbytes])
	# END WORKAROUND

	position.setDn("cn=dns,%s" % (baseDN))
	object = dns_reverse_zone_module.object(co, lo, position=position, superordinate=superordinate)
	object.open()
	object['subnet'] = subnet
	# the nameserver/SOA at the dns_reverse_zone object is always the ldap/master server!
	object['nameserver'] = configRegistry['ldap/master']
	object['contact'] = 'root@%s' % domainname
	try:
		create_object(object, ignore_exists=True)
	except CreateObjectError:
		pass

	position.setDn("cn=%s,cn=dhcp,%s" % (ldap.dn.escape_dn_chars(schoolNr.lower()), getDN(schoolNr)))
	dhcp_service_objects = univention.admin.modules.lookup(
		dhcp_service_module, co, lo, scope='sub', superordinate=superordinate,
		base=baseDN, filter=univention.admin.filter.expression('cn', ldap.filter.escape_filter_chars(schoolNr.lower())))
	if not dhcp_service_objects:
		print 'ERROR: DHCP service object for %r not found' % (schoolNr.lower(),)
		success = False
	else:
		object = dhcp_subnet_module.object(co, lo, position=position, superordinate=dhcp_service_objects[0])
		object.open()
		object['subnet'] = str(network.network)
		object['subnetmask'] = str(network.netmask)
		object['broadcastaddress'] = str(network.broadcast)
		try:
			create_object(object, ignore_exists=True)
		except CreateObjectError:
			print '%r already existed - usually no problem' % (object.dn,)

	position.setDn("cn=networks,%s" % (getDN(schoolNr), ))
	object = network_module.object(co, lo, position=position, superordinate=superordinate)
	object.open()
	object['name'] = '%s-%s' % (schoolNr.lower(), network.network)
	object['netmask'] = str(network.prefixlen)
	object['network'] = str(network.network)
	if iprange:
		object['ipRange'] = [[str(iprange[0]), str(iprange[1])]]
	object['dhcpEntryZone'] = 'cn=%s,cn=dhcp,%s' % (schoolNr.lower(), getDN(schoolNr))
	object['dnsEntryZoneForward'] = 'zoneName=%s,cn=dns,%s' % (domainname, baseDN)
	object['dnsEntryZoneReverse'] = 'zoneName=%s.in-addr.arpa,cn=dns,%s' % ('.'.join(reversed(subnet.split('.'))), baseDN)

	try:
		exists, dn = create_object(object, ignore_exists=True)
	except CreateObjectError:
		success = False

	# set netbios and router for dhcp subnet
	if defaultrouter:
		print 'setting default router'
		set_router_for_subnet(network, defaultrouter, schoolNr)

	if netbiosserver:
		print 'setting netbios server'
		set_netbiosserver_for_subnet(network, netbiosserver, schoolNr)

	# set default value for nameserver
	if nameserver:
		print 'setting nameserver'
		set_nameserver_for_subnet(network, nameserver, schoolNr)

	return (success, dn)


def check_network(schoolNr, network):
	"""
	@param	network	ipaddr.IPv4Network object
	"""
	objects = univention.admin.modules.lookup(
		network_module, co, lo, scope='sub', superordinate=superordinate,
		base='cn=networks,%s' % (getDN(schoolNr)),
		filter=univention.admin.filter.expression('cn', '%s-%s' % (schoolNr.lower(), network.network)))
	if objects:
		n = "cn=%s-%s,cn=networks,%s" % (schoolNr.lower(), network.network, getDN(schoolNr))
		for object in objects:
			if object.dn == n:
				return 1

	return None


def check_macAddress(mac, base=''):
	if not base:
		base = baseDN
	result = lo.search(base=base, scope='sub', filter='(macAddress=%s)' % mac, attr=['macAddress'])

	if result and result[0][1]['macAddress'][0] == mac:
		return result[0][0]


def generate_new_mac(schoolNr, IP):
	ipnum = string.replace(IP, '.', '')
	if IP:
		mac_start = '%s:%s:%s:%s:' % (schoolNr[:2], schoolNr[-2:], ipnum[:2], ipnum[-2:])
	else:
		# FIXME: following line seems to be broken
		mac_start = '%s:%s:00:00:' % (schoolNr[:2], schoolNr[-2:], ipnum[:2], ipnum[-2:])
	mac = '%s00:00' % mac_start
	i = 10
	j = 10
	while check_macAddress(mac, base='cn=computers,%s' % (getDN(schoolNr), )):
		if i == 99:
			i = 10
			j += 1
		else:
			i += 1
		mac = '%s%s:%s' % (mac_start, i, j)

	return mac


def check_computer(module, name, schoolNr):
	objects = univention.admin.modules.lookup(
		module, co, lo, scope='sub', superordinate=superordinate,
		base='cn=computers,%s' % (getDN(schoolNr), ),
		filter=univention.admin.filter.expression('cn', '%s' % name))
	if objects:
		for object in objects:
			if object.dn == "cn=%s,cn=computers,%s" % (name, getDN(schoolNr)):
				return 1
	return None


def get_computer_dn(name):
	objects = univention.admin.modules.lookup(
		computer_module, co, lo, scope='sub', superordinate=superordinate,
		filter=univention.admin.filter.expression('cn', '%s' % name))
	if objects:
		for object in objects:
			if object.dn.startswith("cn=%s," % name):
				return object.dn
	return None


def import_networks(router_only=False):

	# usage
	usage = "%prog [options] <importFile>\n"
	if router_only:
		usage += "  modifies default routers according to import file for UCS@school\n\n"
	else:
		usage += "  creates network objects according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> network import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit()

	print "infile is  : " + infile
	inf = open(infile, 'r')

	with stopped_notifier():
		for line in inf:

			if emptyLineRe.match(line):
				continue

			success = True
			parsed = line.strip('\r\n').split(sepchar)

			schoolNr = parsed[0]
			verify_school_ou(schoolNr, None, lo, baseDN)
			# the network MUST include the netmask
			network = parsed[1]  # netmask new
			# the broadcast address is generated automatically by the
			# combination of network and netmask

			def parseString(parsed, idx, default=None):
				res = default
				if len(parsed) > idx:
					string = parsed[idx]
					if string:
						res = string
				return res
			iprange = parseString(parsed, 2)  # new
			defaultrouter = parseString(parsed, 3)  # new
			nameserver = parseString(parsed, 4)  # new
			netbiosserver = parseString(parsed, 5)  # new

			# invoke pre hooks
			if router_only:
				hooks.pre('router', 'A', line=line)
			else:
				hooks.pre('network', 'A', line=line)
			dn = None
			success = True

			# convert parameters to ipaddr.IPv4Network
			if '/' not in network:
				network = '%s/%s' % (network, default_prefixlen, )
				try:
					network = ipaddr.IPv4Network(network)
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
				print 'WARNING: no netmask specified for network %s using %s' % (network.network, network.netmask)
			else:
				try:
					network = ipaddr.IPv4Network(network)
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
				except ipaddr.NetmaskValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid netmask" % e
					continue

			if iprange:
				tmp = iprange.split('-')
				if len(tmp) != 2:
					print 'ERROR: IP host range not valid: %s' % iprange
					continue
				iprangeStart = ""
				iprangeEnd = ""
				try:
					iprangeStart = ipaddr.IPv4Address(tmp[0])
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
				try:
					iprangeEnd = ipaddr.IPv4Address(tmp[1])
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
				iprange = (iprangeStart, iprangeEnd)
				if iprange[0] < network.network + 1 or iprange[0] > iprange[1] or iprange[1] >= network.broadcast:
					print line.strip()
					print 'ERROR: IP host range not valid: %s-%s' % (iprange[0], iprange[1])
					continue
			elif network.prefixlen == 24:
				iprange = (network.network + 20, network.network + 250)

			if defaultrouter:
				try:
					defaultrouter = ipaddr.IPv4Address(defaultrouter)
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
			if nameserver:
				try:
					nameserver = ipaddr.IPv4Address(nameserver)
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue
			if netbiosserver:
				try:
					netbiosserver = ipaddr.IPv4Address(netbiosserver)
				except ipaddr.AddressValueError, e:
					print line.strip()
					print "ERROR: %s is not a valid ip address" % e
					continue

			if router_only:
				if defaultrouter:
					success, dn = set_router_for_subnet(network, defaultrouter, schoolNr, overwrite_policy=True)
					print 'Router set for subnet.'
				else:
					print 'No router specified for subnet.'
			else:
				success, dn = create_network(schoolNr, network, iprange=iprange, defaultrouter=defaultrouter, nameserver=nameserver, netbiosserver=netbiosserver)

			# invoke post hooks
			if success:
				if router_only:
					hooks.post('router', 'A', dn=dn, line=line)
				else:
					hooks.post('network', 'A', dn=dn, line=line)

		inf.close()


def set_inventory_number_for_computer():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  modifies computer inventory number according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> computer import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit()

	print "infile is  : " + infile
	inf = open(infile, 'r')

	problem_hints = ""

	with stopped_notifier():
		for line in inf:

			if emptyLineRe.match(line):
				continue

			parsed = line.strip('\r\n').split(sepchar)
			ctype = parsed[0]
			name = parsed[1]
			MAC = parsed[2]
			inventoryNumbers = parsed[3].strip().split(',')

			dn = get_computer_dn(name)
			if not dn:
				print "Computer to modify not found: %s" % name
				problem_hints = problem_hints + "Computer to modify not found: %s" % name
			else:
				try:
					computerModule = univention.admin.modules.get("computers/%s" % ctype)
					position_basedn = univention.admin.uldap.position(baseDN)
					univention.admin.modules.init(lo, position_basedn, computerModule)
				except:
					print "failed to get module of type computers/%s" % ctype
					traceback.print_exc(100, sys.stdout)
					problem_hints = problem_hints + "failed to get module of type computers/%s" % ctype
					continue
				computerObject = univention.admin.objects.get(computerModule, co, lo, position='', dn=dn)
				computerObject.open()
				if MAC.replace('-', ':').replace(' ', ':').lower() in computerObject['mac']:
					try:
						computerObject['inventoryNumber'] = inventoryNumbers
						computerObject.modify()
						print "modified inventory Number for %s" % dn
					except:
						print "failed to modify computer %s" % name
						traceback.print_exc(100, sys.stdout)
						problem_hints = problem_hints + "failed to modify computer %s" % name
				else:
					print "mac address does not match while modifying %s" % name
					problem_hints = problem_hints + "mac address does not match while modifying %s" % name

		inf.close()


def set_policy_for_dhcp_subnet(network, schoolNr, policy_module, policy_dn, cn, values=None, overwrite_policy=False):
	"""
	@param	network	network where policy object shall be added
	@param	schoolNr	school number
	"""
	dn = None
	success = True
	if values is None:
		values = {}

	# check if routing policy needs to be created
	dhcp_subnet_object = None
	dhcp_service_list = univention.admin.modules.lookup(dhcp_service_module, co, lo, scope='sub', base=getDN(schoolNr))
	for dhcp_service_dn in dhcp_service_list:
		dhcp_subnet_list = univention.admin.modules.lookup(
			dhcp_subnet_module, co, lo, scope='sub', superordinate=dhcp_service_dn,
			base=baseDN, filter=univention.admin.filter.expression('cn', str(network.network)))

		subnet_dn = "cn=%s,cn=%s,cn=dhcp,%s" % (str(network.network), schoolNr.lower(), getDN(schoolNr))
		for dhcp_subnet in dhcp_subnet_list:
			if dhcp_subnet.dn == subnet_dn:
				dhcp_subnet_object = dhcp_subnet

	if not dhcp_subnet_object:
		print "ERROR: Unable to set policy for dhcp subnet because it does not exist: %s" % (dhcp_subnet,)
		return (False, dn)

	objects = univention.admin.modules.lookup(
		policy_module, co, lo, scope='sub', superordinate=superordinate,
		base=baseDN, filter=univention.admin.filter.expression('cn', cn)
	)
	policy_object = None
	if objects:
		for o in objects:
			if o.dn == policy_dn:
				policy_object = o
	if not policy_object:
		position_dn = ','.join(policy_dn.split(',')[1:])
		verify_containers(position_dn, cn_module, co, lo, superordinate, baseDN, path='policyPath')
		position.setDn(position_dn)
		policy_object = policy_module.object(co, lo, position=position, superordinate=superordinate)
		policy_object.open()
		for k, v in values.iteritems():
			policy_object[k] = v
		try:
			create_object(policy_object)
		except:
			print "WARNING: Error creating policy %s" % policy_object.dn
			traceback.print_exc(100, sys.stdout)
			policy_object = None
			success = False
	elif overwrite_policy:
		policy_object.open()
		for k, v in values.iteritems():
			policy_object[k] = v
		try:
			policy_object.modify()
		except:
			print "WARNING: Error modifying policy %s" % policy_object.dn
			traceback.print_exc(100, sys.stdout)
			policy_object = None

	if policy_object:
		# add policy reference to dhcp_subnet_object
		dn = policy_object.dn
		try:
			lob = lo.get(dhcp_subnet_object.dn, ['objectClass'])
			if 'univentionPolicyReference' not in lob.get('objectClass', []):
				lo.modify(dhcp_subnet_object.dn, [('objectClass', '', 'univentionPolicyReference')])

			lob = lo.get(dhcp_subnet_object.dn, ['univentionPolicyReference'])
			if policy_object.dn not in lob.get('univentionPolicyReference', []):
				print 'connecting dhcp subnet (%s) with policy (%s)' % (dhcp_subnet_object.dn, policy_object.dn)
				lo.modify(dhcp_subnet_object.dn, [('univentionPolicyReference', '', policy_object.dn)])
		except:
			print "WARNING: Error modifying policy %s" % policy_object.dn
			traceback.print_exc(100, sys.stdout)
			policy_object = None
			success = False

	return (success, dn)


def set_netbiosserver_for_subnet(network, ip, schoolNr, overwrite_policy=False):
	"""
	@param	ip	ipaddr object for the netbios server
	@param	schoolNr	school number

	The Netbios node type is set to 8 H-node: Hybrid - WINS, then broadcast
	"""
	values = {'name': '%s-%s' % (schoolNr.lower(), network.network), 'netbios_node_type': '8', 'netbios_name_servers': str(ip)}
	dn = "cn=%s,cn=netbios,cn=dhcp,cn=policies,%s" % (values['name'], getDN(schoolNr))
	return set_policy_for_dhcp_subnet(network, schoolNr, policy_dhcp_netbios_module, dn, values['name'], values=values, overwrite_policy=overwrite_policy)


def set_nameserver_for_subnet(network, ip, schoolNr, overwrite_policy=False):
	"""
	@param	ip	ipaddr object for the netbios server
	@param	schoolNr	school number
	"""
	values = {'name': '%s-%s' % (schoolNr.lower(), network.network), 'domain_name': domainname, 'domain_name_servers': str(ip)}
	dn = "cn=%s,cn=dns,cn=dhcp,cn=policies,%s" % (values['name'], getDN(schoolNr))
	return set_policy_for_dhcp_subnet(network, schoolNr, policy_dhcp_dns_module, dn, values['name'], values=values, overwrite_policy=overwrite_policy)


def set_router_for_subnet(network, ip, schoolNr, overwrite_policy=False):
	"""
	@param	ip	ipaddr object for the router
	@param	schoolNr	school number
	"""
	values = {'name': '%s-%s' % (schoolNr.lower(), network.network), 'routers': str(ip)}
	dn = "cn=%s,cn=routing,cn=dhcp,cn=policies,%s" % (values['name'], getDN(schoolNr))
	return set_policy_for_dhcp_subnet(network, schoolNr, policy_dhcp_routing_module, dn, values['name'], values=values, overwrite_policy=overwrite_policy)


def import_computer():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  creates computer objects according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> computer import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit()

	print "infile is  : " + infile
	inf = open(infile, 'r')

	linecnt = 0

	with stopped_notifier():
		for line in inf:
			linecnt += 1

			if emptyLineRe.match(line):
				print 'Skipping empty line'
				continue

			print 'Processing line %d: %s' % (linecnt, line),
			parsed = line.strip('\r\n').split(sepchar)
			ctype = parsed[0]
			name = parsed[1].lower()
			MAC = parsed[2]
			schoolNr = parsed[3]
			IP = parsed[4]
			inventoryNumbers = None
			if len(parsed) > 5:
				inventoryNumbers = parsed[5].strip().split(',')
			zone = None
			if len(parsed) > 6:
				zone = parsed[6]

			verify_school_ou(schoolNr, co, lo, baseDN)

			try:
				ip = ipaddr.IPv4Network(IP)
			except ipaddr.AddressValueError, e:
				print line
				print "%s is not a valid ip address" % e
				sys.exit(0)
			except ipaddr.NetmaskValueError, e:
				print line
				print "%s is not a valid netmask" % e
				sys.exit(0)

			# groups
			groups = {}
			if ctype == "memberserver":
				if zone == "edukativ":
					groups["cn=OU%s-Member-Edukativnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN)] = 1
					groups["cn=Member-Edukativnetz,cn=ucsschool,cn=groups,%s" % baseDN] = 1
				if zone == "verwaltung":
					groups["cn=OU%s-Member-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % (schoolNr.lower(), baseDN)] = 1
					groups["cn=Member-Verwaltungsnetz,cn=ucsschool,cn=groups,%s" % baseDN] = 1

			# invoke pre hooks
			hooks.pre('computer', 'A', line=line)

			success = True
			if '/' not in IP:
				ip = ipaddr.IPv4Network('%s/%s' % (IP, default_prefixlen, ))
				print 'WARNING: no netmask specified for ip address %s using %s' % (ip.ip, ip.netmask)

			module = univention.admin.modules.get("computers/%s" % ctype)
			if not module:
				print 'ERROR: Type "%s" not found for computer "%s".' % (ctype, name)
				print 'Ignoring of line %d' % linecnt
				success = False
			else:
				position_basedn = univention.admin.uldap.position(baseDN)
				univention.admin.modules.init(lo, position_basedn, module)

				if check_computer(module, name, schoolNr):
					print "computer %s already exists (school %s)" % (name, schoolNr)
					success = False
				elif check_macAddress(MAC):
					print 'mac %s for computer %s already used (school %s)' % (MAC, name, schoolNr, )
					success = False
				else:
					print "generate computer %s (school %s)" % (name, schoolNr)

					success = create_network(schoolNr, ip)

					position.setDn("cn=computers,%s" % (getDN(schoolNr), ))
					object = module.object(co, lo, position=position, superordinate=superordinate)
					object.open()
					object['name'] = name
					object['mac'] = MAC
					if inventoryNumbers:
						object['inventoryNumber'] = inventoryNumbers
					if not ip.ip == ip.network:
						object['ip'] = str(ip.ip)
						print "set ip to %s is not net %s" % (ip.ip, ip.network)
					object['network'] = 'cn=%s-%s,cn=networks,%s' % (schoolNr.lower(), ip.network, getDN(schoolNr))
					for grp in groups:
						if grp not in object['groups']:
							object['groups'].append(grp)
					try:
						create_object(object)
					except:
						print "WARNING: Error creating computer %s" % object.dn
						traceback.print_exc(100, sys.stdout)
						success = False

				print 'Processing of line %d completed' % linecnt

			# invoke post hooks
			if success:
				hooks.post('computer', 'A', dn=object.dn, line=line)

		inf.close()


def import_router():
	"""
	No computer object is created on importing routers! But the dhcp-routing
	policy is set to the IP address of the router
	"""
	import_networks(router_only=True)


def import_group():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  creates/modifies/deletes group objects accoring to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> group import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit()

	print "infile is  : " + infile
	inf = open(infile, 'r')

	with stopped_notifier():
		for line in inf:

			if emptyLineRe.match(line):
				continue

			parsed = line.strip('\r\n').split(sepchar)

			action = parsed[0]   # action=A(dd, M(odify, D(elete
			schoolNr = parsed[1]
			ClassID = parsed[2]
			Descrpt = parsed[3]

			group_dn = "cn=%s,cn=klassen,cn=%s,cn=groups,%s" % (ClassID, cn_pupils, getDN(schoolNr))
			share_dn = "cn=%s,cn=klassen,cn=shares,%s" % (ClassID, getDN(schoolNr))

			verify_school_ou(schoolNr, co, lo, baseDN)

			# invoke pre hooks
			hooks.pre('group', action, line=line)
			success = True
			dn = None

			if action in ['A', 'M']:  # Add/Modify group
				# verify_group(group_dn, co, lo, superordinate, baseDN)
				# object = univention.admin.objects.get(group_module, co, lo, position='', dn=group_dn)
				# object.open()
				# object['description']=Descrpt
				# object.modify()
				# verify_group_share(schoolNr, ClassID, co, lo, superordinate, baseDN)

				# elif action == 'M':  # M)odify group
				verify_group(group_dn, co, lo, superordinate, baseDN)
				object = univention.admin.objects.get(group_module, co, lo, position='', dn=group_dn)
				object.open()
				oldDescrpt = object['description']
				object['description'] = Descrpt
				print "Changed Description of %s from %s to %s" % (group_dn, oldDescrpt, Descrpt)
				object.modify()
				verify_group_share(schoolNr, ClassID, co, lo, superordinate, baseDN)
				dn = object.dn
			elif action == 'D':  # D)elete group
				try:
					delete_dn(group_dn, group_module, co, lo)
					delete_dn(share_dn, group_module, co, lo)
					dn = group_dn
				except:
					success = False

			if success:
				hooks.post('group', action, dn=dn, line=line)

		inf.close()


def import_printer():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  creates/modifies/deletes printer objects according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> printer import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit()

	print "infile is  : " + infile
	inf = open(infile, 'r')

	with stopped_notifier():
		for line in inf:

			if emptyLineRe.match(line):
				continue

			parsed = line.strip('\r\n').split(sepchar)

			# completely new
			action = parsed[0]   # action=A(dd, M(odify, D(elete
			schoolNr = parsed[1]
			spoolHost = parsed[2].lower()
			if '.' not in spoolHost:
				spoolHost = '%s.%s' % (spoolHost, configRegistry['domainname'])
			printerName = parsed[3]
			printerUri = parsed[4]
			verify_school_ou(schoolNr, None, lo, baseDN)

			def parseString(parsed, idx, default=None):
				res = default
				if len(parsed) > idx:
					string = parsed[idx]
					if string:
						res = string
				return res
			printerModel = parseString(parsed, 5)

			position_dn = "cn=%s,cn=printers,%s" % (printerName, getDN(schoolNr))
			container = "cn=printers,%s" % (getDN(schoolNr), )

			# invoke pre hooks
			hooks.pre('printer', action, line=line)
			dn = None
			success = True

			if action in ['A', 'M']:  # Add/Modify printer
				position = univention.admin.uldap.position(baseDN)
				position.setDn(container)
				if action == 'A':
					object = printer_module.object(co, lo, position, superordinate=superordinate)
				else:
					object = univention.admin.objects.get(printer_module, co, lo, position='', dn=position_dn)
				object.open()
				object['name'] = printerName
				object['spoolHost'] = [spoolHost]
				object['setQuota'] = '0'  # WORKAROUND for Bug #14858
				object['uri'] = printer_module.unmapPrinterURI((printerUri, ))
				if printerModel:
					object['model'] = printerModel
				else:
					object['model'] = 'None'
				if action == 'A':
					try:
						create_object(object)
					except:
						success = False
					dn = object.dn
				else:
					try:
						print 'modifying object %s' % position_dn
						object.modify()
					except:
						traceback.print_exc(100, sys.stdout)
						success = False
					dn = object.dn

			elif action == 'D':  # D)elete printer
				dn = position_dn
				try:
					delete_dn(position_dn, printer_module, co, lo)
				except:
					success = False

			# invoke post hooks
			if success:
				hooks.post('printer', action, dn=dn, line=line)

		inf.close()


def activate_groupmembers():
	#  syntax: $0 <groupXXX> [0|1] [0|1]"
	# <groupXXX>    group
	# [0|1]         optional: deactivate | activate
	# [0|1]         optional: keep passwords | set random passwords

	chpasswd = 0
	status = None

	# usage
	usage = "%prog [options] <groupName> <newStatus> <changePassword>\n"
	usage += "  (de)activates group members for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <groupName>      group that shall be dis-/enabled\n"
	usage += "  <newStatus>      0=disabled, 1=enabled\n"
	usage += "  <changePassword> 0=keep passwords, 1=set random passwords\n"
	usage += "                   the logfile groupName.csv contains all activated users"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	if len(args) < 2:
		parser.print_help()
		print 'must have at least one argument'
		sys.exit()
	if len(args) > 0:
		actgrp = args[0]
	if len(args) > 1:
		try:
			status = int(args[1])
		except:
			parser.print_help()
			print 'invalid value for <newstatus>!'
			sys.exit()
	if len(args) > 2:
		try:
			chpasswd = int(args[2])
		except:
			parser.print_help()
			print 'invalid value for <changePassword>!'
			sys.exit()

	if status not in [0, 1]:
		parser.print_help()
		print 'invalid value for <newstatus>!'
		sys.exit()
	elif chpasswd not in [0, 1]:
		parser.print_help()
		print 'invalid value for <changePassword>!'
		sys.exit()

	# inverted logic
	if status == 0:
		disabled = "all"
	else:
		disabled = "none"

	with stopped_notifier():
		# outfile = os.path.basename(actgrp+'.csv')
		outfile = "/var/lib/ucs-school-import/activate-grp-%s-%s.csv" % (time.strftime("%Y%m%d-%H%M%S"), actgrp)
		print "outfile is : " + outfile
		if os.path.exists(outfile):
			print 'outfile %s does already exist. Stopping here.' % outfile
			sys.exit()
		outf = open(outfile, 'w')

		# get group
		objects = univention.admin.modules.lookup(
			group_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
			filter=univention.admin.filter.expression('cn', actgrp)
		)
		out_line = ('%%s%(sep)s' * 8 + '\n') % {'sep': sepchar}
		for grp in objects:

			# get group members
			if "uniqueMember" in grp.oldattr:
				grpmembers = grp.oldattr["uniqueMember"]
				for memberdn in grpmembers:

					membergrplist = ""
					grpobjlist = univention.admin.modules.lookup(
						group_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
						filter=univention.admin.filter.expression('uniqueMember', memberdn)
					)
					for grpobj in grpobjlist:
						if grpobj.dn != grp.dn:
							if len(membergrplist):
								membergrplist += "," + grpobj.oldattr["cn"][0]
							else:
								membergrplist += grpobj.oldattr["cn"][0]

					# modify each member
					memberobj = univention.admin.objects.get(user_module, co, lo, position='', dn=memberdn)
					memberobj.open()

					memberobj['disabled'] = disabled

					print memberdn,
					if status == 0:
						print 'deactivated',
					else:
						print 'activated',

					passwd = '*'
					if chpasswd:
						passwd = create_passwd(dn=memberdn, specials='-+.,;')
						memberobj['password'] = passwd
						memberobj['overridePWHistory'] = '1'
						memberobj['overridePWLength'] = '1'
						print 'and set random password',

					memberobj.modify()

					# write csv line
					snr = memberdn[memberdn.find('ou=') + 3:]
					snr = snr[: snr.find(',')]
					outf.write(out_line % (snr, actgrp, memberobj['username'], memberobj['firstname'], memberobj['lastname'], passwd, memberobj['mailPrimaryAddress'], membergrplist))

					print

		outf.close()


def export_computer():
	#  syntax: $0 <ou> <filename>"
	# <ou>        computers of OU <ou> shall be exported
	# <filename>  output filename

	# usage
	usage = "%prog [options] <ouName> <fileName>\n"
	usage += "  export computer for specified ou in UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <ouName>         name of the ou from which the computers shall be exported\n"
	usage += "  <fileName>       export file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	if len(args) != 2:
		parser.print_help()
		print 'must have at least two arguments'
		sys.exit()
	ou = args[0]
	outfile = args[1]

	verify_school_ou(ou, None, lo, baseDN)
	# outfile = os.path.basename(actgrp+'.csv')
	print "outfile is : " + outfile
	if os.path.exists(outfile):
		print 'outfile %s does already exist. Stopping here.' % outfile
		sys.exit()
	outf = open(outfile, 'w')

	ouBaseDN = getDN(ou)

	# get group
	print 'looking for objects... please wait...'
	objects = univention.admin.modules.lookup(computer_module, co, lo, scope='sub', superordinate=superordinate, base=ouBaseDN, filter=None)
	print 'writing data of %d objects...' % len(objects)
	out_line = ('%%s%(sep)s' * 5 + '\n') % {'sep': sepchar}
	for host in objects:
		host.open()
		inventoryNumber = ''
		ip = ''
		mac = ''
		if host.get('inventoryNumber'):
			inventoryNumber = host['inventoryNumber'][0]
		if host.get('ip'):
			ip = host['ip'][0]
		if host.get('mac'):
			mac = host['mac'][0]
#		Name,OU,1.Zeile Inventar-Nr.,IP-Adresse
		outf.write(out_line % (host['name'], ou, inventoryNumber, ip, mac))
	outf.close()


def set_ou_sharefileserver():

	# usage
	usage = "%prog [options] <ouName> <shareFileServer>\n"
	usage += "  sets shareFileServer for ou in UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <ouName>          name of the ou\n"
	usage += "  <shareFileServer> name of the shareFileServer"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	if len(args) != 2:
		parser.print_help()
		print 'ouname and ShareFileServer is required'
		sys.exit(1)
	ouname = args[0]
	ShareFileServer = args[1]

	if not re.match('^[a-zA-Z0-9](([a-zA-Z0-9-_]*)([a-zA-Z0-9]$))?$', ouname):
		print 'ERROR: invalid ouname name given'
		sys.exit(1)
	if not re.match('^[a-zA-Z0-9](([a-zA-Z0-9-_]*)([a-zA-Z0-9]$))?$', ShareFileServer):
		print 'ERROR: invalid ShareFileServer name given'
		sys.exit(1)
	objects = lo.searchDn(filter='(&(objectClass=univentionHost)(cn=%s))' % ShareFileServer, base=baseDN)
	if len(objects) != 1:
		print 'ERROR: sharefileserver "%s" not found!' % ShareFileServer
		sys.exit(1)
	else:
		ShareFileServer = objects[0]

	verify_school_ou(ouname, None, lo, baseDN)

	with stopped_notifier():
		r = lo.get(getDN(ouname), ['objectClass'])
		if 'ucsschoolOrganizationalUnit' not in r['objectClass']:
			r = lo.modify(getDN(ouname), [('objectClass', '', 'ucsschoolOrganizationalUnit'), ('ucsschoolClassShareFileServer', '', ShareFileServer)])
		else:
			r = lo.get(getDN(ouname), ['ucsschoolClassShareFileServer'])
			if r:
				r = r['ucsschoolClassShareFileServer'][0]
			else:
				r = ''
			r = lo.modify(getDN(ouname), [('ucsschoolClassShareFileServer', r, ShareFileServer)])
	sys.exit(0)


def rename_class():

	# usage
	usage = "%prog [options] <importFile>\n"
	usage += "  renames class groups and shares according to import file for UCS@school\n\n"
	usage += "Arguments:\n"
	usage += "  <importFile> rename class import file"
	parser = optparse.OptionParser(usage=usage)
	options, args = parser.parse_args()

	# argument is infile
	if len(args) > 0:
		infile = args[0]
	else:
		parser.print_help()
		print "must have one Argument for infile"
		sys.exit(1)

	# get all groups and shares
	myGroups = {}
	myShares = {}
	for group in univention.admin.modules.lookup(
		group_module, co, lo, scope="sub",
		superordinate=superordinate,
		base=baseDN, filter="(objectClass=univentionGroup)"):
		cn = group.dn.split(",")[0].replace("cn=", "", 1)
		myGroups[cn] = group
	for share in univention.admin.modules.lookup(
		share_module, co, lo, scope="sub",
		superordinate=superordinate,
		base=baseDN, filter="(objectClass=univentionShare)"):
		cn = share.dn.split(",")[0].replace("cn=", "", 1)
		myShares[cn] = share

	print "infile is  : " + infile
	inf = open(infile, 'r')

	# get old and new group name from infile
	newGroups = []
	lineCounter = 0
	for line in inf:
		lineCounter += 1
		if emptyLineRe.match(line):
			continue
		parsed = line.strip('\r\n').split(sepchar)

		# save old and new name and the udm share and group
		# object
		groupObject = myGroups.get(parsed[0], None)
		shareObject = myShares.get(parsed[0], None)
		newGroups.append({
			"oldName": parsed[0],
			"newName": parsed[1],
			"share": shareObject,
			"group": groupObject,
			"line": line.strip(),
			"lineCounter": "%s" % lineCounter})

	# check groups
	error = ""
	for i in newGroups:
		oldName = i.get("oldName")
		newName = i.get("newName")
		line = i.get("line")
		lineCounter = i.get("lineCounter")
		univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Checking line %s: %r to %r' % (lineCounter, oldName, newName))

		# groups
		if not myGroups.get(oldName):
			error = "old group %s not found" % oldName
		elif myGroups.get(newName):
			error = "new group %s already exists" % newName
		else:
			del myGroups[oldName]
			myGroups[newName] = 1

		# shares
		if not myShares.get(oldName):
			error = "old share %s not found" % oldName
		elif myShares.get(newName):
			error = "new share %s already exists" % newName
		else:
			del myShares[oldName]
			myShares[newName] = 1

		if error:
			univention.debug.debug(univention.debug.MAIN, univention.debug.ERROR, '%s (line %s: %s)' % (error, lineCounter, line))
			univention.debug.debug(univention.debug.MAIN, univention.debug.ERROR, 'Stopping here')
			print "ERROR: %s (line %s: %s)" % (error, lineCounter, line)
			print "do nothing"
			sys.exit(1)

	univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Stopping notifier')
	with stopped_notifier():
		# do it, rename groups and shares and modify share path
		messages = []
		for i in newGroups:
			groupObject = i.get("group")
			shareObject = i.get("share")
			newName = i.get("newName")
			oldName = i.get("oldName")
			line = i.get("line")
			lineCounter = i.get("lineCounter")
			if groupObject and shareObject and newName and oldName:
				univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Processing line %s: renaming %r to %r' % (lineCounter, oldName, newName))

				success = True

				# group pre mod hook
				hooks.pre("group", "M", line=line)

				# rename group
				groupObject.open()
				groupObject['name'] = newName
				try:
					univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Renaming of group %r to %r' % (oldName, newName))
					groupObject.modify()
					messages.append((False, "Renaming of group %s to %s successfully" % (oldName, newName)))
				except Exception, e:
					success = False
					messages.append((True, "Renaming of group %s to %s failed: %s" % (oldName, newName, str(e))))

				if success:
					# rename share and share path
					shareObject.open()
					path = shareObject['path'].split(os.path.sep)
					path[-1] = newName
					shareObject['name'] = newName
					if shareObject['sambaName'] == oldName:
						shareObject['sambaName'] = newName
					if shareObject['sambaForceGroup'] == '+%s' % (oldName, ):
						shareObject['sambaForceGroup'] = '+%s' % (newName, )
					shareObject['path'] = os.path.sep.join(path)
					try:
						univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Renaming of share %r to %r' % (oldName, newName))
						shareObject.modify()
						messages.append((False, "Renaming of share %s to %s successfully" % (oldName, newName)))
					except Exception, e:
						success = False
						messages.append((True, "Renaming of share %s to %s failed: %s" % (oldName, newName, str(e))))

				# group post mod hook
				if success:
					univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Calling group post-modify hooks')
					hooks.post('group', "M", dn=groupObject.dn, line=line)
	univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Resuming notifier')

	# print warnings
	for isError, msg in messages:
		level = {
			False: univention.debug.PROCESS,
			True: univention.debug.ERROR,
		}[isError]
		univention.debug.debug(univention.debug.MAIN, level, msg)
		print msg

	univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'rename_class finished')

	return


def move_domaincontroller_to_ou(co, lo, baseDN, options):
	"""
	Move specified domaincontroller (options.dcname) to specified OU (options.ou).
	"""
	slaves = univention.admin.modules.lookup(server_module, co, lo, scope='sub', base=baseDN, filter=univention.admin.filter.expression('cn', options.dcname))
	if not slaves:
		print 'ERROR: cannot find domaincontroller slave with hostname "%s"' % options.dcname
		sys.exit(1)
	if len(slaves) > 1:
		print 'ERROR: found more than one domaincontroller slave with hostname "%s"' % options.dcname
		sys.exit(1)

	oulist = univention.admin.modules.lookup(ou_module, co, lo, scope='sub', base=baseDN, filter=univention.admin.filter.expression('ou', options.ou))
	if not oulist:
		print 'ERROR: the given ou "%s" does not exist' % options.ou
		sys.exit(1)
	if len(oulist) > 1:
		print 'ERROR: found more than one ou "%s" in LDAP' % options.ou
		sys.exit(1)

	slave = slaves[0]
	ouDn = oulist[0].dn

	group_filter = univention.admin.filter.conjunction('&', [
		univention.admin.filter.conjunction('|', [
			univention.admin.filter.expression('cn', 'OU%s-DC-Edukativnetz' % options.ou),
			univention.admin.filter.expression('cn', 'OU%s-DC-Verwaltungsnetz' % options.ou),
		]),
		univention.admin.filter.expression('uniqueMember', slave.dn),
	])
	groups = univention.admin.modules.lookup(group_module, co, lo, scope='sub', base=baseDN, filter=group_filter)
	if not groups:
		print 'ERROR: cannot move domaincontroller slave with hostname "%s" to OU "%s"' % (options.dcname, options.ou)
		print 'ERROR: The system has no LDAP access to the OU'
		sys.exit(1)

	if slave.dn.endswith(',%s' % ouDn):
		print 'domaincontroller slave "%s" is already located below ou "%s" - stopping here' % (options.dcname, options.ou)
		sys.exit(0)

	REis_in_ou = re.compile('^.+,ou=[^,]+,%s$' % baseDN)
	if REis_in_ou.match(slave.dn) and not options.force:
		print 'ERROR: domaincontroller slave "%s" is located in another OU' % (options.dcname)
		print 'ERROR: DN of domaincontroller slave: %s' % slave.dn
		print 'ERROR: use --force to override'
		sys.exit(1)

	cnDn = 'cn=dc,cn=server,cn=computers,%s' % (getDN(options.ou),)
	containers = univention.admin.modules.lookup(cn_module, co, lo, scope='base', base=cnDn)
	if not containers:
		print 'ERROR: cannot move domaincontroller slave object - target container does not exist: %s' % cnDn
		sys.exit(1)

	oldDn = slave.dn
	newDn = 'cn=%s,cn=dc,cn=server,cn=computers,%s' % (options.dcname, getDN(options.ou))
	slave.open()
	print 'Moving %s to %s ...' % (oldDn, newDn)
	slave.move(newDn, ignore_license=1)

	oulist = univention.admin.modules.lookup(ou_module, co, lo, scope='sub', base=baseDN)
	for ou in oulist:
		ou.open()
		changed = False
		for property in ('ucsschoolClassShareFileServer', 'ucsschoolHomeShareFileServer'):
			if oldDn in ou[property]:
				ou[property] = newDn
				changed = True
		if changed:
			print 'Updating %s ...' % ou.dn
			ou.modify()

	removed = False
	ou_dhcpservice = None

	# find dhcp server object by checking all dhcp service objects
	dhcpservicelist = univention.admin.modules.lookup(dhcp_service_module, co, lo, scope='sub', base=baseDN)
	for dhcpservice in dhcpservicelist:
		# remember dhcpservice of target OU
		if dhcpservice.dn.endswith(',%s' % ouDn):
			ou_dhcpservice = dhcpservice

		# find dhcp server
		serverlist = univention.admin.modules.lookup(dhcp_server_module, co, lo, scope='sub', superordinate=dhcpservice, base=baseDN, filter=univention.admin.filter.expression('cn', options.dcname))
		if serverlist:
			if not serverlist[0].dn.endswith(',%s' % ouDn):
				removed = True
				print 'Removing %s' % serverlist[0].dn
				serverlist[0].open()
				attr_server = serverlist[0]['server']
				serverlist[0].remove()

	if removed:
		position = univention.admin.uldap.position('cn=%s,cn=dhcp,%s' % (options.ou, getDN(options.ou)))
		dhcpserver = dhcp_server_module.object(co, lo, position=position, superordinate=ou_dhcpservice)
		dhcpserver.open()
		dhcpserver["server"] = attr_server
		try:
			create_object(dhcpserver)
		except:
			print "ERROR: Failed to create dhcp server: %s" % (position.getDn(),)

	print 'Move complete'
	print 'HINT: the domaincontroller slave has to be rejoined into the domain!'


def create_dc(co, lo, baseDN, ou_name, dc_name, dc_type):
	if dc_type not in (TYPE_DC_EDUCATIONAL, TYPE_DC_ADMINISTRATIVE):
		print 'ERROR: invalid type for domaincontroller given in create_dc(): %r' % (dc_type, )
		sys.exit(1)

	if dc_type == TYPE_DC_ADMINISTRATIVE and not configRegistry.is_true('ucsschool/ldap/noneducational/create/objects', True):
		print 'ERROR: cannot create administrative DC - noneducational objects disabled via ucsschool/ldap/noneducational/create/objects'
		sys.exit(1)

	if not dc_name or not is_valid_hostname(dc_name):
		print 'ERROR: invalid administrative server name given: %r' % dc_name
		sys.exit(1)

	# verify if OU already exists - abort otherwise
	ou_objects = univention.admin.modules.lookup(
		ou_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
		filter=univention.admin.filter.expression('ou', ou_name)
	)
	if not ou_objects:
		print 'ERROR: specified OU %r does not exist' % ou_name
		sys.exit(1)

	# get list of desired group memberships
	group_dn_list = {
		TYPE_DC_ADMINISTRATIVE: [
			'cn=OU%s-DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s' % (ou_name.lower(), baseDN),
			'cn=DC-Verwaltungsnetz,cn=ucsschool,cn=groups,%s' % (baseDN,),
		],
		TYPE_DC_EDUCATIONAL: [
			'cn=DC-Edukativnetz,cn=ucsschool,cn=groups,%s' % (baseDN,),
			'cn=OU%s-DC-Edukativnetz,cn=ucsschool,cn=groups,%s' % (ou_name.lower(), baseDN),
		],
	}[dc_type]
	for grpdn in group_dn_list:
		verify_group(grpdn, co, lo, superordinate, baseDN)

	host_objects = univention.admin.modules.lookup(
		computer_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
		filter=univention.admin.filter.expression('cn', dc_name)
	)
	slave_objects = univention.admin.modules.lookup(
		server_module, co, lo, scope='sub', superordinate=superordinate, base=baseDN,
		filter=univention.admin.filter.expression('cn', dc_name)
	)
	if host_objects and not slave_objects:
		print 'ERROR: given host name "%s" is already in use and no domaincontroller slave system. Please choose another name.' % dc_name
		sys.exit(1)

	if slave_objects:
		# slave object does exist
		if len(slave_objects) > 1:
			print 'ERROR: more than one domaincontroller slave with cn=%s found in LDAP: %r' % (dc_name, slave_objects)
			sys.exit(1)

		slave_object = slave_objects[0]
		slave_object.open()
		modified = False
		for grpdn in group_dn_list:
			if grpdn not in slave_object["groups"]:
				slave_object["groups"].append(grpdn)
				modified = True
		if modified:
			modify_object(slave_object)
	else:
		# slave object does NOT exist - create missing DC object
		position = univention.admin.uldap.position(baseDN)
		position.setDn('cn=dc,cn=server,cn=computers,%s' % getDN(ou_name))
		slave_object = server_module.object(co, lo, position=position, superordinate=superordinate)
		slave_object.open()
		slave_object['name'] = dc_name
		slave_object['unixhome'] = '/dev/null'
		slave_object['shell'] = '/bin/bash'
		slave_object['primaryGroup'] = 'cn=DC Slave Hosts,cn=groups,%s' % (baseDN,)
		for grpdn in group_dn_list:
			if grpdn not in slave_object["groups"]:
				slave_object["groups"].append(grpdn)
		create_object(slave_object)


# ------------------------------------------------------------------------------------------#
# MAIN                                                                                     #
# ------------------------------------------------------------------------------------------#

# init univention-directory-manager
tls = 2

bindpwd = None
with open('/etc/ldap.secret', 'r') as secretFile:
	bindpwd = secretFile.read()
binddn = 'cn=admin,' + baseDN

lo = None
try:
	lo = univention.admin.uldap.access(
		host=configRegistry['ldap/master'], base=baseDN,
		binddn=binddn, bindpw=bindpwd, start_tls=tls)
except Exception, e:
	univention.debug.debug(univention.debug.MAIN, univention.debug.WARN, 'authentication error: %s' % str(e))
	print 'ERROR: authentication error: %s' % str(e)
	sys.exit(1)

co = univention.admin.config.config()
position = univention.admin.uldap.position(baseDN)
superordinate = None

univention.admin.modules.update()
user_module = univention.admin.modules.get("users/user")
group_module = univention.admin.modules.get("groups/group")
cn_module = univention.admin.modules.get("container/cn")
ou_module = univention.admin.modules.get("container/ou")
dcmaster_module = univention.admin.modules.get("computers/domaincontroller_master")
dcbackup_module = univention.admin.modules.get("computers/domaincontroller_backup")
server_module = univention.admin.modules.get("computers/domaincontroller_slave")
share_module = univention.admin.modules.get("shares/share")
printer_module = univention.admin.modules.get("shares/printer")
computer_module = univention.admin.modules.get("computers/computer")
dhcp_server_module = univention.admin.modules.get("dhcp/server")
dhcp_service_module = univention.admin.modules.get("dhcp/service")
dhcp_subnet_module = univention.admin.modules.get("dhcp/subnet")
dns_reverse_zone_module = univention.admin.modules.get("dns/reverse_zone")
network_module = univention.admin.modules.get("networks/network")
policy_dhcp_routing_module = univention.admin.modules.get("policies/dhcp_routing")
policy_dhcp_netbios_module = univention.admin.modules.get("policies/dhcp_netbios")
policy_dhcp_dns_module = univention.admin.modules.get("policies/dhcp_dns")
setting_module = univention.admin.modules.get("settings/default")
maildomain_module = univention.admin.modules.get("mail/domain")

for m in (
	user_module,
	group_module,
	cn_module,
	ou_module,
	server_module,
	share_module,
	printer_module,
	computer_module,
	dhcp_server_module,
	dhcp_service_module,
	dhcp_subnet_module,
	dns_reverse_zone_module,
	network_module,
	policy_dhcp_routing_module,
	policy_dhcp_netbios_module,
	policy_dhcp_dns_module,
	setting_module,
	maildomain_module,
):
	univention.admin.modules.init(lo, position, m)

# get mail domains
for result in lo.search(base=baseDN, filter="(objectClass=univentionMailDomainname)"):
	cn = result[1].get("cn", [""])[0]
	if cn:
		mailDomains[cn] = 1

# get default group
default_group = "cn=Domain Users,cn=groups,%s" % baseDN  # fallback
for object in univention.admin.modules.lookup(setting_module, co, lo, scope='sub', superordinate=superordinate, base='', filter=''):
	if object.has_key("defaultGroup"):
		default_group = object["defaultGroup"]
	else:
		print "WARNING, no default group found"

univention.debug.debug(univention.debug.MAIN, univention.debug.PROCESS, 'Starting %s %s' % (os.path.basename(sys.argv[0]), ' '.join([repr(x) for x in sys.argv[1:]])))

# select action
if sys.argv[0].endswith("import_user") or sys.argv[0].endswith("ucs-school-import"):
	import_user()
elif sys.argv[0].endswith("import_networks"):
	import_networks()
elif sys.argv[0].endswith("import_computer"):
	import_computer()
elif sys.argv[0].endswith("import_router"):
	import_router()
elif sys.argv[0].endswith("import_inventory_number"):
	set_inventory_number_for_computer()
elif sys.argv[0].endswith("import_group"):
	import_group()
elif sys.argv[0].endswith("import_printer"):
	import_printer()
elif sys.argv[0].endswith("create_ou"):
	dcNameEducational = None
	dcNameAdministrative = None

	usage = '''%prog [options] <ou_name> [<educational_dc_name> [<administrative_dc_name>]]
 create school container for UCS@school

Arguments:
  <ou_name>		        name of ou that shall be created or verified
  <educational_dc_name>	hostname of the educational DC for specified OU
						(if dc_name is not specified "dc<ou_name>-01" will be
						used as the default for the domaincontroller name)
  <administrative_dc_name>  hostname of the administrative DC for the specified OU'''
	parser = optparse.OptionParser(usage=usage)
	parser.add_option(
		'--sharefileserver', action='store', type='string',
		dest='ShareFileServer', default=None,
		help="hostname of the fileserver within given OU that is used for class shares and user home shares")
	parser.add_option(
		'--displayName', action='store', type='string',
		dest='displayName', default=None,
		help='Descriptive name of the school OU that is shown within UCS@school modules as school name (e.g. "Gymnasium Mitte")')

	(options, args, ) = parser.parse_args()
	if len(args) > 0:
		ouname = args[0]
		if len(args) > 1:
			dcNameEducational = args[1]
		if len(args) > 2:
			dcNameAdministrative = args[2]

		if not is_valid_ou_name(ouname):
			print 'ERROR: invalid ou name given'
			sys.exit(1)

		for name in (dcNameEducational, dcNameAdministrative):
			if name and not is_valid_hostname(name):
				print 'ERROR: invalid domaincontroller name given: %r' % name
				sys.exit(1)

		if dcNameEducational and dcNameAdministrative and dcNameEducational == dcNameAdministrative:
			print 'ERROR: hostname of educational DC and administrative DC may not be equal!'
			sys.exit(1)

		if options.ShareFileServer is not None:
			if options.ShareFileServer and not is_valid_hostname(options.ShareFileServer):
				print 'ERROR: invalid share server name given: "%s"' % options.ShareFileServer
				sys.exit(1)
			objects = lo.searchDn(filter='(&(objectClass=univentionHost)(cn=%s))' % options.ShareFileServer, base=baseDN)
			if not objects:
				print 'ERROR: cannot find share server object with given name "%s"' % options.ShareFileServer
				sys.exit(1)

		# In a single server environment the default school DC is the master
		if not dcNameEducational and configRegistry.is_true('ucsschool/singlemaster', False):
			dcNameEducational = configRegistry.get('hostname')

		# if no displayName has been set, use the OU name
		if options.displayName is None:
			options.displayName = ouname

		with stopped_notifier():
			create_school_ou(ouname, co, lo, baseDN, dcName=dcNameEducational, ShareFileServer=options.ShareFileServer, displayName=options.displayName, dcNameAdministrative=dcNameAdministrative)
		sys.exit(0)
	parser.print_help()
	sys.exit(1)

elif sys.argv[0].endswith("create_dc"):
	usage = '''%prog --ou <ou> --name <dcname> --type <dctype>

%prog creates domaincontroller slave objects within the given OU.'''

	parser = optparse.OptionParser(usage=usage)
	parser.add_option('--name', action='store', dest='dc_name', default=None, help='hostname of the domaincontroller slave object that shall be created')
	parser.add_option('--ou', action='store', dest='ou_name', default=None, help='target OU where the domaincontroller slave object will be created in')
	parser.add_option('--type', action='store', dest='dc_type', default=None, help='UCS@school type of the domaincontroller slave object (valid values: %r, %r)' % (TYPE_DC_EDUCATIONAL, TYPE_DC_ADMINISTRATIVE))
	(options, args, ) = parser.parse_args()

	if not options.dc_name or not options.ou_name:
		print 'ERROR: no domaincontroller hostname or ou specified'
		print
		parser.print_help()
		sys.exit(1)

	if not is_valid_ou_name(options.ou_name):
		print 'ERROR: invalid ou name given'
		print
		parser.print_help()
		sys.exit(1)

	verify_school_ou(options.ou_name, None, lo, baseDN)

	if not is_valid_hostname(options.dc_name):
		print 'ERROR: invalid domaincontroller name given'
		print
		parser.print_help()
		sys.exit(1)

	if options.dc_type not in (TYPE_DC_EDUCATIONAL, TYPE_DC_ADMINISTRATIVE):
		print 'ERROR: invalid type specified'
		print
		parser.print_help()
		sys.exit(1)

	with stopped_notifier():
		create_dc(co, lo, baseDN, options.ou_name, options.dc_name, options.dc_type)

elif sys.argv[0].endswith("move_domaincontroller_to_ou"):
	usage = '''%prog --dcname <dcname> --ou <ou>

%prog moves domaincontroller slave objects that are not located
within an OU LDAP subtree to the given OU.'''

	parser = optparse.OptionParser(usage=usage)
	parser.add_option('--dcname', action='store', dest='dcname', default=None, help='hostname of the domaincontroller slave object that shall be moved')
	parser.add_option('--ou', action='store', dest='ou', default=None, help='target OU where the domaincontroller slave object is moved to')
	parser.add_option('--force', action='store_true', dest='force', default=False, help='force move of domaincontroller slave object if located in other OU')
	(options, args, ) = parser.parse_args()

	if not options.dcname or not options.ou:
		print 'ERROR: no domaincontroller hostname or ou specified'
		print
		parser.print_help()
		sys.exit(1)

	if not is_valid_ou_name(options.ou):
		print 'ERROR: invalid ou name given'
		print
		parser.print_help()
		sys.exit(1)

	verify_school_ou(options.ou, None, lo, baseDN)

	if not is_valid_hostname(options.dcname):
		print 'ERROR: invalid domaincontroller name given'
		print
		parser.print_help()
		sys.exit(1)

	with stopped_notifier():
		move_domaincontroller_to_ou(co, lo, baseDN, options)

elif sys.argv[0].endswith("activate_groupmembers"):
	activate_groupmembers()
elif sys.argv[0].endswith("export_computer"):
	export_computer()
elif sys.argv[0].endswith("set_ou_sharefileserver"):
	set_ou_sharefileserver()
elif sys.argv[0].endswith("rename_class"):
	rename_class()
else:
	print "unknown action defined by the filename"
