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

import imaplib
import sys
import pwd
import grp
import os
import optparse
import subprocess
import time

import univention.config_registry

jobPath = "/var/spool/cyrus/jobs/mailbox/create/user"
cr = univention.config_registry.ConfigRegistry()
cr.load()

# get spam required hits in "*"
spamHitsValue = ""
try:
	flo = float(cr.get("mail/antispam/requiredhits", "5.0"))
	spamHits = int(flo)
	if spamHits < flo:
		spamHits = spamHits + 1
except:
	spamHits = 5
for i in range(0, spamHits):
	spamHitsValue += "*"


sieveSpamFilter =  """# Univention Sieve Script - generated on %s
require "fileinto";

# Spamfilter
if header :comparator "i;ascii-casemap" :contains "X-Spam-Level" "%s"  {
	fileinto "INBOX/%s";
	stop;
}""" % (time.asctime(time.localtime()), spamHitsValue, cr.get('mail/cyrus/folder/spam', "Spam"))

# save mailbox name if creation failed
def failed(mailBox, remote, e):

	sys.stderr.write("creation of mailbox %s failed with: %s\n" % (mailBox, e))
	path = os.path.join(jobPath, mailBox)
	if not os.path.exists(path) and not remote:
		fd = os.open(path, os.O_CREAT)
		os.close(fd)
	sys.exit(1)

# options
password = ""
if os.path.isfile("/etc/cyrus.secret"):
	password = open('/etc/cyrus.secret').read()
	if password[-1] == '\n':
		password = password[0:-1]

usage = "usage: %prog [options] mailPrimaryAddress\n\n"
usage += "to create cyrus account for user with mailPrimaryAddress"

parser = optparse.OptionParser(usage=usage, conflict_handler="resolve")
parser.add_option("-u", "--username", dest="username",
	help="Connect to imap server as this user instead of the default (cyrus).")
parser.add_option("-h", "--hostname", dest="hostname",
	help="Connect to this imap server instead of the default (localhost).")
parser.add_option("-p", "--password", dest="password", 
	help="Use this password for the connection instead of the default (/etc/cyrus.secret).")
parser.set_defaults (username="cyrus")
parser.set_defaults (hostname="localhost")
parser.set_defaults (password=password)
options, args = parser.parse_args()

# test options
if len(args) < 1:
	parser.print_help()
	sys.exit(1)
if args[0].find('@') < 0:
	parser.print_help()
	sys.exit(1)

# get domain and user part
mailPrimaryAddress = args[0].lower()
user, domain = mailPrimaryAddress.split('@')
fsUser = user.replace(".", "^")
remote = False

# remote or not remote
if options.hostname != "localhost" or options.username != "cyrus" or options.password != password:
	remote = True
	
# create sieve directory on localhost
if not remote:
	sieve = '/var/spool/cyrus/sieve/domain/%s/%s/%s/%s' % (domain[0], domain, fsUser[0], fsUser)
	if not os.path.exists(sieve):
		sieveDirTmp = "/var/spool/cyrus/"
		cyrusId=pwd.getpwnam('cyrus')[2]
		mailId=grp.getgrnam('mail')[2]
		sieveDirs = sieve.replace(sieveDirTmp, "")
		for sieveDir in sieveDirs.split("/"):
			sieveDirTmp = os.path.join(sieveDirTmp, sieveDir)
			if not os.path.isdir(sieveDirTmp):
				os.mkdir(sieveDirTmp)
				os.chown(sieveDirTmp, cyrusId, mailId)

		# create default spam sieve script
		if cr.is_true("mail/cyrus/sieve/spam", True):
			sieveScript = os.path.join(sieve, "default.script")
			sieveBc = os.path.join(sieve, "default.bc")
			sieveLink = os.path.join(sieve, "defaultbc")
			FILE = open(sieveScript, "w")
			FILE.writelines(sieveSpamFilter)
			FILE.close()
			subprocess.call(("/usr/lib/cyrus/bin/sievec", "-C", "/etc/imapd/imapd.conf", sieveScript, sieveBc))
			os.symlink("default.bc", sieveLink)
			os.chown(sieveScript, cyrusId, mailId)
			os.chown(sieveBc, cyrusId, mailId)
	
# overwrite hostname if mail/cyrus/murder/backend/hostname 
if not remote:
	murder = cr.get("mail/cyrus/murder/backend/hostname", "")
	if murder:
		options.hostname = murder

		
# create imap connection
try:
	imap = imaplib.IMAP4_SSL(options.hostname)
except Exception, e:
	failed(mailPrimaryAddress, remote, e)

try:
	imap.login(options.username, options.password)
except Exception, e:
	failed(mailPrimaryAddress, remote, e)

# get folders
mbs = []
mbs.append("user/" + mailPrimaryAddress)
if not remote:
	
	# default folders are Spam and Ham nothing else
	
	# spam
	spamFolder = cr.get('mail/cyrus/folder/spam', "Spam")
	if not spamFolder: spamFolder = "Spam"
	if spamFolder.lower() != 'none':
		mbs.append("user/%s/%s@%s" % (user, spamFolder, domain))

	# ham
	hamFolder = cr.get('mail/cyrus/folder/ham', "Ham")
	if not hamFolder: hamFolder = "Ham"
	if hamFolder.lower() != 'none':
		mbs.append("user/%s/%s@%s" % (user, hamFolder, domain))

	# other folders
	for folder in cr.get("mail/cyrus/folder/predefined_folders", "").split(";"):
		if folder and not folder.lower() == 'none':
			mbs.append("user/%s/%s@%s" % (user, folder, domain))

# create mailbox and extra folder
for mb in mbs:
	# IMAP CREATE results (http://www.faqs.org/rfcs/rfc3501.html)
	#    OK - create completed
	#    NO - create failure: can't create mailbox with that name
	#    BAD - command unknown or arguments invalid
	# we need OK
	res, msg = imap.create(mb)
	#if res.lower() != "ok":
	#	failed(mailPrimaryAddress, remote, msg)
	#

imap.logout()

if not remote:
	path = os.path.join(jobPath, mailPrimaryAddress)
	if os.path.exists(path):
		os.unlink(path)

sys.exit(0)

