#!/usr/bin/env python
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2 of the License.
#
#    This program is distributed 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
""" A common used mail sender wrapper"""

import os
import smtplib
import base64

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders as Encoders
from email.header import Header
from email.utils import parseaddr, formataddr

class MailError(Exception):
    """Local Error handler
    """
    pass


def prepare_mail(env_filename, subject, body, mail_from, mail_to,
                 mail_cc='', mail_bcc='', attachment=None):
    """ Prepare a parameter inject file for mail sender job """
    if type(mail_to) != list:
        mail_to = mail_to.split(',')
    if type(mail_cc) != list:
        mail_cc = mail_cc.split(',')
    if type(mail_bcc) != list:
        mail_bcc = mail_bcc.split(',')

    mail_env = {}

    message = makemail(subject, body, from_email=mail_from, to_who=mail_to,
                       cc_who=mail_cc, bcc=mail_bcc, attachment=attachment)

    mail_env['FROM'] = mail_from
    mail_env['TO'] = ','.join(mail_to + mail_cc + mail_bcc)
    mail_env['MESSAGE'] = base64.b64encode(message.as_string())

    with open(env_filename, 'w') as env_file:
        for key in mail_env.keys():
            env_file.write('%s=%s\n' %(key, mail_env[key]))

def sendmail(from_email, to_who, msg, smtp_server):
    """The main sender method"""

    if type(to_who) != list:
        to_who = [to_who]

    try:
        smtp = smtplib.SMTP(smtp_server)
        smtp.sendmail(from_email, to_who, msg)
        smtp.quit()
        print "Email to %s sent succeeded" % to_who
    except smtplib.SMTPException, smtpe:
        if 'no valid recipients' in smtpe:
            raise MailError('Error: unable to send email: %s' % smtpe)
        raise Exception ("Error: unable to send email: %s" % smtpe)

def makemail(subject='', body='', from_email=None, to_who=(),
             cc_who=(), bcc=(), attachment=None, extra_headers=None):

    """Send an email.
    All arguments should be Unicode strings (plain ASCII works as well).

    Only the real name part of sender and recipient addresses may contain
    non-ASCII characters.

    The email will be properly MIME encoded and delivered though SMTP the
    smtp server port 25.

    The charset of the email will be the first one out of US-ASCII, ISO-8859-1
    and UTF-8 that can represent all the characters occurring in the email.
    """

    def normalize_addr_header(hdsf):
        """ Helper routine to normalize the charset of headersf """

        # Header class is smart enough to try US-ASCII, then the charset we
        # provide, then fall back to UTF-8.
        header_charset = 'ISO-8859-1'

        # Split real name (which is optional) and email address parts
        name, addr = parseaddr(hdsf)

        if name:
            # We must always pass Unicode strings to Header, otherwise it will
            # use RFC 2047 encoding even on plain ASCII strings.
            name = str(Header(unicode(name), header_charset))

        # Make sure email addresses do not contain non-ASCII characters
        addr = addr.encode('ascii')

        return formataddr((name, addr))

    # We must choose the body charset manually
    body_charset, charsets = '', ('US-ASCII', 'UTF-8')

    for charset in charsets:
        try:
            body.decode(charset)
        except UnicodeError:
            pass
        else:
            body_charset = charset
            break

    if type(to_who) != list:
        to_who = [to_who]
    if type(cc_who) != list:
        cc_who = [cc_who]
    if type(bcc) != list:
        bcc = [bcc]

    # Create the message ('plain' stands for Content-Type: text/plain)
    if attachment and os.path.isfile(attachment):
        msg = MIMEMultipart()
        msg.attach(MIMEText(body, 'plain', body_charset))

        attach = MIMEBase('application', "octet-stream")
        attach.set_payload(open(attachment, "rb").read())
        Encoders.encode_base64(attach)
        attach.add_header("Content-Disposition", 'attachment; filename="%s"' %
                (os.path.basename(attachment)))
        msg.attach(attach)
    else:
        msg = MIMEText(body, 'plain', body_charset)

    # Normalize all headers
    msg['Subject'] = Header(unicode(subject), 'ISO-8859-1')
    msg['From'] = normalize_addr_header(from_email)
    msg['To'] = ','.join([normalize_addr_header(hdsf) for hdsf in to_who])
    msg['Cc'] = ','.join([normalize_addr_header(hdsf) for hdsf in cc_who])
    msg['Bcc'] = ','.join([normalize_addr_header(hdsf) for hdsf in bcc])

    if extra_headers and isinstance(extra_headers, dict):
        for k in extra_headers:
            msg[k] = extra_headers[k]

    return msg
