#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Criticality: High
Check that emails can be sent.
'''
import os
import subprocess
import sys
import random
import time
import imp

try:
    import spf
except ImportError:
    subprocess.check_call(['apt-get', '-qq', '-y', 'install', 'python3-spf'])
    import spf
if subprocess.call(['which', 'net-tools']) != 0:
    subprocess.check_call(['apt-get', '-qq', '-y', 'install', 'net-tools'])

YELLOW = '\033[93m'
GREEN = '\033[92m'
RED = '\033[91m'
DEF = '\033[0m'

os.chdir(os.path.dirname(__file__))
if not os.path.isfile('../utils.py'):
    print('The envsetup configuration was not found.')
    sys.exit(1)
else:
    es_utils = imp.load_source('es_utils', '../utils.py')
    conf = es_utils.load_conf()


def print_color(txt, col):
    print('%s%s%s' % (col, txt, DEF))


def print_yellow(txt):
    print_color(txt, YELLOW)


def print_red(txt):
    print_color(txt, RED)


def print_green(txt):
    print_color(txt, GREEN)


def check_listening_port():
    # check that postfix listens the port 25 correctly
    status, out = subprocess.getstatusoutput('netstat -pant | grep master | grep ":25"')
    if status != 0:
        print_red('The port 25 is not listened by postfix "master" process.')
        return 1
    print_green('Postfix "master" process is listening port 25 correctly.')
    if '127.0.0.1:25' not in out:
        print_red('Postfix "master" process is not listening address 127.0.0.1, please check postfix configuration.')
        print('Postfix should listen address 127.0.0.1 to be sure that this server cannot be used as an SMTP relay by external services.')
        return 1
    print_green('Postfix "master" process is listening address 127.0.0.1 correctly.')
    return 0


def check_relay():
    print('Checking if SMTP relay conforms to conf.')
    status, out = subprocess.getstatusoutput('grep relayhost /etc/postfix/main.cf')
    if status == 0:
        configured_relay = out[len('relayhost'):].strip(' \t=').replace('[', '').replace(']', '')
    else:
        configured_relay = ''
    if not configured_relay:
        # no relay configured, check relayless situations
        ip = conf.get('NETWORK_IP_NAT')
        if not ip:
            ip = conf.get('NETWORK_IP')
        if not ip:
            print_yellow('Cannot determine public IP address')
            return 3
        with open('/etc/mailname', 'r') as f:
            d = f.read().strip()
        if d not in ('ubicast.tv', 'ubicast.eu'):
            print_yellow('/etc/mailname does not contain ubicast.eu or ubicast.tv, mails will probably not be received on ubicast mailing lists')
            return 3
        # check spf
        result, explain = spf.check2(i=ip, s='support@ubicast.eu', h='')
        if result != 'pass':
            print_red('ip %s is not in ubicast.eu SPF and emails sent from support@ubicast.eu may be treated as spam' % ip)
            return 3
    conf_relay = conf.get('EMAIL_SMTP_SERVER', '').replace('[', '').replace(']', '')
    if conf_relay != configured_relay:
        print_red('Configured STMP relay (%s) does not match the expected value (%s).' % (configured_relay, conf_relay))
        return 3
    else:
        print_green('STMP relay is properly set.')
        return 0


def send_test_email():
    email = 'noreply+%s-%s@ubicast.eu' % (time.time(), random.randint(0, 1000))
    print('Sending test email to "%s".' % email)
    cmd = 'echo "This is a test email" | mail -s "Test email from `cat /etc/hostname`" %s' % email
    subprocess.getstatusoutput(cmd)
    timeout = 120
    waited = 1
    delay = 2
    print('Timeout to find email sending log is set to %s seconds.' % timeout)
    out = ''
    if os.path.isfile('/var/log/mail.log'):
        cmd = 'grep "%s" /var/log/mail.log' % email
    else:
        print('/var/log/mail.log not found, trying journalctl')
        cmd = 'journalctl -u postfix | grep %s' % email
    time.sleep(1)
    while True:
        status, out = subprocess.getstatusoutput(cmd)
        if status == 0:
            out = out.strip().split('\n')[-1]
            if 'status=deferred' not in out:
                print('Log entry found after %s seconds.' % waited)
                break
        if waited >= timeout:
            print_red('Failed to send email.')
            print('No log entry found after %s seconds using command: %s' % (waited, cmd))
            return 1
        print('No log entry found after %s seconds, waiting %s more seconds...' % (waited, delay))
        time.sleep(delay)
        waited += delay
        delay *= 2
    if 'bounced' not in out or 'The email account that you tried to reach does not exist.' in out:
        print_green('Email sent.')
        return 0
    else:
        print_red('Failed to send email.')
        print('Sending log line:\n%s' % out)
        return 1


if not os.path.exists('/etc/postfix'):
    print_red('Postfix dir does not exists, please install postfix.')
    sys.exit(1)

rc = check_listening_port()
if rc == 0:
    rc = check_relay()
    if send_test_email() == 1:
        rc = 1

sys.exit(rc)