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

adminuser=0
import os, string, pwd, grp, sys, univention.config_registry
import getopt
from subprocess import *

def fix_permissions(fn, dirmode, filemode, username, grpname, lastitems=None):
	items = fn.split(os.sep)
	if not lastitems or lastitems < 0 or lastitems > len(items):
		tailcnt = len(items)
	else:
		tailcnt = lastitems

	tfn = os.sep.join(items[0:-tailcnt])
	if not tfn:
		tfn = os.sep
	for i in xrange(-tailcnt,0):
		if tfn == '/':
			tfn += items[i]
		else:
			tfn += os.sep + items[i]

		mode = filemode
		if os.path.isdir(tfn):
			mode = dirmode

		try:
			os.chmod(tfn, mode)
		except:
			print 'Failed to set mode %s to %s' % (mode, tfn)
		try:
			cyrus_id=pwd.getpwnam(username)[2]
			mail_id=grp.getgrnam(grpname)[2]
			os.chown(tfn, cyrus_id, mail_id)
		except:
			print 'Failed to set cyrus:mail to %s' % (tfn)


def cyrescape(address):	# only necessary for filesystem level operations
	address=address.replace("@","\@")
	address=address.replace(".","\^")
	return address.strip()

def usage():
	print 'usage: %s [-v] [--partition=, --prefix=, --user, --shared] <mailbox> <new mailboxname>' % sys.argv[0].split('/')[-1]
	sys.exit(1)

try:
	opts, args = getopt.getopt(sys.argv[1:], "v", ["partition=", "prefix=", "user", "shared"])
except getopt.GetoptError, err:
	# print help information and exit:
	print str(err) # will print something like "option -a not recognized"
	usage()
partition = None
prefix = 'shared'	# default
verbose = 0
for key, val in opts:
	if key == "-v":
		verbose += 1
	elif key in ("--partition"):
		partition = val
	elif key in ("--shared"):
		prefix = 'shared'
	elif key in ("--user"):
		prefix = 'user'
	elif key in ("--prefix"):
		prefix = value
	else:
		assert False, "unhandled option"

if not prefix:
	print 'prefix must not be empty'
	sys.exit(1)

if len(args) == 2:
	src=args[0].lower().strip()
	dst=args[1].lower().strip()
else:
	usage()

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

password=open('/etc/cyrus.secret').read()
if password[-1] == '\n':
	password=password[0:-1]

cyrus_user='cyrus'
serverhost='localhost'

if configRegistry.get('mail/cyrus/murder/backend/hostname'):
	serverhost = configRegistry['mail/cyrus/murder/backend/hostname']
elif configRegistry.get('mail/cyrus/murder/master'):
	serverhost = '%s.%s' % (configRegistry['hostname'], configRegistry['domainname'])

if partition and partition != 'default' and not configRegistry.get('mail/cyrus/murder/servers'):
	print >> sys.stderr, "this host is not a cyrus murder frontend"
	sys.exit(1)

if prefix == 'user':
	# rename sieve directory, this has to be done before cyrus rename, as
	# cyrus rename deletes the sieve scripts in the src_sieve_path
	src_domainpart=src.split('@')[1]
	src_userpart=src.split('@')[0]
	src_userpart_modified=src_userpart.replace(".", "^")
	src_sieve_path='/var/spool/cyrus/sieve/domain/%s/%s/%s/%s' % (src_domainpart[0], src_domainpart, src_userpart_modified[0], src_userpart_modified)
	src_mail_path='/var/spool/cyrus/mail/domain/%s/%s/%s/user/%s' % (src_domainpart[0], src_domainpart, src_userpart_modified[0], src_userpart_modified)
	src_subfile='/var/lib/cyrus/domain/%s/%s/user/%s/%s.sub' % (src_domainpart[0], src_domainpart, src_userpart_modified[0], src_userpart_modified)

	dst_domainpart=dst.split('@')[1]
	dst_userpart=dst.split('@')[0]
	dst_userpart_modified=dst_userpart.replace(".", "^")
	dst_sieve_path='/var/spool/cyrus/sieve/domain/%s/%s/%s/%s' % (dst_domainpart[0], dst_domainpart, dst_userpart_modified[0], dst_userpart_modified)
	dst_subfile='/var/lib/cyrus/domain/%s/%s/user/%s/%s.sub' % (dst_domainpart[0], dst_domainpart, dst_userpart_modified[0], dst_userpart_modified)

	# check id src mailbox exists otherwise cyrus rename will fail below
	if os.path.exists(src_mail_path):
		if not os.path.exists(dst_sieve_path):
			if os.path.exists(src_sieve_path):
				os.renames(src_sieve_path, dst_sieve_path)
				fix_permissions(dst_sieve_path, 0700, 0600, 'cyrus', 'mail', lastitems=4)
			else:
				print >>sys.stderr, "Warning: Source sieve directory did not exist"
				## probably the cyrus-sieve.py listener should deal with this
				# os.makedirs(dst_sieve_path, mode=0777)
				# cyrus_id=pwd.getpwnam('cyrus')[2]
				# mail_id=grp.getgrnam('mail')[2]
				# os.chown(dst_sieve_path, cyrus_id, mail_id)
				# print >>sys.stderr, "Warning: Destination sieve directory created"
		else:
			print >>sys.stderr, "Warning: Destination sieve directory exists"

		# sub file
		if not os.path.exists(dst_subfile):
			if os.path.exists(src_subfile):
				os.renames(src_subfile, dst_subfile)
				fix_permissions(dst_subfile, 0700, 0600, 'cyrus', 'mail', lastitems=4)
				call(["/bin/sed", "-i", "-e", 's|^%s!user.%s|%s!user.%s|g' % (src_domainpart, src_userpart_modified, dst_domainpart, dst_userpart_modified), dst_subfile])
		else:
			print >>sys.stderr, "Warning: Source sieve directory did not exist"


# create cyradm script
cmd_list=[]
if not partition:
	cmd_list.append('renamemailbox %s/%s %s/%s' % (prefix, src, prefix, dst))
else:
	cmd_list.append('renamemailbox %s/%s %s/%s %s' % (prefix, src, prefix, dst, partition))
cmd_list.append('disc')
cmd_list.append('exit')
script='\n'.join(cmd_list)

# run cyradm script
if verbose > 1:
	print "/usr/bin/cyradm", "-u", cyrus_user, "--password=%s" % password, serverhost
default_env={'TERM': 'vt100', 'COLUMNS': '80', 'LINES': '24'}
default_env.update(os.environ)
p = Popen(["/usr/bin/cyradm", "-u", cyrus_user , "--password=%s" % password, serverhost], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=default_env)
(stdout, stderr)=p.communicate(script)
if verbose:
	print stdout
if stderr:
	print stderr
	sys.exit(1)

