##############################################################################
#
# Copyright (c) 2004 Christian Heimes and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
"""
from config import X_MAILER

import os, sys
import smtplib
import email.Message
import email.Utils
import socket
from DateTime import DateTime
from random import randint

from Products.MailHost.MailHost import MailHostError

ssl_support = False
if hasattr(socket, 'ssl'):
    ssl_support = True

class Mail:
    """A email object which knows how to send itself

    mfrom     - mail from tag (only for SMTP server)
    mto       - mail to tag (only for SMTP server)
    message   - The message email.Message.Message based object
    smtp_host - SMTP server address
    smtp_port - SMTP server port
    **kwargs  - additional keywords like userid, password and forceTLS
    """

    def __init__(self, mfrom, mto, message,
                 smtp_host='localhost', smtp_port=25,
                 **kwargs):
        self.mfrom = mfrom
        self.mto = mto
        # message must be email.Message.Message based
        assert(isinstance(message, email.Message.Message))
        # Add some important headers
        if not message.has_key('Date'):
            message['Date'] = DateTime().rfc822()
        if not message.has_key('X-Mailer'):
            message['X-Mailer'] = X_MAILER
        if not message.has_key('Message-Id'):
            fqdn = socket.getfqdn()
            message['Message-Id'] = email.Utils.make_msgid(fqdn)

        self.message = message

        self.host = smtp_host
        self.port = int(smtp_port)

        self.kwargs = kwargs
        self.errors = 0
        self.id = None

    def setId(self, id):
        """Set the unique id of the email
        """
        self.id = id

    def getId(self):
        """Get unique id
        """
        return self.id

    def incError(self):
        """Increase the error counter
        """
        self.errors+=1

    def getErrors(self):
        """Get the error counter
        """
        return self.errors

    def send(self, debug=False):
        """Send email to the SMTP server
        """
        kw = self.kwargs
        userid   = kw.get('userid', None)
        password = kw.get('password', None)
        forceTLS = kw.get('forcetls', False)
        noTLS    = kw.get('notls', False)
        message  = self.message.as_string()

        # connect
        smtpserver = smtplib.SMTP(self.host, self.port)
        if debug:
            smtpserver.set_debuglevel(1)

        # Try EHLO first, then HELO.
        if not (200 <= smtpserver.ehlo()[0] <= 299):
            (code, resp) = smtpserver.helo()
            if not (200 <= code <= 299):
                raise MailHostError('Host refused to talk to us: %s' % resp)

        # check for ssl encryption
        if smtpserver.has_extn('starttls') and ssl_support and not(noTLS):
            smtpserver.starttls()
            smtpserver.ehlo()
        elif forceTLS:
            if noTLS:
                raise MailHostError('Configured not to try TLS '
                    'but it is required')
            else:
                raise MailHostError('Host does NOT support StartTLS '
                    'but it is required')
        # login
        if smtpserver.does_esmtp:
            if userid:
                smtpserver.login(userid, password)
        elif userid:
            #indicate error here to prevent inadvertent use of spam relay
            raise MailHostError('Host does NOT support ESMTP '
                                'but username/password provided')
        # send and quit
        smtpserver.sendmail(self.mfrom, self.mto, message)
        smtpserver.quit()

    def __str__(self):
        return self.message.as_string()

    def __repr__(self):
        return '<%s (%s) at %s>' % (
            self.__class__.__name__, self.info(),
            id(self))

    def info(self):
        """Return status informations about the email
        """
        return ('From: %(from)s, To: %(to)s, Subject: %(subject)s '
                '(s:%(size)d, e:%(errors)d)' % {
            'id' : self.getId(), 'errors' : self.errors,
            'from' : self.message['From'], 'to' : self.message['To'],
            'subject' : self.message['Subject'], 'size' : len(self.message)
            })
