#!/usr/bin/env python
#
# Copyright (C) 2006, 2007, 2016 by Intevation GmbH
# Author(s):
# Thomas Arendsen Hein <thomas@intevation.de>
#
# This program is free software under the GNU GPL (>=v2)
# Read the file COPYING coming with the software for details.
#
# In addition, as a special exception, Intevation GmbH gives
# permission to link the code of this program with the OpenSSL
# library (or with modified versions of OpenSSL that use the same
# license as OpenSSL), and distribute linked combinations including
# the two. You must obey the GNU General Public License in all
# respects for all of the code used other than OpenSSL. If you
# modify this file, you may extend this exception to your version
# of the file, but you are not obligated to do so. If you do not
# wish to do so, delete this exception statement from your version.

"""
maildir-split-rfc822 folder mydomain [myotherdomain]...

- read mail from stdin
- if mail is sent from an address in one of my domains and the content type
  is multipart/mixed, save message/rfc822 in the maildir folder
- otherwise save the full mail in the maildir folder

Using at least Python 2.4 is recommended due to a bug in the email module.
"""

import os
import sys
import email
import email.Generator
import email.Utils
import socket
import errno
import time

def in_domains(addr, domains):
    try:
        return email.Utils.parseaddr(addr)[1].split('@')[1] in domains
    except IndexError, why:
        return False

_count = 1  # This is used to generate unique file names.
def _create_tmp(folder):
    """Create a file in the tmp subdirectory and open and return it."""
    global _count
    now = time.time()
    hostname = socket.gethostname()
    if '/' in hostname:
        hostname = hostname.replace('/', r'\057')
    if ':' in hostname:
        hostname = hostname.replace(':', r'\072')
    uniq = "%s.M%sP%sQ%s.%s" % (int(now), int(now % 1 * 1e6), os.getpid(),
                                _count, hostname)
    path = os.path.join(folder, 'tmp', uniq)
    try:
        os.stat(path)
    except OSError, e:
        if e.errno == errno.ENOENT:
            _count += 1
            return open(path, 'wb+')
        else:
            raise

def deliver_maildir(folder, text):
    tmp_file = _create_tmp(folder)
    msggen = email.Generator.Generator(tmp_file, maxheaderlen=998)
    msggen.flatten(text)
    tmp_file.close()
    uniq = os.path.basename(tmp_file.name).split(':')[0]
    dest = os.path.join(folder, 'new', uniq)
    os.rename(tmp_file.name, dest)

def split_message(folder, mydomains=None, sender=None):
    try:
        # XXX: I have no idea why I added the sleep call in 2006/2007 -- thomas
        time.sleep(5)
        msg = email.message_from_file(sys.stdin)
        if sender is None:
            try:
                sender = msg.get_unixfrom().split(' ', 2)[1]
            except AttributeError:
                return os.EX_UNAVAILABLE

        if (msg.get_content_type() == 'multipart/mixed'
            and in_domains(msg.get("From"), mydomains)):
            for subpart in msg.get_payload():
                if subpart.get_content_type() == 'message/rfc822':
                    deliver_maildir(folder, subpart.get_payload(0))
        else:
            deliver_maildir(folder, msg)
    except StandardError, inst:
        exctype = sys.exc_info()[0]
        why = str(inst) or 'unknown'
        sys.stderr.write("Unhandled exception: %s: %s\n" % (exctype, why))
        return os.EX_TEMPFAIL

if __name__ == '__main__':
    if len(sys.argv) < 3:
        sys.stderr.write("usage: %s\n" % __doc__.strip())
        sys.exit(os.EX_USAGE)

    sys.exit(split_message(sys.argv[1], mydomains=sys.argv[2:]))

