#######################################################################
# This file is part of PyBlosxom.
#
# Copyright (C) 2011 by the PyBlosxom team.  See AUTHORS.
#
# PyBlosxom is distributed under the MIT license.  See the file
# LICENSE for distribution details.
#######################################################################

"""Utility module for sending email notifications.
"""

from email.mime.text import MIMEText
from email.utils import formatdate
import time
import subprocess
import smtplib
import re


class MailConfigurationError(Exception):
    pass

class MailSendError(Exception):
    pass


def send_mail(config, from_addr, subject, body):
    """Takes a config, series of addresses, a subject and a body
    and sends an email through SMTP.

    :param config: pyblosxom config
    :param from_addr: from address; either "<foo@example.com>" or
        "foo <foo@example.com>"
    :param subject: subject of the email as a string
    :param body: the body of the email as a string

    :raises MailConfigurationError: if ``email_to`` is missing from
        config, if ``email_server`` or ``email_command`` is missing
        from config

    :raises MailSendError: if the email command kicks up stderr
    """
    if "email_to" not in config:
        raise MailConfigurationError("'email_to' missing in configuration")

    if "email_server" not in config and "email_command" not in config:
        raise MailConfigurationError(
            "either 'email_command' or 'email_server' must be "
            "set in configuration")

    body = re.sub("\nFrom", "\n> From", body, flags=re.IGNORECASE)

    msg = MIMEText(body, 'plain', 'utf-8')

    msg["Subject"] = subject
    msg["From"] = from_addr
    msg["To"] = config["email_to"]
    msg["Date"] = formatdate(time.localtime())

    if "email_server" in config:
        s = smtplib.SMTP(config["smtp_server"])
        s.sendmail(from_addr=from_addr,
                   to_addrs=config["email_to"],
                   msg=msg.as_string())
        s.quit()

    elif "email_command" in config:
        argv = [config["email_command"], '-s', subject, config["email_to"]]
        
        process = subprocess.Popen(
            argv, stdin=subprocess.PIPE,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        process.stdin.write(msg.as_string())
        process.stdin.close()
        process.wait()
        stderr = process.stderr.read()
        # the except clause below will catch this
        if stderr:
            raise MailSendError("email command returned stderr: %s" % stderr)



def send_mail(server, from_addr, to_addrs, subject, body):

    


def clean_author(s):
    """
    Guard against blasterattacko style attacks that embedd SMTP commands in
    author field.

    If author field is more than one line, reduce to one line

    @param the string to be checked
    @type string

    @returns the sanitized string
    """
    return s.splitlines()[0]

def escape_smtp_commands(s):
    """
    Guard against blasterattacko style attacks that embed SMTP commands by
    using an HTML span to make the command syntactically invalid to SMTP but
    renderable by HTML

    @param the string to be checked
    @type string

    @returns the sanitized string
    """
    def repl_fn(mo):
        return '<span>'+mo.group(0)+'</span>'
    s = re.sub('([Tt]o:.*)',repl_fn,s)
    s = re.sub('([Ff]rom:.*)',repl_fn,s)
    s = re.sub('([Ss]ubject:.*)',repl_fn,s)
    return s

def send_email(config, entry, comment, comment_dir, comment_filename):
    """Send an email to the blog owner on a new comment

    @param config: configuration as parsed by Pyblosxom
    @type config: dictionary

    @param entry: a file entry
    @type config: dictionary

    @param comment: comment as generated by read_comments
    @type comment: dictionary

    @param comment_dir: the comment directory
    @type comment_dir: string

    @param comment_filename: file name of current comment
    @type comment_filename: string
    """
    import smtplib
    # import the formatdate function which is in a different
    # place in Python 2.3 and up.
    try:
        from email.Utils import formatdate
    except ImportError:
        from rfc822 import formatdate
    from socket import gethostbyaddr

    author = escape_smtp_commands(clean_author(comment['author']))
    description = escape_smtp_commands(comment['description'])
    ipaddress = escape_smtp_commands(comment.get('ipaddress', '?'))

    if 'comment_smtp_from' in config:
        email = config['comment_smtp_from']
    else:
        email = escape_smtp_commands(clean_author(comment['email']))

    try:
        curl = "%s/%s" % (config['base_url'],
                          tools.urlencode_text(entry['file_path']))
        comment_dir = os.path.join(config['comment_dir'], entry['absolute_path'])

        # create the message
        message = []
        message.append("Name: %s" % author)
        if 'email' in comment:
            message.append("Email: %s" % comment['email'])
        if 'link' in comment:
            message.append("URL: %s" % comment['link'])
        try:
            host_name = gethostbyaddr(ipaddress)[0]
            message.append("Hostname: %s (%s)" % (host_name, ipaddress))
        # FIXME - bare except here--bad!
        except:
            message.append("IP: %s" % ipaddress)
        message.append("Entry URL: %s" % curl)
        message.append("Comment location: %s" % comment_filename)
        message.append("\n\n%s" % description)

        if 'comment_mta_cmd' in config:
            # set the message headers
            message.insert(0, "")
            message.insert(0, "Subject: comment on %s" % curl)
            message.insert(0, "Date: %s" % formatdate(float(comment['pubDate'])))
            message.insert(0, "To: %s" % config["comment_smtp_to"])
            message.insert(0, "From: %s" % email)

            body = '\n'.join(message).encode('utf-8')

            argv = [config['comment_mta_cmd'],
                    '-s',
                    '"comment on %s"' % curl,
                    config['comment_smtp_to']]

            process = subprocess.Popen(
                argv, stdin=subprocess.PIPE,
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            process.stdin.write(body)
            process.stdin.close()
            process.wait()
            stdout = process.stdout.read()
            stderr = process.stderr.read()
            tools.get_logger().debug('Ran MTA command: ' + ' '.join(argv))
            tools.get_logger().debug('Received stdout: ' + stdout)
            tools.get_logger().debug('Received stderr: ' + stderr)
            # the except clause below will catch this
            assert stderr == '', stderr

        else:
            assert 'comment_smtp_server' in config
            server = smtplib.SMTP(config['comment_smtp_server'])
            mimemsg = MIMEText("\n".join(message).encode("utf-8"), 'plain', 'utf-8')

            # set the message headers
            mimemsg["From"] = email
            mimemsg["To"] = config["comment_smtp_to"]
            mimemsg["Date"] = formatdate(float(comment["pubDate"]))
            mimemsg["Subject"] = ("comment on %s" % curl)

            # send the message via smtp
            server.sendmail(from_addr=email,
                            to_addrs=config['comment_smtp_to'],
                            msg=mimemsg.as_string())
            server.quit()

    except Exception, e:
        tools.get_logger().error("error sending email: %s" %
                                traceback.format_exception(*sys.exc_info()))
