#!/usr/bin/python3
#
# linuxmuster-mail.py
# thomas@linuxmuster.net
# 20200317
#

import configparser
import datetime
import getopt
import os
import sys
import re


def usage():
    print('Usage: linuxmuster-mail.py [options]')
    print(' [options] may be:')
    print(' -c <file>,   --config=<file>  : path to ini file with setup values (default: /var/lib/linuxmuster/setup.ini)')
    print(' -f,          --force          : force overwrite an already configured container')
    print(" -b <secret>, --bindpw=<secret>: global-binduser's password (optional, per default read from setup.ini)")
    print(' -h,          --help           : print this help')


# get cli args
try:
    opts, args = getopt.getopt(sys.argv[1:], "b:c:fh", ["bindpw=", "config=", "force", "help"])
except getopt.GetoptError as err:
    # will print something like "option -a not recognized"
    print(err)
    usage()
    sys.exit(2)


# default values
tpldir = '/usr/share/linuxmuster-mail/templates/docker'
dockerdir = '/srv/docker/linuxmuster-mail/'
setupini = '/var/lib/linuxmuster/setup.ini'
ssldir = '/etc/linuxmuster/ssl'
mailcert = ssldir + '/mail.cert.pem'
mailkey = ssldir + '/mail.key.pem'
force = False
binduserpw_cl = ''


# evaluate options
for o, a in opts:
    if o in ("-c", "--config"):
        if os.path.isfile(a):
            setupini = a
        else:
            usage()
            sys.exit()
    elif o in ("-f", "--force"):
        force = True
    elif o in ("-b", "--bindpw"):
        binduserpw_cl = a
    elif o in ("-h", "--help"):
        usage()
        sys.exit()
    else:
        assert False, "unhandled option"


# check if linuxmuster-mail container is already configured
if force is False and os.path.isfile(dockerdir + 'docker-compose.yml'):
    print('The linuxmuster-mail docker container is already configured. Exiting.')
    sys.exit(0)


# functions start
# print without linefeed
def printr(msg):
    print(msg, end='', flush=True)


# return datetime string
def dtStr():
    return "{:%Y%m%d%H%M%S}".format(datetime.datetime.now())


# return content of text file
def readTextfile(tfile):
    if not os.path.isfile(tfile):
        return False, None
    try:
        infile = open(tfile, 'r')
        content = infile.read()
        infile.close()
        return True, content
    except:
        print('Cannot read ' + tfile + '!')
        return False, None


# write textfile
def writeTextfile(tfile, content, flag):
    try:
        outfile = open(tfile, flag)
        outfile.write(content)
        outfile.close()
        return True
    except:
        print('Failed to write ' + tfile + '!')
        return False


# mailserver setup
def mailSetup():
    # read ini file
    print('### linuxmuster-mail: mailserver setup')
    try:
        print('Reading setup data ...')
        setup = configparser.ConfigParser(inline_comment_prefixes=('#', ';'))
        setup.read(setupini)
        domainname = setup.get('setup', 'domainname')
        serverip = setup.get('setup', 'serverip')
        servername = setup.get('setup', 'servername')
        binduserpw = setup.get('setup', 'binduserpw')
        basedn = setup.get('setup', 'basedn')
        smtprelay_full = setup.get('setup', 'smtprelay')
        smtpuser = setup.get('setup', 'smtpuser')
        smtppw = setup.get('setup', 'smtppw')
    except Exception as e:
        print(e)
        return 1

    # use binduser password given on cl
    if binduserpw_cl != '':
        binduserpw = binduserpw_cl
    # try to get the password assuming we are on the server
    if binduserpw == '':
        try:
            rc, binduserpw = readTextfile('/etc/linuxmuster/.secret/global-binduser')
        except:
            print('No binduser password!')
            usage()
            return 1

    # split relay name and port
    smtprelay = smtprelay_full.split(':')[0]
    try:
        smtpport = smtprelay_full.split(':')[1]
    except:
        smtpport = '25'

    # check certificate & key
    for item in [mailkey, mailcert]:
        if not os.path.isfile(item):
            print('Certificate file ' + item + ' is missing!')
            return 1

    # create maildata dir
    maildata = dockerdir + '/maildata/' + domainname
    os.system('mkdir -p ' + maildata)
    os.system('chown docker:docker ' + maildata)
    rc = os.system('chmod 770 ' + maildata)
    if rc != 0:
        print('Can not change rights for', maildata, '!')
        return 1

    # create docker configuration
    print('Writing docker configuration ...')
    for f in os.listdir(tpldir):
        infile = tpldir + '/' + f
        # read template
        rc, content = readTextfile(infile)
        if not rc:
            return 1
        # extract oufile path from first line
        firstline = re.findall(r'# .*\n', content)[0]
        outfile = firstline.partition(' ')[2].replace('\n', '')
        # replace placeholders
        content = content.replace('@@servername@@', servername)
        content = content.replace('@@serverip@@', serverip)
        content = content.replace('@@basedn@@', basedn)
        content = content.replace('@@binduserpw@@', binduserpw)
        content = content.replace('@@domainname@@', domainname)
        content = content.replace('@@smtprelay@@', smtprelay)
        content = content.replace('@@smtpport@@', smtpport)
        content = content.replace('@@smtpuser@@', smtpuser)
        content = content.replace('@@smtppw@@', smtppw)
        content = content.replace('@@mailcert@@', mailcert)
        content = content.replace('@@mailkey@@', mailkey)
        # add date string to content
        content = '# modified by linuxmuster-mail-setup at ' + dtStr() + '\n' + content
        # write outfile
        if not writeTextfile(outfile, content, 'w'):
            return 1
        # copy ldap-users.cf to ldap-groups.cf and ldap-aliases.cf
        if f == 'ldap-users.cf':
            outfile = outfile.replace('ldap-users.cf', 'ldap-groups.cf')
            if not writeTextfile(outfile, content, 'w'):
                return 1
            outfile = outfile.replace('ldap-groups.cf', 'ldap-aliases.cf')
            if not writeTextfile(outfile, content, 'w'):
                return 1
            outfile = outfile.replace('ldap-aliases.cf', 'ldap-domains.cf')
            if not writeTextfile(outfile, content, 'w'):
                return 1
    # restart container
    rc = os.system('docker-compose ps | grep -qw ^mail && ' + dockerdir + 'stop.sh')
    rc = os.system(dockerdir + 'start.sh')

    return rc
# functions end


rc = mailSetup()

print('Script finished with return code ' + str(rc) + '.')

sys.exit(rc)
