#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Benno MailArchiv
#
# Copyright 2018-2021 LWsystems GmbH
#
# http://www.lw-systems.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 argparse
import configparser
import getpass
import imaplib
import logging
import os
import stat
import sys
from Benno.IMAP.Config import Config
from Benno.IMAP.User import UserError, IMAPUser
from Benno.RSAkey import RSAkey


versionstring='benno_imapauth version 3.0.4'

################################################################################
def isTTY(message):
    mode = os.fstat(sys.stdin.fileno()).st_mode
    if stat.S_ISFIFO(mode):
        pass
    elif stat.S_ISREG(mode):
        pass
    else:
        if message=='':
            return True
        sys.stderr.write('%s ' % (message))
    return False



### MAIN #################
if __name__ == "__main__":
    logarg=os.getenv('LOGLEVEL','ERROR')
    configfile=os.getenv('CONFIGFILE','/etc/benno-imap/imapauth.conf')

    parser = argparse.ArgumentParser(description='Benno IMAP AUTH Module - authenticate and store IMAP password in DB')
    parser.add_argument('-c', '--config', help='config file (/etc/benno-imap/imapauth.conf)', default='%s' % configfile)
    parser.add_argument('-L', '--loglevel', help='loglevel (default=ERROR, values: CRITICAL, ERROR, WARNING, INFO, DEBUG')
    parser.add_argument('-v', '--version', action='store_true')
    args = parser.parse_args()

    username=''
    password=''
    imaphost=''
    deleteuser=''

    if args.version:
        print(versionstring)
        sys.exit(0)
    if args.loglevel:
        logarg=args.loglevel

    try:
        config = Config(args.config)
    except (FileNotFoundError, PermissionError):
        print('Cannot read configfile %s' % args.config)
        parser.print_usage()
        sys.exit(1)
    config.add_section('LOG')
    config.set('LOG','loglevel',logarg.upper())

    logger=logging.getLogger()
    logger.setLevel(config.get('LOG','loglevel'))
    handler=logging.StreamHandler()
    formatter = logging.Formatter('%(levelname)s: %(message)s')
    handler.setFormatter((formatter))
    logger.addHandler(handler)

    logger.info("Read file \"%s\"", args.config)

    # read username and password from stdin
    isTTY('Username:')
    line1=sys.stdin.readline()
    if isTTY(''):
        line2=getpass.getpass('Password: ')
        username=line1.rstrip()
        password=line2.rstrip()
        isTTY('IMAP hostname:')
        line3=sys.stdin.readline()
        if line3:
            imaphost=line3.rstrip()
    else:
        line2=sys.stdin.readline()
        if line2:
            username=line1.rstrip()
            password=line2.rstrip()
        else:
            try:
                # whitespace separated
                token=line1.split()
                username=token[0]
                password=token[1]
                if len(token) > 2:
                    imaphost=token[2]
            except Exception as e:
                logger.debug(e)
    if not password:
        print('No username or password given.')
        parser.print_usage()
        sys.exit(1)
    try:
        if imaphost:
            user = IMAPUser.CreateImapData(config, username, imaphost)
        else:
            user = IMAPUser.CreateUserid(config,username)
    except UserError as e:
        print("User %s does not exist" % username)
        logger.debug("%s" % e)
        sys.exit(1)
    except Exception as e:
        print(e)
        sys.exit(1)
    if (user.status & 2) < 2:
        logger.info("Login of user %s/%s disabled" % (user.id,user.imaphost))
        sys.exit('ERROR ERR_DISABLED')
    imapssl=config.getboolean(user.id,'ssl')
    try:
        imaphost,imapport=user.imaphost.split(':')
    except ValueError:
        imaphost=user.imaphost
        imapport=config.getint(user.id,'port')
    try:
        if imapssl == True:
            imapport=993
            logger.debug("Connect %s at port %s",imaphost,imapport)
            imap=imaplib.IMAP4_SSL(imaphost,imapport)
        else:
            if imapport == 0:
                imapport=143
            logger.debug("Connect %s at port %s",imaphost,imapport)
            imap=imaplib.IMAP4(imaphost,imapport)
        imap.login(username,password)
        imap.logout()
        logger.info("User %s successful authenticated", username)
    except Exception as e:
        logger.error("Cannot connect to \"%s:%s\": %s", imaphost,imapport,e)
        print('ERROR ERR_AUTH')
        sys.exit(1)
    # authentication successful
    user.password=password
    user.imaphost=imaphost
    # store password
    try:
        if config.getboolean(user.id, 'store password') and user.password:
            keyfile = config.get(user.id, 'keyfile')
            key = open(keyfile).read()
            user.saveIMAPPassword(RSAkey.encrypt(key, user.password))
    except Exception as e:
        logger.error("Cannot store password for %s: %s", user.id,e)
        sys.exit(1)

    try:
        adminuser = config.get('DEFAULT','adminuser')
    except configparser.NoOptionError:
        adminuser = 'benno'
    if username == adminuser:
        logger.info("%s is admin user",username)
        user.role='ADMIN'
        user.email.append('*@*')
    for container in user.archive:
        print("ARCHIVE %s" % container)
    print("ROLE %s" % user.role)
    print("DISPLAYNAME %s" % user.name)
    print("USERID %s" % user.id)
    for address in user.email:
        print("MAIL %s" % address)
    print("AUTH OK")
